[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#777042: unblock: suricata/2.0.6-1



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Dear release team, please unblock package suricata

We were contacted privately regarding this release of libhtp/suricata
which include important security updates (no CVE asigned though).

We considered backporting just the important patches, but the changelog is
rather small and we decided to package the new version directly.

Before we upload 2.0.6-1 to unstable we would like to make sure that this is OK for you.

Similar unblock exists for libhtp (#777040).

The the debdiff, generated with this cmdline:
debdiff suricata_2.0.4-1.dsc suricata_2.0.6-1.dsc | filterdiff -i '*.[ch]

Note that the resulting debdiff was hand-modified to delete the libhtp code, which is
included in upstream tarball but it has his own source package.

diff -Nru suricata-2.0.4/src/app-layer-detect-proto.c suricata-2.0.6/src/app-layer-detect-proto.c
--- suricata-2.0.4/src/app-layer-detect-proto.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/app-layer-detect-proto.c	2015-01-28 08:26:48.000000000 +0100
@@ -1727,19 +1727,17 @@
 {
     SCEnter();
 
-    AppProto a = ALPROTO_UNKNOWN;
-
+    AppProto a;
     for (a = 0; a < ALPROTO_MAX; a++) {
         if (alpd_ctx.alproto_names[a] != NULL &&
             strlen(alpd_ctx.alproto_names[a]) == strlen(alproto_name) &&
             (SCMemcmp(alpd_ctx.alproto_names[a], alproto_name, strlen(alproto_name)) == 0))
         {
-            goto end;
+            SCReturnCT(a, "AppProto");
         }
     }
 
- end:
-    SCReturnCT(a, "AppProto");
+    SCReturnCT(ALPROTO_UNKNOWN, "AppProto");
 }
 
 char *AppLayerProtoDetectGetProtoName(AppProto alproto)
diff -Nru suricata-2.0.4/src/app-layer-htp-libhtp.c suricata-2.0.6/src/app-layer-htp-libhtp.c
--- suricata-2.0.4/src/app-layer-htp-libhtp.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/app-layer-htp-libhtp.c	2015-01-28 08:26:48.000000000 +0100
@@ -201,11 +201,13 @@
 
     if (uri->query != NULL) {
         bstr *query = bstr_dup(uri->query);
-        uint64_t flags = 0;
-        htp_urldecode_inplace(tx->cfg, HTP_DECODER_URLENCODED, query, &flags);
-        bstr_add_c_noex(r, "?");
-        bstr_add_noex(r, query);
-        bstr_free(query);
+        if (query) {
+            uint64_t flags = 0;
+            htp_urldecode_inplace(tx->cfg, HTP_DECODER_URLENCODED, query, &flags);
+            bstr_add_c_noex(r, "?");
+            bstr_add_noex(r, query);
+            bstr_free(query);
+        }
     }
 
     if (uri->fragment != NULL) {
diff -Nru suricata-2.0.4/src/defrag.c suricata-2.0.6/src/defrag.c
--- suricata-2.0.4/src/defrag.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/defrag.c	2015-01-28 08:26:48.000000000 +0100
@@ -291,7 +291,7 @@
     if (rp == NULL) {
         SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for "
                    "fragmentation re-assembly, dumping fragments.");
-        goto remove_tracker;
+        goto error_remove_tracker;
     }
     PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
     rp->recursion_level = p->recursion_level;
@@ -311,7 +311,7 @@
         if (frag->offset == 0) {
 
             if (PacketCopyData(rp, frag->pkt, frag->len) == -1)
-                goto remove_tracker;
+                goto error_remove_tracker;
 
             hlen = frag->hlen;
             ip_hdr_offset = frag->ip_hdr_offset;
@@ -327,12 +327,12 @@
             if (pkt_end > (int)MAX_PAYLOAD_SIZE) {
                 SCLogWarning(SC_ERR_REASSEMBLY, "Failed re-assemble "
                         "fragmented packet, exceeds size of packet buffer.");
-                goto remove_tracker;
+                goto error_remove_tracker;
             }
             if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim,
                 frag->pkt + frag->data_offset + frag->ltrim,
                 frag->data_len - frag->ltrim) == -1) {
-                goto remove_tracker;
+                goto error_remove_tracker;
             }
             if (frag->offset + frag->data_len > fragmentable_len)
                 fragmentable_len = frag->offset + frag->data_len;
@@ -350,12 +350,17 @@
         old, rp->ip4h->ip_len + rp->ip4h->ip_off);
     SET_PKT_LEN(rp, ip_hdr_offset + hlen + fragmentable_len);
 
-remove_tracker:
-    /** \todo check locking */
     tracker->remove = 1;
     DefragTrackerFreeFrags(tracker);
 done:
     return rp;
+
+error_remove_tracker:
+    tracker->remove = 1;
+    DefragTrackerFreeFrags(tracker);
+    if (rp != NULL)
+        PacketFreeOrRelease(rp);
+    return NULL;
 }
 
 /**
@@ -405,7 +410,7 @@
     if (rp == NULL) {
         SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for "
                 "fragmentation re-assembly, dumping fragments.");
-        goto remove_tracker;
+        goto error_remove_tracker;
     }
     PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
 
@@ -428,11 +433,11 @@
              * IPv6 headers. We also copy in its data, but remove the
              * fragmentation header. */
             if (PacketCopyData(rp, frag->pkt, frag->frag_hdr_offset) == -1)
-                goto remove_tracker;
+                goto error_remove_tracker;
             if (PacketCopyDataOffset(rp, frag->frag_hdr_offset,
                 frag->pkt + frag->frag_hdr_offset + sizeof(IPV6FragHdr),
                 frag->data_len) == -1)
-                goto remove_tracker;
+                goto error_remove_tracker;
             ip_hdr_offset = frag->ip_hdr_offset;
 
             /* This is the start of the fragmentable portion of the
@@ -445,13 +450,13 @@
              * and the frag header. */
             unfragmentable_len = (fragmentable_offset - ip_hdr_offset) - IPV6_HEADER_LEN;
             if (unfragmentable_len >= fragmentable_offset)
-                goto remove_tracker;
+                goto error_remove_tracker;
         }
         else {
             if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim,
                 frag->pkt + frag->data_offset + frag->ltrim,
                 frag->data_len - frag->ltrim) == -1)
-                goto remove_tracker;
+                goto error_remove_tracker;
             if (frag->offset + frag->data_len > fragmentable_len)
                 fragmentable_len = frag->offset + frag->data_len;
         }
@@ -468,12 +473,17 @@
     SET_PKT_LEN(rp, ip_hdr_offset + sizeof(IPV6Hdr) +
             unfragmentable_len + fragmentable_len);
 
-remove_tracker:
-    /** \todo check locking */
     tracker->remove = 1;
     DefragTrackerFreeFrags(tracker);
 done:
     return rp;
+
+error_remove_tracker:
+    tracker->remove = 1;
+    DefragTrackerFreeFrags(tracker);
+    if (rp != NULL)
+        PacketFreeOrRelease(rp);
+    return NULL;
 }
 
 /**
diff -Nru suricata-2.0.4/src/detect-byte-extract.c suricata-2.0.6/src/detect-byte-extract.c
--- suricata-2.0.4/src/detect-byte-extract.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/detect-byte-extract.c	2015-01-28 08:26:48.000000000 +0100
@@ -770,22 +770,30 @@
     return;
 }
 
-SigMatch *DetectByteExtractRetrieveSMVar(const char *arg, Signature *s, int list)
+/**
+ * \brief Lookup the SigMatch for a named byte_extract variable.
+ *
+ * \param arg The name of the byte_extract variable to lookup.
+ * \param s Pointer the signature to look in.
+ *
+ * \retval A pointer to the SigMatch if found, otherwise NULL.
+ */
+SigMatch *DetectByteExtractRetrieveSMVar(const char *arg, Signature *s)
 {
-    if (list == -1)
-        return NULL;
-
     DetectByteExtractData *bed = NULL;
-    SigMatch *sm = s->sm_lists[list];
+    int list;
 
-    while (sm != NULL) {
-        if (sm->type == DETECT_BYTE_EXTRACT) {
-            bed = (DetectByteExtractData *)sm->ctx;
-            if (strcmp(bed->name, arg) == 0) {
-                return sm;
+    for (list = 0; list < DETECT_SM_LIST_MAX; list++) {
+        SigMatch *sm = s->sm_lists[list];
+        while (sm != NULL) {
+            if (sm->type == DETECT_BYTE_EXTRACT) {
+                bed = (DetectByteExtractData *)sm->ctx;
+                if (strcmp(bed->name, arg) == 0) {
+                    return sm;
+                }
             }
+            sm = sm->next;
         }
-        sm = sm->next;
     }
 
     return NULL;
diff -Nru suricata-2.0.4/src/detect-byte-extract.h suricata-2.0.6/src/detect-byte-extract.h
--- suricata-2.0.4/src/detect-byte-extract.h	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/detect-byte-extract.h	2015-01-28 08:26:48.000000000 +0100
@@ -64,7 +64,7 @@
 void DetectByteExtractFree(void *);
 int DetectByteExtractMatch(ThreadVars *, DetectEngineThreadCtx *,
                            Packet *, Signature *, SigMatch *);
-SigMatch *DetectByteExtractRetrieveSMVar(const char *, Signature *, int);
+SigMatch *DetectByteExtractRetrieveSMVar(const char *, Signature *);
 int DetectByteExtractDoMatch(DetectEngineThreadCtx *, SigMatch *, Signature *,
                              uint8_t *, uint16_t, uint64_t *, uint8_t);
 
diff -Nru suricata-2.0.4/src/detect-bytejump.c suricata-2.0.6/src/detect-bytejump.c
--- suricata-2.0.4/src/detect-bytejump.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/detect-bytejump.c	2015-01-28 08:26:48.000000000 +0100
@@ -697,7 +697,7 @@
     }
 
     if (offset != NULL) {
-        SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(offset, s, sm_list);
+        SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(offset, s);
         if (bed_sm == NULL) {
             SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var "
                        "seen in byte_jump - %s\n", offset);
diff -Nru suricata-2.0.4/src/detect-bytetest.c suricata-2.0.6/src/detect-bytetest.c
--- suricata-2.0.4/src/detect-bytetest.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/detect-bytetest.c	2015-01-28 08:26:48.000000000 +0100
@@ -621,7 +621,7 @@
     }
 
     if (value != NULL) {
-        SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(value, s, sm_list);
+        SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(value, s);
         if (bed_sm == NULL) {
             SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var "
                        "seen in byte_test - %s\n", value);
@@ -633,7 +633,7 @@
     }
 
     if (offset != NULL) {
-        SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(offset, s, sm_list);
+        SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(offset, s);
         if (bed_sm == NULL) {
             SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var "
                        "seen in byte_test - %s\n", offset);
diff -Nru suricata-2.0.4/src/detect-depth.c suricata-2.0.6/src/detect-depth.c
--- suricata-2.0.4/src/detect-depth.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/detect-depth.c	2015-01-28 08:26:48.000000000 +0100
@@ -126,7 +126,7 @@
         goto end;
     }
     if (str[0] != '-' && isalpha((unsigned char)str[0])) {
-        SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(str, s, SigMatchListSMBelongsTo(s, pm));
+        SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(str, s);
         if (bed_sm == NULL) {
             SCLogError(SC_ERR_INVALID_SIGNATURE, "unknown byte_extract var "
                        "seen in depth - %s\n", str);
diff -Nru suricata-2.0.4/src/detect-distance.c suricata-2.0.6/src/detect-distance.c
--- suricata-2.0.4/src/detect-distance.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/detect-distance.c	2015-01-28 08:26:48.000000000 +0100
@@ -133,7 +133,7 @@
         goto end;
     }
     if (str[0] != '-' && isalpha((unsigned char)str[0])) {
-        SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(str, s, SigMatchListSMBelongsTo(s, pm));
+        SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(str, s);
         if (bed_sm == NULL) {
             SCLogError(SC_ERR_INVALID_SIGNATURE, "unknown byte_extract var "
                        "seen in distance - %s\n", str);
diff -Nru suricata-2.0.4/src/detect-filestore.c suricata-2.0.6/src/detect-filestore.c
--- suricata-2.0.4/src/detect-filestore.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/detect-filestore.c	2015-01-28 08:26:48.000000000 +0100
@@ -76,7 +76,7 @@
     sigmatch_table[DETECT_FILESTORE].Setup = DetectFilestoreSetup;
     sigmatch_table[DETECT_FILESTORE].Free  = DetectFilestoreFree;
     sigmatch_table[DETECT_FILESTORE].RegisterTests = NULL;
-    sigmatch_table[DETECT_FILESTORE].flags = SIGMATCH_NOOPT;
+    sigmatch_table[DETECT_FILESTORE].flags = SIGMATCH_OPTIONAL_OPT;
 
     const char *eb;
     int eo;
diff -Nru suricata-2.0.4/src/detect.h suricata-2.0.6/src/detect.h
--- suricata-2.0.4/src/detect.h	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/detect.h	2015-01-28 08:26:48.000000000 +0100
@@ -1021,6 +1021,9 @@
 #define SIGMATCH_PAYLOAD        (1 << 3)
 /**< Flag to indicate that the signature is not built-in */
 #define SIGMATCH_NOT_BUILT      (1 << 4)
+/** sigmatch may have options, so the parser should be ready to
+ *  deal with both cases */
+#define SIGMATCH_OPTIONAL_OPT   (1 << 5)
 
 /** Remember to add the options in SignatureIsIPOnly() at detect.c otherwise it wont be part of a signature group */
 
diff -Nru suricata-2.0.4/src/detect-isdataat.c suricata-2.0.6/src/detect-isdataat.c
--- suricata-2.0.4/src/detect-isdataat.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/detect-isdataat.c	2015-01-28 08:26:48.000000000 +0100
@@ -375,7 +375,7 @@
     }
 
     if (offset != NULL) {
-        SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(offset, s, sm_list);
+        SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(offset, s);
         if (bed_sm == NULL) {
             SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var "
                        "seen in isdataat - %s\n", offset);
diff -Nru suricata-2.0.4/src/detect-offset.c suricata-2.0.6/src/detect-offset.c
--- suricata-2.0.4/src/detect-offset.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/detect-offset.c	2015-01-28 08:26:48.000000000 +0100
@@ -126,7 +126,7 @@
     }
     if (str[0] != '-' && isalpha((unsigned char)str[0])) {
         SigMatch *bed_sm =
-            DetectByteExtractRetrieveSMVar(str, s, SigMatchListSMBelongsTo(s, pm));
+            DetectByteExtractRetrieveSMVar(str, s);
         if (bed_sm == NULL) {
             SCLogError(SC_ERR_INVALID_SIGNATURE, "unknown byte_extract var "
                        "seen in offset - %s\n", str);
diff -Nru suricata-2.0.4/src/detect-parse.c suricata-2.0.6/src/detect-parse.c
--- suricata-2.0.4/src/detect-parse.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/detect-parse.c	2015-01-28 08:26:48.000000000 +0100
@@ -545,7 +545,7 @@
         }
     }
 
-    if (!(st->flags & SIGMATCH_NOOPT)) {
+    if (!(st->flags & (SIGMATCH_NOOPT|SIGMATCH_OPTIONAL_OPT))) {
         if (strlen(optvalue) == 0) {
             SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid formatting or malformed option to %s keyword: \'%s\'",
                     optname, optstr);
diff -Nru suricata-2.0.4/src/detect-pcre.c suricata-2.0.6/src/detect-pcre.c
--- suricata-2.0.4/src/detect-pcre.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/detect-pcre.c	2015-01-28 08:26:48.000000000 +0100
@@ -736,6 +736,11 @@
     sm->ctx = (void *)pd;
     SigMatchAppendSMToList(s, sm, sm_list);
 
+    if (pd->capidx != 0) {
+        if (DetectFlowvarPostMatchSetup(s, pd->capidx) < 0)
+            goto error_nofree;
+    }
+
     if (!(pd->flags & DETECT_PCRE_RELATIVE))
         goto okay;
 
@@ -759,11 +764,6 @@
         tmp->flags |= DETECT_PCRE_RELATIVE_NEXT;
     }
 
-    if (pd->capidx != 0) {
-        if (DetectFlowvarPostMatchSetup(s, pd->capidx) < 0)
-            goto error_nofree;
-    }
-
  okay:
     ret = 0;
     SCReturnInt(ret);
diff -Nru suricata-2.0.4/src/detect-ssh-software-version.c suricata-2.0.6/src/detect-ssh-software-version.c
--- suricata-2.0.4/src/detect-ssh-software-version.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/detect-ssh-software-version.c	2015-01-28 08:26:48.000000000 +0100
@@ -61,7 +61,7 @@
 /**
  * \brief Regex for parsing the softwareversion string
  */
-#define PARSE_REGEX  "^\\s*\"?\\s*?([0-9a-zA-Z\\.\\-\\_]+)\\s*\"?\\s*$"
+#define PARSE_REGEX  "^\\s*\"?\\s*?([0-9a-zA-Z\\.\\-\\_\\+\\s+]+)\\s*\"?\\s*$"
 
 static pcre *parse_regex;
 static pcre_extra *parse_regex_study;
diff -Nru suricata-2.0.4/src/detect-within.c suricata-2.0.6/src/detect-within.c
--- suricata-2.0.4/src/detect-within.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/detect-within.c	2015-01-28 08:26:48.000000000 +0100
@@ -29,6 +29,7 @@
 #include "decode.h"
 
 #include "detect.h"
+#include "detect-engine.h"
 #include "detect-parse.h"
 #include "detect-content.h"
 #include "detect-uricontent.h"
@@ -137,7 +138,7 @@
         goto end;
     }
     if (str[0] != '-' && isalpha((unsigned char)str[0])) {
-        SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(str, s, SigMatchListSMBelongsTo(s, pm));
+        SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(str, s);
         if (bed_sm == NULL) {
             SCLogError(SC_ERR_INVALID_SIGNATURE, "unknown byte_extract var "
                        "seen in within - %s\n", str);
@@ -244,6 +245,38 @@
     return result;
 }
 
+static int DetectWithinTestVarSetup(void)
+{
+    DetectEngineCtx *de_ctx = NULL;
+    int result = 0;
+    char sig[] = "alert tcp any any -> any any ( "
+        "msg:\"test rule\"; "
+        "content:\"abc\"; "
+        "http_client_body; "
+        "byte_extract:2,0,somevar,relative; "
+        "content:\"def\"; "
+        "within:somevar; "
+        "http_client_body; "
+        "sid:4; rev:1;)";
+
+    de_ctx = DetectEngineCtxInit();
+    if (de_ctx == NULL) {
+        goto end;
+    }
+    de_ctx->sig_list = SigInit(de_ctx, sig);
+    if (de_ctx->sig_list == NULL) {
+        goto end;
+    }
+
+    result = 1;
+
+end:
+    SigGroupCleanup(de_ctx);
+    SigCleanSignatures(de_ctx);
+    DetectEngineCtxFree(de_ctx);
+
+    return result;
+}
 
 #endif /* UNITTESTS */
 
@@ -251,5 +284,6 @@
     #ifdef UNITTESTS
     UtRegisterTest("DetectWithinTestPacket01", DetectWithinTestPacket01, 1);
     UtRegisterTest("DetectWithinTestPacket02", DetectWithinTestPacket02, 1);
+    UtRegisterTest("DetectWithinTestVarSetup", DetectWithinTestVarSetup, 1);
     #endif /* UNITTESTS */
 }
diff -Nru suricata-2.0.4/src/flow-util.c suricata-2.0.6/src/flow-util.c
--- suricata-2.0.4/src/flow-util.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/flow-util.c	2015-01-28 08:26:48.000000000 +0100
@@ -79,7 +79,8 @@
     FLOW_DESTROY(f);
     SCFree(f);
 
-    (void) SC_ATOMIC_SUB(flow_memuse, sizeof(Flow));
+    size_t size = sizeof(Flow) + FlowStorageSize();
+    (void) SC_ATOMIC_SUB(flow_memuse, size);
 }
 
 /**
diff -Nru suricata-2.0.4/src/flow-util.h suricata-2.0.6/src/flow-util.h
--- suricata-2.0.4/src/flow-util.h	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/flow-util.h	2015-01-28 08:26:48.000000000 +0100
@@ -97,7 +97,9 @@
         (f)->data_al_so_far[1] = 0; \
         (f)->de_ctx_id = 0; \
         if ((f)->de_state != NULL) { \
+            SCMutexLock(&(f)->de_state_m); \
             DetectEngineStateReset((f)->de_state, (STREAM_TOSERVER | STREAM_TOCLIENT)); \
+            SCMutexUnlock(&(f)->de_state_m); \
         } \
         (f)->sgh_toserver = NULL; \
         (f)->sgh_toclient = NULL; \
@@ -115,7 +117,9 @@
         \
         FLOWLOCK_DESTROY((f)); \
         if ((f)->de_state != NULL) { \
+            SCMutexLock(&(f)->de_state_m); \
             DetectEngineStateFree((f)->de_state); \
+            SCMutexUnlock(&(f)->de_state_m); \
         } \
         GenericVarFree((f)->flowvar); \
         SCMutexDestroy(&(f)->de_state_m); \
diff -Nru suricata-2.0.4/src/output-json-alert.c suricata-2.0.6/src/output-json-alert.c
--- suricata-2.0.4/src/output-json-alert.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/output-json-alert.c	2015-01-28 08:26:48.000000000 +0100
@@ -79,8 +79,6 @@
     if (p->alerts.cnt == 0)
         return TM_ECODE_OK;
 
-    MemBufferReset(buffer);
-
     json_t *js = CreateJSONHeader((Packet *)p, 0, "alert");
     if (unlikely(js == NULL))
         return TM_ECODE_OK;
@@ -104,6 +102,8 @@
             return TM_ECODE_OK;
         }
 
+        MemBufferReset(buffer);
+
         json_object_set_new(ajs, "action", json_string(action));
         json_object_set_new(ajs, "gid", json_integer(pa->s->gid));
         json_object_set_new(ajs, "signature_id", json_integer(pa->s->id));
@@ -136,11 +136,11 @@
     if (p->alerts.cnt == 0)
         return TM_ECODE_OK;
 
-    MemBufferReset(buffer);
-
     CreateIsoTimeString(&p->ts, timebuf, sizeof(timebuf));
 
     for (i = 0; i < p->alerts.cnt; i++) {
+        MemBufferReset(buffer);
+
         const PacketAlert *pa = &p->alerts.alerts[i];
         if (unlikely(pa->s == NULL)) {
             continue;
diff -Nru suricata-2.0.4/src/output-json.c suricata-2.0.6/src/output-json.c
--- suricata-2.0.4/src/output-json.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/output-json.c	2015-01-28 08:26:48.000000000 +0100
@@ -301,7 +301,7 @@
     SCMutexLock(&file_ctx->fp_mutex);
     if (json_out == ALERT_SYSLOG) {
         syslog(alert_syslog_level, "%s", js_s);
-    } else if (json_out == ALERT_FILE) {
+    } else if (json_out == ALERT_FILE || json_out == ALERT_UNIX_DGRAM || json_out == ALERT_UNIX_STREAM) {
         MemBufferWriteString(buffer, "%s\n", js_s);
         file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer),
             MEMBUFFER_OFFSET(buffer), file_ctx);
@@ -403,7 +403,7 @@
             }
         }
 
-        if (json_ctx->json_out == ALERT_FILE) {
+        if (json_ctx->json_out == ALERT_FILE || json_ctx->json_out == ALERT_UNIX_DGRAM || json_ctx->json_out == ALERT_UNIX_STREAM) {
 
             if (SCConfLogOpenGeneric(conf, json_ctx->file_ctx, DEFAULT_LOG_FILENAME) < 0) {
                 LogFileFreeCtx(json_ctx->file_ctx);
diff -Nru suricata-2.0.4/src/runmode-tile.c suricata-2.0.6/src/runmode-tile.c
--- suricata-2.0.4/src/runmode-tile.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/runmode-tile.c	2015-01-28 08:26:48.000000000 +0100
@@ -130,7 +130,8 @@
                       aconf->out_iface);
             aconf->copy_mode = MPIPE_COPY_MODE_TAP;
         } else {
-            SCLogInfo("Invalid mode (no in tap, ips)");
+            SCLogError(SC_ERR_RUNMODE, "Invalid mode (expected tap or ips)");
+            exit(EXIT_FAILURE);
         }
     }
     return aconf;
diff -Nru suricata-2.0.4/src/source-af-packet.c suricata-2.0.6/src/source-af-packet.c
--- suricata-2.0.4/src/source-af-packet.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/source-af-packet.c	2015-01-28 08:26:48.000000000 +0100
@@ -96,7 +96,6 @@
 
 #endif /* HAVE_AF_PACKET */
 
-extern uint8_t suricata_ctl_flags;
 extern int max_pending_packets;
 
 #ifndef HAVE_AF_PACKET
diff -Nru suricata-2.0.4/src/source-erf-dag.c suricata-2.0.6/src/source-erf-dag.c
--- suricata-2.0.4/src/source-erf-dag.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/source-erf-dag.c	2015-01-28 08:26:48.000000000 +0100
@@ -91,7 +91,6 @@
 #define BYTES_PER_LOOP (4 * 1024 * 1024) /* 4 MB */
 
 extern int max_pending_packets;
-extern uint8_t suricata_ctl_flags;
 
 typedef struct ErfDagThreadVars_ {
     ThreadVars *tv;
diff -Nru suricata-2.0.4/src/source-mpipe.c suricata-2.0.6/src/source-mpipe.c
--- suricata-2.0.4/src/source-mpipe.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/source-mpipe.c	2015-01-28 08:26:48.000000000 +0100
@@ -76,8 +76,6 @@
 
 #define min(a,b) (((a) < (b)) ? (a) : (b))
 
-extern uint8_t suricata_ctl_flags;
-
 /** storage for mpipe device names */
 typedef struct MpipeDevice_ {
     char *dev;  /**< the device (e.g. "xgbe1") */
@@ -330,7 +328,7 @@
     TmSlot *s = (TmSlot *)slot;
     ptv->slot = s->slot_next;
     Packet *p = NULL;
-    int cpu = tmc_cpus_get_my_cpu();
+    //int cpu = tmc_cpus_get_my_cpu();
     int rank = tv->rank;
     int max_queued = 0;
     char *ctype;
@@ -541,7 +539,7 @@
     unsigned long available_pagesizes = tmc_alloc_get_pagesizes();
 
     void *packet_page = NULL;
-    size_t tile_vhuge_size;
+    size_t tile_vhuge_size = 64 * 1024;
 
     /* Try the largest available page size first to see if any
      * pages of that size can be allocated. */
@@ -915,7 +913,7 @@
                 SCReturnInt(TM_ECODE_FAILED);
             }
         }
-        gxio_mpipe_init(context, instance);
+        result = gxio_mpipe_init(context, instance);
         VERIFY(result, "gxio_mpipe_init()");
         /* open ingress interfaces */
         for (int i = 0; i < nlive; i++) {
diff -Nru suricata-2.0.4/src/source-napatech.c suricata-2.0.6/src/source-napatech.c
--- suricata-2.0.4/src/source-napatech.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/source-napatech.c	2015-01-28 08:26:48.000000000 +0100
@@ -77,7 +77,6 @@
 #include <nt.h>
 
 extern int max_pending_packets;
-extern uint8_t suricata_ctl_flags;
 
 typedef struct NapatechThreadVars_ {
     ThreadVars *tv;
diff -Nru suricata-2.0.4/src/source-pcap.c suricata-2.0.6/src/source-pcap.c
--- suricata-2.0.4/src/source-pcap.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/source-pcap.c	2015-01-28 08:26:48.000000000 +0100
@@ -54,8 +54,6 @@
 
 #endif /* __SC_CUDA_SUPPORT__ */
 
-extern uint8_t suricata_ctl_flags;
-
 #define PCAP_STATE_DOWN 0
 #define PCAP_STATE_UP 1
 
diff -Nru suricata-2.0.4/src/source-pcap-file.c suricata-2.0.6/src/source-pcap-file.c
--- suricata-2.0.4/src/source-pcap-file.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/source-pcap-file.c	2015-01-28 08:26:48.000000000 +0100
@@ -57,7 +57,6 @@
 
 #endif /* __SC_CUDA_SUPPORT__ */
 
-extern uint8_t suricata_ctl_flags;
 extern int max_pending_packets;
 
 //static int pcap_max_read_packets = 0;
diff -Nru suricata-2.0.4/src/source-pfring.c suricata-2.0.6/src/source-pfring.c
--- suricata-2.0.4/src/source-pfring.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/source-pfring.c	2015-01-28 08:26:48.000000000 +0100
@@ -71,7 +71,6 @@
 TmEcode DecodePfringThreadDeinit(ThreadVars *tv, void *data);
 
 extern int max_pending_packets;
-extern uint8_t suricata_ctl_flags;
 
 #ifndef HAVE_PFRING
 
diff -Nru suricata-2.0.4/src/stream-tcp.c suricata-2.0.6/src/stream-tcp.c
--- suricata-2.0.4/src/stream-tcp.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/stream-tcp.c	2015-01-28 08:26:48.000000000 +0100
@@ -835,6 +835,8 @@
         ssn->client.last_ack = TCP_GET_ACK(p);
         ssn->server.last_ack = TCP_GET_SEQ(p);
 
+        ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
+
         /** If the client has a wscale option the server had it too,
          *  so set the wscale for the server to max. Otherwise none
          *  will have the wscale opt just like it should. */
@@ -1481,8 +1483,11 @@
                 ,ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p)
                 + p->payload_len, ssn->client.next_seq);
 
-        ssn->client.wscale = TCP_WSCALE_MAX;
-        ssn->server.wscale = TCP_WSCALE_MAX;
+        /* if SYN had wscale, assume it to be supported. Otherwise
+         * we know it not to be supported. */
+        if (ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) {
+            ssn->client.wscale = TCP_WSCALE_MAX;
+        }
 
         /* Set the timestamp values used to validate the timestamp of
          * received packets.*/
@@ -1501,6 +1506,9 @@
             ssn->flags |= STREAMTCP_FLAG_SACKOK;
         }
 
+        StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
+                &ssn->client, p, pq);
+
     } else {
         SCLogDebug("ssn %p: default case", ssn);
     }
@@ -1742,14 +1750,17 @@
             ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
 
             if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
-                ssn->client.window = TCP_GET_WINDOW(p);
+                ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
+                ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
                 ssn->server.next_win = ssn->server.last_ack +
                     ssn->server.window;
-                /* window scaling for midstream pickups, we can't do much
-                 * other than assume that it's set to the max value: 14 */
-                ssn->server.wscale = TCP_WSCALE_MAX;
-                ssn->client.wscale = TCP_WSCALE_MAX;
-                ssn->flags |= STREAMTCP_FLAG_SACKOK;
+                if (!(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) {
+                    /* window scaling for midstream pickups, we can't do much
+                     * other than assume that it's set to the max value: 14 */
+                    ssn->server.wscale = TCP_WSCALE_MAX;
+                    ssn->client.wscale = TCP_WSCALE_MAX;
+                    ssn->flags |= STREAMTCP_FLAG_SACKOK;
+                }
             }
 
             StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
@@ -1809,6 +1820,42 @@
 
             StreamTcpSetEvent(p, STREAM_3WHS_RIGHT_SEQ_WRONG_ACK_EVASION);
             return -1;
+
+        /* if we get a packet with a proper ack, but a seq that is beyond
+         * next_seq but in-window, we probably missed some packets */
+        } else if (SEQ_GT(TCP_GET_SEQ(p), ssn->client.next_seq) &&
+                   SEQ_LEQ(TCP_GET_SEQ(p),ssn->client.next_win) &&
+                   SEQ_EQ(TCP_GET_ACK(p), ssn->server.next_seq))
+        {
+            SCLogDebug("ssn %p: ACK for missing data", ssn);
+
+            if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
+                StreamTcpHandleTimestamp(ssn, p);
+            }
+
+            StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
+
+            ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
+            ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
+
+            ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
+
+            if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
+                ssn->client.window = TCP_GET_WINDOW(p);
+                ssn->server.next_win = ssn->server.last_ack +
+                    ssn->server.window;
+                /* window scaling for midstream pickups, we can't do much
+                 * other than assume that it's set to the max value: 14 */
+                ssn->server.wscale = TCP_WSCALE_MAX;
+                ssn->client.wscale = TCP_WSCALE_MAX;
+                ssn->flags |= STREAMTCP_FLAG_SACKOK;
+            }
+
+            StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
+            SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
+
+            StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
+                    &ssn->client, p, pq);
         } else {
             SCLogDebug("ssn %p: wrong seq nr on packet", ssn);
 
@@ -4186,6 +4233,45 @@
 }
 
 /**
+ *  Try to detect whether a packet is a valid FIN 4whs final ack.
+ *
+ */
+static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p)
+{
+    TcpStream *stream = NULL, *ostream = NULL;
+    uint32_t seq;
+    uint32_t ack;
+
+    if (p->flags & PKT_PSEUDO_STREAM_END)
+        return 0;
+    if (!(ssn->state == TCP_TIME_WAIT || ssn->state == TCP_CLOSE_WAIT || ssn->state == TCP_LAST_ACK))
+        return 0;
+    if (p->tcph->th_flags != TH_ACK)
+        return 0;
+    if (p->payload_len != 0)
+        return 0;
+
+    if (PKT_IS_TOSERVER(p)) {
+        stream = &ssn->client;
+        ostream = &ssn->server;
+    } else {
+        stream = &ssn->server;
+        ostream = &ssn->client;
+    }
+
+    seq = TCP_GET_SEQ(p);
+    ack = TCP_GET_ACK(p);
+
+    SCLogDebug("%"PRIu64", seq %u ack %u stream->next_seq %u ostream->next_seq %u",
+            p->pcap_cnt, seq, ack, stream->next_seq, ostream->next_seq);
+
+    if (SEQ_EQ(stream->next_seq + 1, seq) && SEQ_EQ(ack, ostream->next_seq + 1)) {
+        return 1;
+    }
+    return 0;
+}
+
+/**
  *  Try to detect packets doing bad window updates
  *
  *  See bug 1238.
@@ -4195,9 +4281,10 @@
  *
  *  The logic we use here is:
  *  - packet seq > next_seq
- *  - packet acq > next_seq (packet acks unseen data)
+ *  - packet ack > next_seq (packet acks unseen data)
  *  - packet shrinks window more than it's own data size
- *    (in case of no data, any shrinking is rejected)
+ *  - packet shrinks window more than the diff between it's ack and the
+ *    last_ack value
  *
  *  Packets coming in after packet loss can look quite a bit like this.
  */
@@ -4211,7 +4298,7 @@
     if (p->flags & PKT_PSEUDO_STREAM_END)
         return 0;
 
-    if (ssn->state < TCP_ESTABLISHED)
+    if (ssn->state < TCP_ESTABLISHED || ssn->state == TCP_CLOSED)
         return 0;
 
     if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0)
@@ -4240,12 +4327,25 @@
                 p->pcap_cnt, pkt_win, ostream->window, diff, p->payload_len);
             SCLogDebug("%"PRIu64", pkt_win %u, stream win %u",
                 p->pcap_cnt, pkt_win, ostream->window);
-            SCLogDebug("%"PRIu64", seq %u ack %u ostream->next_seq %u stream->last_ack %u, diff %u (%u)",
-                p->pcap_cnt, seq, ack, ostream->next_seq, stream->last_ack,
-                ostream->next_seq - ostream->last_ack, stream->next_seq - stream->last_ack);
-
-            StreamTcpSetEvent(p, STREAM_PKT_BAD_WINDOW_UPDATE);
-            return 1;
+            SCLogDebug("%"PRIu64", seq %u ack %u ostream->next_seq %u ostream->last_ack %u, ostream->next_win %u, diff %u (%u)",
+                    p->pcap_cnt, seq, ack, ostream->next_seq, ostream->last_ack, ostream->next_win,
+                    ostream->next_seq - ostream->last_ack, stream->next_seq - stream->last_ack);
+
+            /* get the expected window shrinking from looking at ack vs last_ack.
+             * Observed a lot of just a little overrunning that value. So added some
+             * margin that is still ok. To make sure this isn't a loophole to still
+             * close the window, this is limited to windows above 1024. Both values
+             * are rather arbitrary. */
+            uint32_t adiff = ack - ostream->last_ack;
+            if (((pkt_win > 1024) && (diff > (adiff + 32))) ||
+                ((pkt_win <= 1024) && (diff > adiff)))
+            {
+                SCLogDebug("pkt ACK %u is %u bytes beyond last_ack %u, shrinks window by %u "
+                        "(allowing 32 bytes extra): pkt WIN %u", ack, adiff, ostream->last_ack, diff, pkt_win);
+                SCLogDebug("%u - %u = %u (state %u)", diff, adiff, diff - adiff, ssn->state);
+                StreamTcpSetEvent(p, STREAM_PKT_BAD_WINDOW_UPDATE);
+                return 1;
+            }
         }
 
     }
@@ -4320,9 +4420,10 @@
 
         /* if packet is not a valid window update, check if it is perhaps
          * a bad window update that we should ignore (and alert on) */
-        if (StreamTcpPacketIsWindowUpdate(ssn, p) == 0)
-            if (StreamTcpPacketIsBadWindowUpdate(ssn,p))
-                goto skip;
+        if (StreamTcpPacketIsFinShutdownAck(ssn, p) == 0)
+            if (StreamTcpPacketIsWindowUpdate(ssn, p) == 0)
+                if (StreamTcpPacketIsBadWindowUpdate(ssn,p))
+                    goto skip;
 
         switch (ssn->state) {
             case TCP_SYN_SENT:
@@ -4410,6 +4511,12 @@
                                        ~FLOW_TS_PP_ALPROTO_DETECT_DONE &
                                        ~FLOW_TC_PM_ALPROTO_DETECT_DONE &
                                        ~FLOW_TC_PP_ALPROTO_DETECT_DONE);
+                    p->flow->flags &= ~ FLOW_NO_APPLAYER_INSPECTION;
+                    if (p->flow->de_state != NULL) {
+                        SCMutexLock(&p->flow->de_state_m);
+                        DetectEngineStateReset(p->flow->de_state, (STREAM_TOSERVER | STREAM_TOCLIENT));
+                        SCMutexUnlock(&p->flow->de_state_m);
+                    }
 
                     if (StreamTcpPacketStateNone(tv,p,stt,ssn, &stt->pseudo_queue)) {
                         goto error;
diff -Nru suricata-2.0.4/src/stream-tcp-reassemble.c suricata-2.0.6/src/stream-tcp-reassemble.c
--- suricata-2.0.4/src/stream-tcp-reassemble.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/stream-tcp-reassemble.c	2015-01-28 08:26:48.000000000 +0100
@@ -1911,7 +1911,10 @@
     if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) {\
         flag |= STREAM_START; \
     } \
-    if (stream->flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) {    \
+    if (ssn->state == TCP_CLOSED) { \
+        flag |= STREAM_EOF; \
+    } \
+    if (p->flags & PKT_PSEUDO_STREAM_END) { \
         flag |= STREAM_EOF; \
     } \
     if ((p)->flowflags & FLOW_PKT_TOSERVER) { \
@@ -1929,7 +1932,10 @@
     if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) {\
         flag |= STREAM_START; \
     } \
-    if (stream->flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) {    \
+    if (ssn->state == TCP_CLOSED) { \
+        flag |= STREAM_EOF; \
+    } \
+    if (p->flags & PKT_PSEUDO_STREAM_END) { \
         flag |= STREAM_EOF; \
     } \
     if ((p)->flowflags & FLOW_PKT_TOSERVER) { \
@@ -2018,6 +2024,59 @@
     SCReturnInt(1);
 }
 
+/**
+ *  \brief see if app layer is done with a segment
+ *
+ *  \retval 1 app layer is done with this segment
+ *  \retval 0 not done yet
+ */
+#define StreamTcpAppLayerSegmentProcessed(stream, segment) \
+    (( ( (stream)->flags & STREAMTCP_STREAM_FLAG_GAP ) || \
+       ( (segment)->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED ) ? 1 :0 ))
+
+/** \internal
+ *  \brief check if we can remove a segment from our segment list
+ *
+ *  If a segment is entirely before the oldest smsg, we can discard it. Otherwise
+ *  we keep it around to be able to log it.
+ *
+ *  \retval 1 yes
+ *  \retval 0 no
+ */
+static inline int StreamTcpReturnSegmentCheck(const Flow *f, TcpSession *ssn, TcpStream *stream, TcpSegment *seg)
+{
+    if (stream == &ssn->client && ssn->toserver_smsg_head != NULL) {
+        /* not (seg is entirely before first smsg, skip) */
+        if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toserver_smsg_head->seq))) {
+            SCReturnInt(0);
+        }
+    } else if (stream == &ssn->server && ssn->toclient_smsg_head != NULL) {
+        /* not (seg is entirely before first smsg, skip) */
+        if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toclient_smsg_head->seq))) {
+            SCReturnInt(0);
+        }
+    }
+
+    /* if proto detect isn't done, we're not returning */
+    if (!(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream))) {
+        SCReturnInt(0);
+    }
+
+    /* check app layer conditions */
+    if (!(f->flags & FLOW_NO_APPLAYER_INSPECTION)) {
+        if (!(StreamTcpAppLayerSegmentProcessed(stream, seg))) {
+            SCReturnInt(0);
+        }
+    }
+
+    /* check raw reassembly conditions */
+    if (!(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED)) {
+        SCReturnInt(0);
+    }
+
+    SCReturnInt(1);
+}
+
 static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg) {
     if (seg->prev == NULL) {
         stream->seg_list = seg->next;
@@ -2034,16 +2093,6 @@
 }
 
 /**
- *  \brief see if app layer is done with a segment
- *
- *  \retval 1 app layer is done with this segment
- *  \retval 0 not done yet
- */
-#define StreamTcpAppLayerSegmentProcessed(stream, segment) \
-    (( ( (stream)->flags & STREAMTCP_STREAM_FLAG_GAP ) || \
-       ( (segment)->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED ) ? 1 :0 ))
-
-/**
  *  \brief Update the stream reassembly upon receiving a data segment
  *
  *  Reassembly is in the same direction of the packet.
@@ -2112,53 +2161,69 @@
     uint16_t payload_len = 0;
     uint32_t next_seq = ra_base_seq + 1;
     uint32_t data_sent = 0;
+    TcpSegment *seg = stream->seg_list;
 
     SCLogDebug("ra_base_seq %u", ra_base_seq);
 
+    /* Check if we have a gap at the start of the list. If last_ack is
+     * bigger than the list start and the list start is bigger than
+     * next_seq, we know we are missing data that has been ack'd. That
+     * won't get retransmitted, so it's a data gap.
+     */
+    if (!(p->flow->flags & FLOW_NO_APPLAYER_INSPECTION)) {
+        if (SEQ_GT(seg->seq, next_seq) && SEQ_LT(seg->seq, stream->last_ack)) {
+            /* send gap signal */
+            STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags);
+            AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
+                    NULL, 0, flags|STREAM_GAP);
+            AppLayerProfilingStore(ra_ctx->app_tctx, p);
+
+            /* set a GAP flag and make sure not bothering this stream anymore */
+            SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set");
+            stream->flags |= STREAMTCP_STREAM_FLAG_GAP;
+
+            StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP);
+            SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca);
+#ifdef DEBUG
+            dbg_app_layer_gap++;
+#endif
+            SCReturnInt(0);
+        }
+    }
+
     /* loop through the segments and fill one or more msgs */
-    TcpSegment *seg = stream->seg_list;
     SCLogDebug("pre-loop seg %p", seg);
     for (; seg != NULL;) {
-        SCLogDebug("seg %p", seg);
+        SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32,
+                seg, seg->seq, seg->payload_len,
+                (uint32_t)(seg->seq + seg->payload_len));
 
         if (p->flow->flags & FLOW_NO_APPLAYER_INSPECTION) {
-            if (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) {
-                SCLogDebug("removing seg %p seq %"PRIu32
-                           " len %"PRIu16"", seg, seg->seq, seg->payload_len);
-
-                TcpSegment *next_seg = seg->next;
-                StreamTcpRemoveSegmentFromStream(stream, seg);
-                StreamTcpSegmentReturntoPool(seg);
-                seg = next_seg;
-                continue;
-            } else {
-                break;
-            }
+            SCLogDebug("FLOW_NO_APPLAYER_INSPECTION set, breaking out");
+            break;
+        }
 
-            /* if app layer protocol has been detected, then remove all the segments
-             * which has been previously processed and reassembled */
-        } else if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream) &&
-                   (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) &&
-                   StreamTcpAppLayerSegmentProcessed(stream, seg)) {
-            SCLogDebug("segment(%p) of length %"PRIu16" has been processed,"
-                    " so return it to pool", seg, seg->payload_len);
+        if (StreamTcpReturnSegmentCheck(p->flow, ssn, stream, seg) == 1) {
+            SCLogDebug("removing segment");
             TcpSegment *next_seg = seg->next;
             StreamTcpRemoveSegmentFromStream(stream, seg);
             StreamTcpSegmentReturntoPool(seg);
             seg = next_seg;
             continue;
+        } else if (StreamTcpAppLayerSegmentProcessed(stream, seg)) {
+            TcpSegment *next_seg = seg->next;
+            seg = next_seg;
+            continue;
         }
 
-        /* If packets are fully before ra_base_seq, skip them. We do this
-         * because we've reassembled up to the ra_base_seq point already,
-         * so we won't do anything with segments before it anyway. */
-        SCLogDebug("checking for pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32""
-                   " len %"PRIu16", combined %"PRIu32" and stream->last_ack "
-                   "%"PRIu32"", ra_base_seq, seg, seg->seq,
-                   seg->payload_len, seg->seq+seg->payload_len, stream->last_ack);
-
         /* we've run into a sequence gap */
         if (SEQ_GT(seg->seq, next_seq)) {
+            SCLogDebug("GAP: we expected %u, got %u. Diff %u", next_seq, seg->seq, seg->seq - next_seq);
+
+            /* don't conclude it's a gap until we see that the data
+             * that is missing was acked. */
+            if (SEQ_GT(seg->seq,stream->last_ack) && ssn->state != TCP_CLOSED)
+                break;
 
             /* first, pass on data before the gap */
             if (data_len > 0) {
@@ -2170,55 +2235,40 @@
                 AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
                                       data, data_len, flags);
                 AppLayerProfilingStore(ra_ctx->app_tctx, p);
-
-                data_sent += data_len;
                 data_len = 0;
             }
 
-            /* don't conclude it's a gap straight away. If ra_base_seq is lower
-             * than last_ack - the window, we consider it a gap. */
-            if (SEQ_GT((stream->last_ack - stream->window), ra_base_seq))
-            {
-                /* see what the length of the gap is, gap length is seg->seq -
-                 * (ra_base_seq +1) */
+            /* see what the length of the gap is, gap length is seg->seq -
+             * (ra_base_seq +1) */
 #ifdef DEBUG
-                uint32_t gap_len = seg->seq - next_seq;
-                SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , "
-                        "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"",
-                        next_seq, seg->seq, stream->last_ack, gap_len);
+            uint32_t gap_len = seg->seq - next_seq;
+            SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , "
+                    "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"",
+                    next_seq, seg->seq, stream->last_ack, gap_len);
 #endif
+            /* We have missed the packet and end host has ack'd it, so
+             * IDS should advance it's ra_base_seq and should not consider this
+             * packet any longer, even if it is retransmitted, as end host will
+             * drop it anyway */
+            ra_base_seq = seg->seq - 1;
 
-                /* We have missed the packet and end host has ack'd it, so
-                 * IDS should advance it's ra_base_seq and should not consider this
-                 * packet any longer, even if it is retransmitted, as end host will
-                 * drop it anyway */
-                ra_base_seq = seg->seq - 1;
-
-                /* send gap signal */
-                STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags);
-                AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
-                                      NULL, 0, flags|STREAM_GAP);
-                AppLayerProfilingStore(ra_ctx->app_tctx, p);
-                data_len = 0;
+            /* send gap signal */
+            STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags);
+            AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
+                    NULL, 0, flags|STREAM_GAP);
+            AppLayerProfilingStore(ra_ctx->app_tctx, p);
+            data_sent += data_len;
 
-                /* set a GAP flag and make sure not bothering this stream anymore */
-                SCLogDebug("set STREAMTCP_STREAM_FLAG_GAP flag");
-                stream->flags |= STREAMTCP_STREAM_FLAG_GAP;
+            /* set a GAP flag and make sure not bothering this stream anymore */
+            SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set");
+            stream->flags |= STREAMTCP_STREAM_FLAG_GAP;
 
-                StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP);
-                SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca);
+            StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP);
+            SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca);
 #ifdef DEBUG
-                dbg_app_layer_gap++;
+            dbg_app_layer_gap++;
 #endif
-                break;
-            } else {
-                SCLogDebug("possible GAP, but waiting to see if out of order "
-                        "packets might solve that");
-#ifdef DEBUG
-                dbg_app_layer_gap_candidate++;
-#endif
-                break;
-            }
+            break;
         }
 
         /* if the segment ends beyond ra_base_seq we need to consider it */
@@ -2376,6 +2426,12 @@
     /* store ra_base_seq in the stream */
     if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
         stream->ra_app_base_seq = ra_base_seq;
+    } else {
+        TcpSegment *tmp_seg = stream->seg_list;
+        while (tmp_seg != NULL) {
+            tmp_seg->flags &= ~SEGMENTTCP_FLAG_APPLAYER_PROCESSED;
+            tmp_seg = tmp_seg->next;
+        }
     }
 
     SCLogDebug("stream->ra_app_base_seq %u", stream->ra_app_base_seq);
@@ -2704,48 +2760,6 @@
     SCReturnInt(0);
 }
 
-/** \internal
- *  \brief check if we can remove a segment from our segment list
- *
- *  If a segment is entirely before the oldest smsg, we can discard it. Otherwise
- *  we keep it around to be able to log it.
- *
- *  \retval 1 yes
- *  \retval 0 no
- */
-static inline int StreamTcpReturnSegmentCheck(const Flow *f, TcpSession *ssn, TcpStream *stream, TcpSegment *seg) {
-    if (stream == &ssn->client && ssn->toserver_smsg_head != NULL) {
-        /* not (seg is entirely before first smsg, skip) */
-        if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toserver_smsg_head->seq))) {
-            SCReturnInt(0);
-        }
-    } else if (stream == &ssn->server && ssn->toclient_smsg_head != NULL) {
-        /* not (seg is entirely before first smsg, skip) */
-        if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toclient_smsg_head->seq))) {
-            SCReturnInt(0);
-        }
-    }
-
-    /* if proto detect isn't done, we're not returning */
-    if (!(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream))) {
-        SCReturnInt(0);
-    }
-
-    /* check app layer conditions */
-    if (!(f->flags & FLOW_NO_APPLAYER_INSPECTION)) {
-        if (!(StreamTcpAppLayerSegmentProcessed(stream, seg))) {
-            SCReturnInt(0);
-        }
-    }
-
-    /* check raw reassembly conditions */
-    if (!(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED)) {
-        SCReturnInt(0);
-    }
-
-    SCReturnInt(1);
-}
-
 /** \brief Remove idle TcpSegments from TcpSession
  *
  *  \param f flow
diff -Nru suricata-2.0.4/src/stream-tcp-sack.c suricata-2.0.6/src/stream-tcp-sack.c
--- suricata-2.0.4/src/stream-tcp-sack.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/stream-tcp-sack.c	2015-01-28 08:26:48.000000000 +0100
@@ -69,6 +69,17 @@
 #ifdef DEBUG
     StreamTcpSackPrintList(stream);
 #endif
+
+    /* if to the left of last_ack then ignore */
+    if (SEQ_LT(re, stream->last_ack)) {
+        SCLogDebug("too far left. discarding");
+        goto end;
+    }
+    /* if to the right of the tcp window then ignore */
+    if (SEQ_GT(le, (stream->last_ack + stream->window))) {
+        SCLogDebug("too far right. discarding");
+        goto end;
+    }
     if (stream->sack_head != NULL) {
         StreamTcpSackRecord *rec;
 
@@ -221,6 +232,7 @@
         stream->sack_tail = stsr;
     }
 
+    StreamTcpSackPruneList(stream);
 end:
     SCReturnInt(0);
 }
@@ -348,6 +360,7 @@
     int retval = 0;
 
     memset(&stream, 0, sizeof(stream));
+    stream.window = 100;
 
     StreamTcpSackInsertRange(&stream, 1, 10);
     StreamTcpSackInsertRange(&stream, 10, 20);
@@ -384,6 +397,7 @@
     int retval = 0;
 
     memset(&stream, 0, sizeof(stream));
+    stream.window = 100;
 
     StreamTcpSackInsertRange(&stream, 10, 20);
     StreamTcpSackInsertRange(&stream, 1, 20);
@@ -418,6 +432,7 @@
     int retval = 0;
 
     memset(&stream, 0, sizeof(stream));
+    stream.window = 100;
 
     StreamTcpSackInsertRange(&stream, 10, 20);
     StreamTcpSackInsertRange(&stream,  5, 15);
@@ -454,6 +469,7 @@
     int retval = 0;
 
     memset(&stream, 0, sizeof(stream));
+    stream.window = 100;
 
     StreamTcpSackInsertRange(&stream, 0,  20);
     StreamTcpSackInsertRange(&stream, 30, 50);
@@ -487,6 +503,7 @@
     int retval = 0;
 
     memset(&stream, 0, sizeof(stream));
+    stream.window = 100;
 
     StreamTcpSackInsertRange(&stream, 0,  20);
     StreamTcpSackInsertRange(&stream, 30, 50);
@@ -520,6 +537,7 @@
     int retval = 0;
 
     memset(&stream, 0, sizeof(stream));
+    stream.window = 100;
 
     StreamTcpSackInsertRange(&stream, 0,  9);
     StreamTcpSackInsertRange(&stream, 11, 19);
@@ -555,6 +573,7 @@
     int retval = 0;
 
     memset(&stream, 0, sizeof(stream));
+    stream.window = 100;
 
     StreamTcpSackInsertRange(&stream, 0,  9);
     StreamTcpSackInsertRange(&stream, 11, 19);
@@ -599,6 +618,7 @@
     int retval = 0;
 
     memset(&stream, 0, sizeof(stream));
+    stream.window = 100;
 
     StreamTcpSackInsertRange(&stream, 0,  9);
     StreamTcpSackInsertRange(&stream, 11, 19);
@@ -643,6 +663,7 @@
     int retval = 0;
 
     memset(&stream, 0, sizeof(stream));
+    stream.window = 100;
 
     StreamTcpSackInsertRange(&stream, 0,  9);
     StreamTcpSackInsertRange(&stream, 11, 19);
@@ -688,6 +709,7 @@
     int retval = 0;
 
     memset(&stream, 0, sizeof(stream));
+    stream.window = 1000;
 
     StreamTcpSackInsertRange(&stream, 100, 119);
     StreamTcpSackInsertRange(&stream, 111, 119);
@@ -732,6 +754,7 @@
     int retval = 0;
 
     memset(&stream, 0, sizeof(stream));
+    stream.window = 1000;
 
     StreamTcpSackInsertRange(&stream, 100, 119);
     StreamTcpSackInsertRange(&stream, 111, 119);
@@ -776,6 +799,7 @@
     int retval = 0;
 
     memset(&stream, 0, sizeof(stream));
+    stream.window = 2000;
 
     StreamTcpSackInsertRange(&stream, 800, 1000);
     StreamTcpSackInsertRange(&stream, 700, 900);
@@ -816,6 +840,70 @@
     SCReturnInt(retval);
 }
 
+/**
+ *  \test   Test the insertion on out of window condition.
+ *
+ *  \retval On success it returns 1 and on failure 0.
+ */
+
+static int StreamTcpSackTest13 (void) {
+    TcpStream stream;
+    int retval = 0;
+    int i;
+
+    memset(&stream, 0, sizeof(stream));
+    stream.last_ack = 10000;
+    stream.window = 2000;
+
+    for (i = 0; i < 10; i++) {
+        StreamTcpSackInsertRange(&stream, 100+(20*i), 110+(20*i));
+    }
+#ifdef DEBUG
+    StreamTcpSackPrintList(&stream);
+#endif /* DEBUG */
+
+    if (StreamTcpSackedSize(&stream) != 0) {
+        printf("Sacked size is %u: ", StreamTcpSackedSize(&stream));
+        goto end;
+    }
+
+    retval = 1;
+end:
+    SCReturnInt(retval);
+}
+
+/**
+ *  \test   Test the insertion of out of window condition.
+ *
+ *  \retval On success it returns 1 and on failure 0.
+ */
+
+static int StreamTcpSackTest14 (void) {
+    TcpStream stream;
+    int retval = 0;
+    int i;
+
+    memset(&stream, 0, sizeof(stream));
+    stream.last_ack = 1000;
+    stream.window = 2000;
+
+    for (i = 0; i < 10; i++) {
+        StreamTcpSackInsertRange(&stream, 4000+(20*i), 4010+(20*i));
+    }
+#ifdef DEBUG
+    StreamTcpSackPrintList(&stream);
+#endif /* DEBUG */
+
+    if (StreamTcpSackedSize(&stream) != 0) {
+        printf("Sacked size is %u: ", StreamTcpSackedSize(&stream));
+        goto end;
+    }
+
+    retval = 1;
+end:
+    SCReturnInt(retval);
+}
+
 #endif /* UNITTESTS */
 
 void StreamTcpSackRegisterTests (void) {
@@ -844,5 +932,9 @@
                     StreamTcpSackTest11, 1);
     UtRegisterTest("StreamTcpSackTest12 -- Insertion && Pruning",
                     StreamTcpSackTest12, 1);
+    UtRegisterTest("StreamTcpSackTest13 -- Insertion out of window",
+                    StreamTcpSackTest13, 1);
+    UtRegisterTest("StreamTcpSackTest14 -- Insertion out of window",
+                    StreamTcpSackTest14, 1);
 #endif
 }
diff -Nru suricata-2.0.4/src/suricata.c suricata-2.0.6/src/suricata.c
--- suricata-2.0.4/src/suricata.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/suricata.c	2015-01-28 08:26:48.000000000 +0100
@@ -197,7 +197,7 @@
 #define DEFAULT_MAX_PENDING_PACKETS 1024
 
 /** suricata engine control flags */
-uint8_t suricata_ctl_flags = 0;
+volatile uint8_t suricata_ctl_flags = 0;
 
 /** Run mode selected */
 int run_mode = RUNMODE_UNKNOWN;
diff -Nru suricata-2.0.4/src/suricata-common.h suricata-2.0.6/src/suricata-common.h
--- suricata-2.0.4/src/suricata-common.h	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/suricata-common.h	2015-01-28 08:26:48.000000000 +0100
@@ -323,8 +323,12 @@
 #include "util-path.h"
 #include "util-conf.h"
 
+#ifndef HAVE_STRLCAT
 size_t strlcat(char *, const char *src, size_t siz);
+#endif
+#ifndef HAVE_STRLCPY
 size_t strlcpy(char *dst, const char *src, size_t siz);
+#endif
 
 extern int coverage_unittests;
 extern int g_ut_modules;
diff -Nru suricata-2.0.4/src/suricata.h suricata-2.0.6/src/suricata.h
--- suricata-2.0.4/src/suricata.h	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/suricata.h	2015-01-28 08:26:48.000000000 +0100
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2010 Open Information Security Foundation
+/* Copyright (C) 2007-2014 Open Information Security Foundation
  *
  * You can copy, redistribute or modify this Program under the terms of
  * the GNU General Public License version 2 as published by the Free
@@ -71,7 +71,7 @@
 
 /* the name of our binary */
 #define PROG_NAME "Suricata"
-#define PROG_VER "2.0.4"
+#define PROG_VER "2.0.6"
 
 /* workaround SPlint error (don't know __gnuc_va_list) */
 #ifdef S_SPLINT_S
@@ -162,7 +162,7 @@
 /* memset to zeros, and mutex init! */
 void GlobalInits();
 
-extern uint8_t suricata_ctl_flags;
+extern volatile uint8_t suricata_ctl_flags;
 
 /* uppercase to lowercase conversion lookup table */
 uint8_t g_u8_lowercasetable[256];
diff -Nru suricata-2.0.4/src/threads.c suricata-2.0.6/src/threads.c
--- suricata-2.0.4/src/threads.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/threads.c	2015-01-28 08:26:48.000000000 +0100
@@ -86,7 +86,14 @@
     int r = 0;
     r |= SCRWLockInit(&rwl_write, NULL);
     r |= SCRWLockWRLock(&rwl_write);
+/* work around OS X 10.10 Yosemite returning EDEADLK. All other
+ * OS' (and versions of OS X that I tested) seem to return EBUSY
+ * instead. */
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__==101000
+    r |= (SCRWLockTryWRLock(&rwl_write) == EDEADLK)? 0 : 1;
+#else
     r |= (SCRWLockTryWRLock(&rwl_write) == EBUSY)? 0 : 1;
+#endif
     r |= SCRWLockUnlock(&rwl_write);
     r |= SCRWLockDestroy(&rwl_write);
 
diff -Nru suricata-2.0.4/src/unix-manager.c suricata-2.0.6/src/unix-manager.c
--- suricata-2.0.4/src/unix-manager.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/unix-manager.c	2015-01-28 08:26:48.000000000 +0100
@@ -297,6 +297,7 @@
         SCLogInfo("Command server: client message is too long, "
                   "disconnect him.");
         close(client);
+        return 0;
     }
     buffer[ret] = 0;
 
diff -Nru suricata-2.0.4/src/util-memcmp.c suricata-2.0.6/src/util-memcmp.c
--- suricata-2.0.4/src/util-memcmp.c	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/util-memcmp.c	2015-01-28 08:26:48.000000000 +0100
@@ -322,6 +322,46 @@
     return 1;
 }
 
+struct MemcmpTest18Tests {
+    char *a;
+    char *b;
+    int result;
+} memcmp_tests18_tests[] = {
+        { "abcdefgh", "!bcdefgh", 1, },
+        { "?bcdefgh", "!bcdefgh", 1, },
+        { "!bcdefgh", "abcdefgh", 1, },
+        { "!bcdefgh", "?bcdefgh", 1, },
+        { "zbcdefgh", "bbcdefgh", 1, },
+
+        { "abcdefgh12345678", "!bcdefgh12345678", 1, },
+        { "?bcdefgh12345678", "!bcdefgh12345678", 1, },
+        { "!bcdefgh12345678", "abcdefgh12345678", 1, },
+        { "!bcdefgh12345678", "?bcdefgh12345678", 1, },
+        { "bbcdefgh12345678", "zbcdefgh12345678", 1, },
+
+        { "abcdefgh", "abcdefgh", 0, },
+        { "abcdefgh", "Abcdefgh", 0, },
+        { "abcdefgh12345678", "Abcdefgh12345678", 0, },
+
+        { NULL, NULL, 0 },
+
+    };
+
+static int MemcmpTest18 (void)
+{
+    struct MemcmpTest18Tests *t = memcmp_tests18_tests;
+
+    while (t && t->a != NULL) {
+
+        if (SCMemcmpLowercase(t->a, t->b, strlen(t->a)-1) != t->result)
+            return 0;
+        SCLogInfo("ok");
+        t++;
+    }
+
+    return 1;
+}
+
 #endif /* UNITTESTS */
 
 void MemcmpRegisterTests(void) {
@@ -343,6 +383,7 @@
     UtRegisterTest("MemcmpTest15", MemcmpTest15, 1);
     UtRegisterTest("MemcmpTest16", MemcmpTest16, 1);
     UtRegisterTest("MemcmpTest17", MemcmpTest17, 1);
+    UtRegisterTest("MemcmpTest18", MemcmpTest18, 1);
 #endif /* UNITTESTS */
 }
 
diff -Nru suricata-2.0.4/src/util-memcmp.h suricata-2.0.6/src/util-memcmp.h
--- suricata-2.0.4/src/util-memcmp.h	2014-09-25 21:10:10.000000000 +0200
+++ suricata-2.0.6/src/util-memcmp.h	2015-01-28 08:26:48.000000000 +0100
@@ -39,13 +39,14 @@
 void MemcmpRegisterTests(void);
 
 static inline int
-MemcmpLowercase(const void *s1, const void *s2, size_t n) {
-    size_t i;
+MemcmpLowercase(const void *s1, const void *s2, size_t n)
+{
+    ssize_t i;
 
     /* check backwards because we already tested the first
      * 2 to 4 chars. This way we are more likely to detect
      * a miss and thus speed up a little... */
-    for (i = n - 1; i; i--) {
+    for (i = n - 1; i >= 0; i--) {
         if (((uint8_t *)s1)[i] != u8_tolower(*(((uint8_t *)s2)+i)))
             return 1;
     }


unblock suricata/2.0.6-1

-- System Information:
Debian Release: 8.0
  APT prefers testing-updates
  APT policy: (500, 'testing-updates'), (500, 'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 3.16.0-4-amd64 (SMP w/2 CPU cores)
Locale: LANG=es_ES.utf8, LC_CTYPE=es_ES.utf8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)


Reply to: