From: Victor Julien Date: Wed, 26 Oct 2016 14:55:34 +0000 (+0200) Subject: pcre: support multiple captures X-Git-Tag: suricata-4.0.0-beta1~327 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a0bd15a1c47f64b34604fa3a4b8bd143af0bc1d6;p=thirdparty%2Fsuricata.git pcre: support multiple captures Support up to 8 substring captures into pkt or flow vars. --- diff --git a/src/detect-engine-sigorder.c b/src/detect-engine-sigorder.c index 56b87c9cc6..737e493653 100644 --- a/src/detect-engine-sigorder.c +++ b/src/detect-engine-sigorder.c @@ -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; diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 8d2e758a83..b3f7281dcc 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -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) diff --git a/src/detect-pcre.h b/src/detect-pcre.h index 3f9ce7557f..14360c1eef 100644 --- a/src/detect-pcre.h +++ b/src/detect-pcre.h @@ -27,20 +27,22 @@ #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 */ diff --git a/src/util-error.c b/src/util-error.c index 105add555d..4503986fb5 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -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"; diff --git a/src/util-error.h b/src/util-error.h index acaec81625..59778c5606 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -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);