]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
pcre: support multiple captures
authorVictor Julien <victor@inliniac.net>
Wed, 26 Oct 2016 14:55:34 +0000 (16:55 +0200)
committerVictor Julien <victor@inliniac.net>
Thu, 16 Feb 2017 09:35:44 +0000 (10:35 +0100)
Support up to 8 substring captures into pkt or flow vars.

src/detect-engine-sigorder.c
src/detect-pcre.c
src/detect-pcre.h
src/util-error.c
src/util-error.h

index 56b87c9cc6142ff42856660388b0896c29c97f71..737e493653531d9c3cd8bc5f91860a0909006af4 100644 (file)
@@ -267,8 +267,14 @@ static inline int SCSigGetFlowvarType(Signature *sig)
 
     while (sm != NULL) {
         pd = (DetectPcreData *)sm->ctx;
-        if (sm->type == DETECT_PCRE && (pd->flags & DETECT_PCRE_CAPTURE_FLOW)) {
-            write++;
+        if (sm->type == DETECT_PCRE) {
+            uint8_t x;
+            for (x = 0; x < pd->idx; x++) {
+                if (pd->captypes[x] == VAR_TYPE_FLOW_VAR) {
+                    write++;
+                    break;
+                }
+            }
         }
 
         sm = sm->next;
@@ -319,8 +325,14 @@ static inline int SCSigGetPktvarType(Signature *sig)
 
     while (sm != NULL) {
         pd = (DetectPcreData *)sm->ctx;
-        if (sm->type == DETECT_PCRE && (pd->flags & DETECT_PCRE_CAPTURE_PKT)) {
-            write++;
+        if (sm->type == DETECT_PCRE) {
+            uint8_t x;
+            for (x = 0; x < pd->idx; x++) {
+                if (pd->captypes[x] == VAR_TYPE_PKT_VAR) {
+                    write++;
+                    break;
+                }
+            }
         }
 
         sm = sm->next;
index 8d2e758a83c0b8189140cfa81b7c05814b07e31e..b3f7281dcc707e806989a9ea33f14cb8197e90c0 100644 (file)
@@ -213,26 +213,29 @@ int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, const Signature *s,
             /* regex matched and we're not negated,
              * considering it a match */
 
-            SCLogDebug("ret %d capidx %u", ret, pe->capidx);
+            SCLogDebug("ret %d pe->idx %u", ret, pe->idx);
 
             /* see if we need to do substring capturing. */
-            if (ret > 1 && pe->capidx != 0) {
-                SCLogDebug("capturing");
-                const char *str_ptr;
-                ret = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, 1, &str_ptr);
-                if (ret) {
-                    if (pe->flags & DETECT_PCRE_CAPTURE_PKT) {
-                        if (p != NULL) {
-                            PktVarAdd(p, pe->capname, (uint8_t *)str_ptr, ret);
-                        }
-                    } else if (pe->flags & DETECT_PCRE_CAPTURE_FLOW) {
-                        if (f != NULL) {
-                            /* store max 64k. Errors are ignored */
-                            capture_len = (ret < 0xffff) ? (uint16_t)ret : 0xffff;
-                            (void)DetectFlowvarStoreMatch(det_ctx, pe->capidx,
-                                    (uint8_t *)str_ptr, capture_len,
-                                    DETECT_FLOWVAR_TYPE_POSTMATCH);
-                        }
+            if (ret > 1 && pe->idx != 0) {
+                uint8_t x;
+                for (x = 0; x < pe->idx; x++) {
+                    SCLogDebug("capturing");
+                    const char *str_ptr;
+                    ret = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, x+1, &str_ptr);
+                    if (unlikely(ret == 0))
+                        continue;
+
+                    if (pe->captypes[x] == VAR_TYPE_PKT_VAR && p != NULL) {
+                        const char *varname = VarNameStoreLookupById(pe->capids[x],
+                                VAR_TYPE_PKT_VAR);
+                        PktVarAdd(p, varname, (uint8_t *)str_ptr, ret);
+
+                    } else if (pe->captypes[x] == VAR_TYPE_FLOW_VAR && f != NULL) {
+                        /* store max 64k. Errors are ignored */
+                        capture_len = (ret < 0xffff) ? (uint16_t)ret : 0xffff;
+                        (void)DetectFlowvarStoreMatch(det_ctx, pe->capids[x],
+                                (uint8_t *)str_ptr, capture_len,
+                                DETECT_FLOWVAR_TYPE_POSTMATCH);
                     }
                 }
             }
@@ -607,7 +610,11 @@ static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, Detec
 {
     int ret = 0, res = 0;
     int ov[MAX_SUBSTRINGS];
+    memset(&ov, 0, sizeof(ov));
     char type_str[16] = "";
+    char *orig_right_edge = regexstr + strlen(regexstr);
+
+    SCLogDebug("regexstr %s, pd %p", regexstr, pd);
 
     /* take the size of the whole input as buffer size for the string we will
      * extract below. Add 1 to please Coverity's alloc_strlen test. */
@@ -618,55 +625,57 @@ static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, Detec
     if (de_ctx == NULL)
         goto error;
 
-    SCLogDebug("\'%s\'", regexstr);
+    while (1) {
+        SCLogDebug("\'%s\'", regexstr);
 
-    ret = pcre_exec(parse_capture_regex, parse_capture_regex_study, regexstr, strlen(regexstr), 0, 0, ov, MAX_SUBSTRINGS);
-    if (ret < 3) {
-        return 0;
-    }
+        ret = pcre_exec(parse_capture_regex, parse_capture_regex_study, regexstr, strlen(regexstr), 0, 0, ov, MAX_SUBSTRINGS);
+        if (ret < 3) {
+            return 0;
+        }
 
-    res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 1, type_str, sizeof(type_str));
-    if (res < 0) {
-        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
-        goto error;
-    }
-    res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 2, capture_str, cap_buffer_len);
-    if (res < 0) {
-        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
-        goto error;
-    }
-    if (strlen(capture_str) == 0 || strlen(type_str) == 0) {
-        goto error;
-    }
+        res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 1, type_str, sizeof(type_str));
+        if (res < 0) {
+            SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
+            goto error;
+        }
+        res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 2, capture_str, cap_buffer_len);
+        if (res < 0) {
+            SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
+            goto error;
+        }
+        if (strlen(capture_str) == 0 || strlen(type_str) == 0) {
+            goto error;
+        }
 
-    SCLogDebug("type \'%s\'", type_str);
-    SCLogDebug("capture \'%s\'", capture_str);
+        SCLogDebug("type \'%s\'", type_str);
+        SCLogDebug("capture \'%s\'", capture_str);
 
-    pd->capname = SCStrdup(capture_str);
-    if (unlikely(pd->capname == NULL))
-        goto error;
+        if (pd->idx >= DETECT_PCRE_CAPTURE_MAX) {
+            SCLogError(SC_ERR_VAR_LIMIT, "rule can have maximally %d pkt/flow "
+                    "var captures", DETECT_PCRE_CAPTURE_MAX);
+            return -1;
+        }
 
-    if (strcmp(type_str, "pkt") == 0) {
-        pd->flags |= DETECT_PCRE_CAPTURE_PKT;
-    } else if (strcmp(type_str, "flow") == 0) {
-        pd->flags |= DETECT_PCRE_CAPTURE_FLOW;
-        SCLogDebug("flow capture");
-    }
-    if (pd->capname != NULL) {
-        if (pd->flags & DETECT_PCRE_CAPTURE_PKT)
-            pd->capidx = VarNameStoreSetupAdd((char *)pd->capname, VAR_TYPE_PKT_VAR);
-        else if (pd->flags & DETECT_PCRE_CAPTURE_FLOW)
-            pd->capidx = VarNameStoreSetupAdd((char *)pd->capname, VAR_TYPE_FLOW_VAR);
-    }
+        if (strcmp(type_str, "pkt") == 0) {
+            pd->capids[pd->idx] = VarNameStoreSetupAdd((char *)capture_str, VAR_TYPE_PKT_VAR);
+            pd->captypes[pd->idx] = VAR_TYPE_PKT_VAR;
+            SCLogDebug("id %u type %u", pd->capids[pd->idx], pd->captypes[pd->idx]);
+            pd->idx++;
+        } else if (strcmp(type_str, "flow") == 0) {
+            pd->capids[pd->idx] = VarNameStoreSetupAdd((char *)capture_str, VAR_TYPE_FLOW_VAR);
+            pd->captypes[pd->idx] = VAR_TYPE_FLOW_VAR;
+            pd->idx++;
+        }
 
-    SCLogDebug("pd->capname %s", pd->capname);
+        //SCLogDebug("pd->capname %s", pd->capname);
+        regexstr += ov[1];
+
+        if (regexstr >= orig_right_edge)
+            break;
+    }
     return 0;
 
 error:
-    if (pd->capname != NULL) {
-        SCFree(pd->capname);
-        pd->capname = NULL;
-    }
     return -1;
 }
 
@@ -708,9 +717,12 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst
     sm->ctx = (void *)pd;
     SigMatchAppendSMToList(s, sm, sm_list);
 
-    if (pd->capidx != 0) {
-        if (DetectFlowvarPostMatchSetup(s, pd->capidx) < 0)
-            goto error_nofree;
+    uint8_t x;
+    for (x = 0; x < pd->idx; x++) {
+        if (pd->captypes[x] == VAR_TYPE_FLOW_VAR) {
+            if (DetectFlowvarPostMatchSetup(s, pd->capids[x]) < 0)
+                goto error_nofree;
+        }
     }
 
     if (!(pd->flags & DETECT_PCRE_RELATIVE))
@@ -751,8 +763,6 @@ static void DetectPcreFree(void *ptr)
 
     DetectPcreData *pd = (DetectPcreData *)ptr;
 
-    if (pd->capname != NULL)
-        SCFree(pd->capname);
     if (pd->re != NULL)
         pcre_free(pd->re);
     if (pd->sd != NULL)
@@ -3022,7 +3032,7 @@ static int DetectPcreFlowvarCapture01(void)
 
     FAIL_IF(!(PacketAlertCheck(p1, 1)));
 
-    FlowVar *fv = FlowVarGet(&f, pd->capidx);
+    FlowVar *fv = FlowVarGet(&f, pd->capids[0]);
     FAIL_IF(fv == NULL);
 
     FAIL_IF(fv->data.fv_str.value_len != ualen1);
@@ -3114,7 +3124,7 @@ static int DetectPcreFlowvarCapture02(void)
         s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE);
     DetectPcreData *pd2 = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx;
 
-    FAIL_IF(pd1->capidx != pd2->capidx);
+    FAIL_IF(pd1->capids[0] != pd2->capids[0]);
 
     SCSigRegisterSignatureOrderingFuncs(de_ctx);
     SCSigOrderSignatures(de_ctx);
@@ -3136,7 +3146,7 @@ static int DetectPcreFlowvarCapture02(void)
 
     FAIL_IF(!(PacketAlertCheck(p1, 1)));
 
-    FlowVar *fv = FlowVarGet(&f, pd1->capidx);
+    FlowVar *fv = FlowVarGet(&f, pd1->capids[0]);
     FAIL_IF(fv == NULL);
 
     if (fv->data.fv_str.value_len != ualen1) {
@@ -3230,7 +3240,7 @@ static int DetectPcreFlowvarCapture03(void)
         s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE);
     DetectPcreData *pd2 = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx;
 
-    FAIL_IF(pd1->capidx != pd2->capidx);
+    FAIL_IF(pd1->capids[0] != pd2->capids[0]);
 
     SigGroupBuild(de_ctx);
     DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
@@ -3249,7 +3259,7 @@ static int DetectPcreFlowvarCapture03(void)
 
     FAIL_IF(PacketAlertCheck(p1, 1));
 
-    FlowVar *fv = FlowVarGet(&f, pd1->capidx);
+    FlowVar *fv = FlowVarGet(&f, pd1->capids[0]);
     FAIL_IF(fv != NULL);
 
     if (alp_tctx != NULL)
index 3f9ce7557f8cce2610f65e41af4c89784f0ca335..14360c1eefebdd5582fc68426acbdeaf1b0e7009 100644 (file)
 #define DETECT_PCRE_RELATIVE            0x00001
 #define DETECT_PCRE_RAWBYTES            0x00002
 #define DETECT_PCRE_CASELESS            0x00004
-#define DETECT_PCRE_CAPTURE_PKT         0x00008
-#define DETECT_PCRE_CAPTURE_FLOW        0x00010
+
 #define DETECT_PCRE_MATCH_LIMIT         0x00020
 #define DETECT_PCRE_RELATIVE_NEXT       0x00040
 #define DETECT_PCRE_NEGATE              0x00080
 
+#define DETECT_PCRE_CAPTURE_MAX         8
+
 typedef struct DetectPcreData_ {
     /* pcre options */
     pcre *re;
     pcre_extra *sd;
     int opts;
     uint16_t flags;
-    uint32_t capidx;
-    char *capname;
+    uint8_t idx;
+    uint8_t captypes[DETECT_PCRE_CAPTURE_MAX];
+    uint32_t capids[DETECT_PCRE_CAPTURE_MAX];
 } DetectPcreData;
 
 /* prototypes */
index 105add555dc628a80546044db0896ff0ba5a7256..4503986fb5c28a64d78ffb643c4c22c6ef24c6dc 100644 (file)
@@ -335,6 +335,7 @@ const char * SCErrorToString(SCError err)
         CASE_CODE(SC_WARN_REMOVE_FILE);
         CASE_CODE (SC_ERR_NO_MAGIC_SUPPORT);
         CASE_CODE (SC_ERR_REDIS);
+        CASE_CODE (SC_ERR_VAR_LIMIT);
     }
 
     return "UNKNOWN_ERROR";
index acaec8162567dc385afa82f00bdd334f0b706f59..59778c5606c44a472387dcbdcd0476b80882bd30 100644 (file)
@@ -325,6 +325,7 @@ typedef enum {
     SC_WARN_REMOVE_FILE,
     SC_ERR_NO_MAGIC_SUPPORT,
     SC_ERR_REDIS,
+    SC_ERR_VAR_LIMIT,
 } SCError;
 
 const char *SCErrorToString(SCError);