static DetectParseRegex parse_regex;
static DetectParseRegex parse_capture_regex;
-#ifdef PCRE_HAVE_JIT
-static int pcre_use_jit = 1;
+#ifdef PCRE2_HAVE_JIT
+static int pcre2_use_jit = 1;
#endif
-#ifdef PCRE_HAVE_JIT_EXEC
-#define PCRE_JIT_MIN_STACK 32*1024
-#define PCRE_JIT_MAX_STACK 512*1024
-
-#endif
+// TODOpcre2 pcre2_jit_stack_create ?
/* \brief Helper function for using pcre_exec with/without JIT
*/
-static inline int DetectPcreExec(DetectEngineThreadCtx *det_ctx, DetectPcreData *pd, DetectParseRegex *regex,
- const char *str, const size_t strlen, int start_offset, int options, int *ovector, int ovector_size)
+static inline int DetectPcreExec(DetectEngineThreadCtx *det_ctx, DetectPcreData *pd,
+ const char *str, const size_t strlen, int start_offset, int options)
{
-#ifdef PCRE_HAVE_JIT_EXEC
- if (pd->thread_ctx_jit_stack_id != -1) {
- pcre_jit_stack *jit_stack = (pcre_jit_stack *)
- DetectThreadCtxGetKeywordThreadCtx(det_ctx, pd->thread_ctx_jit_stack_id);
- if (jit_stack) {
- SCLogDebug("Using jit_stack %p", jit_stack);
- return pcre_jit_exec(regex->regex, regex->study, str, strlen,
- start_offset, options, ovector, ovector_size,
- jit_stack);
- }
- }
-#endif
/* Fallback if registration during setup failed */
- return pcre_exec(regex->regex, regex->study, str, strlen,
- start_offset, options, ovector, ovector_size);
+ return pcre2_match(pd->parse_regex.regex, (PCRE2_SPTR8)str, strlen, start_offset, options,
+ pd->parse_regex.match, NULL);
}
static int DetectPcreSetup (DetectEngineCtx *, Signature *, const char *);
FatalError(SC_ERR_PCRE_COMPILE, "pcre compile and study failed");
}
-#ifdef PCRE_HAVE_JIT
+#ifdef PCRE2_HAVE_JIT
if (PageSupportsRWX() == 0) {
- SCLogConfig("PCRE won't use JIT as OS doesn't allow RWX pages");
- pcre_use_jit = 0;
+ SCLogConfig("PCRE2 won't use JIT as OS doesn't allow RWX pages");
+ pcre2_use_jit = 0;
}
#endif
{
SCEnter();
int ret = 0;
- int ov[MAX_SUBSTRINGS];
const uint8_t *ptr = NULL;
uint16_t len = 0;
- uint16_t capture_len = 0;
+ PCRE2_SIZE capture_len = 0;
DetectPcreData *pe = (DetectPcreData *)smd->ctx;
}
/* run the actual pcre detection */
- ret = DetectPcreExec(det_ctx, pe, &pe->parse_regex, (char *) ptr, len, start_offset, 0, ov, MAX_SUBSTRINGS);
+ ret = DetectPcreExec(det_ctx, pe, (char *)ptr, len, start_offset, 0);
SCLogDebug("ret %d (negating %s)", ret, (pe->flags & DETECT_PCRE_NEGATE) ? "set" : "not set");
- if (ret == PCRE_ERROR_NOMATCH) {
+ if (ret == PCRE2_ERROR_NOMATCH) {
if (pe->flags & DETECT_PCRE_NEGATE) {
/* regex didn't match with negate option means we
* consider it a match */
uint8_t x;
for (x = 0; x < pe->idx; x++) {
SCLogDebug("capturing %u", x);
- const char *str_ptr = NULL;
- ret = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, x+1, &str_ptr);
- if (unlikely(ret == 0)) {
- pcre_free_substring(str_ptr);
+ const char *pcre2_str_ptr = NULL;
+ ret = pcre2_substring_get_bynumber(pe->parse_regex.match, x + 1,
+ (PCRE2_UCHAR8 **)&pcre2_str_ptr, &capture_len);
+ if (unlikely(ret != 0)) {
+ pcre2_substring_free((PCRE2_UCHAR8 *)pcre2_str_ptr);
+ continue;
+ }
+ /* store max 64k. Errors are ignored */
+ capture_len = (capture_len < 0xffff) ? (uint16_t)capture_len : 0xffff;
+ uint8_t *str_ptr = SCMalloc(capture_len);
+ if (unlikely(str_ptr == NULL)) {
+ pcre2_substring_free((PCRE2_UCHAR8 *)pcre2_str_ptr);
continue;
}
+ memcpy(str_ptr, pcre2_str_ptr, capture_len);
+ pcre2_substring_free((PCRE2_UCHAR8 *)pcre2_str_ptr);
SCLogDebug("data %p/%u, type %u id %u p %p",
str_ptr, ret, pe->captypes[x], pe->capids[x], p);
if (pe->captypes[x] == VAR_TYPE_PKT_VAR_KV) {
/* get the value, as first capture is the key */
- const char *str_ptr2 = NULL;
- int ret2 = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, x+2, &str_ptr2);
- if (unlikely(ret2 == 0)) {
- pcre_free_substring(str_ptr);
- pcre_free_substring(str_ptr2);
+ const char *pcre2_str_ptr2 = NULL;
+ /* key length is limited to 256 chars */
+ uint16_t key_len = (capture_len < 0xff) ? (uint16_t)capture_len : 0xff;
+ int ret2 = pcre2_substring_get_bynumber(pe->parse_regex.match, x + 2,
+ (PCRE2_UCHAR8 **)&pcre2_str_ptr2, &capture_len);
+
+ if (unlikely(ret2 != 0)) {
+ SCFree(str_ptr);
+ pcre2_substring_free((PCRE2_UCHAR8 *)pcre2_str_ptr2);
break;
}
- /* key length is limited to 256 chars */
- uint16_t key_len = (ret < 0xff) ? (uint16_t)ret : 0xff;
- capture_len = (ret2 < 0xffff) ? (uint16_t)ret2 : 0xffff;
+ capture_len = (capture_len < 0xffff) ? (uint16_t)capture_len : 0xffff;
+ uint8_t *str_ptr2 = SCMalloc(capture_len);
+ if (unlikely(str_ptr2 == NULL)) {
+ pcre2_substring_free((PCRE2_UCHAR8 *)pcre2_str_ptr);
+ continue;
+ }
+ memcpy(str_ptr2, pcre2_str_ptr2, capture_len);
+ pcre2_substring_free((PCRE2_UCHAR8 *)pcre2_str_ptr2);
(void)DetectVarStoreMatchKeyValue(det_ctx,
(uint8_t *)str_ptr, key_len,
DETECT_VAR_TYPE_PKT_POSTMATCH);
} else if (pe->captypes[x] == VAR_TYPE_PKT_VAR) {
- /* store max 64k. Errors are ignored */
- capture_len = (ret < 0xffff) ? (uint16_t)ret : 0xffff;
(void)DetectVarStoreMatch(det_ctx, pe->capids[x],
(uint8_t *)str_ptr, capture_len,
DETECT_VAR_TYPE_PKT_POSTMATCH);
} 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)DetectVarStoreMatch(det_ctx, pe->capids[x],
(uint8_t *)str_ptr, capture_len,
DETECT_VAR_TYPE_FLOW_POSTMATCH);
}
}
+ PCRE2_SIZE *ov = pcre2_get_ovector_pointer(pe->parse_regex.match);
/* update offset for pcre RELATIVE */
det_ctx->buffer_offset = (ptr + ov[1]) - payload;
det_ctx->pcre_match_start_offset = (ptr + ov[0] + 1) - payload;
const char *regexstr, int *sm_list, char *capture_names,
size_t capture_names_size, bool negate, AppProto *alproto)
{
- int ec;
- const char *eb;
- int eo;
+ int en;
+ PCRE2_SIZE eo2;
int opts = 0;
DetectPcreData *pd = NULL;
char *op = NULL;
switch (*op) {
case 'A':
- opts |= PCRE_ANCHORED;
+ opts |= PCRE2_ANCHORED;
break;
case 'E':
- opts |= PCRE_DOLLAR_ENDONLY;
+ opts |= PCRE2_DOLLAR_ENDONLY;
break;
case 'G':
- opts |= PCRE_UNGREEDY;
+ opts |= PCRE2_UNGREEDY;
break;
case 'i':
- opts |= PCRE_CASELESS;
+ opts |= PCRE2_CASELESS;
pd->flags |= DETECT_PCRE_CASELESS;
break;
case 'm':
- opts |= PCRE_MULTILINE;
+ opts |= PCRE2_MULTILINE;
break;
case 's':
- opts |= PCRE_DOTALL;
+ opts |= PCRE2_DOTALL;
break;
case 'x':
- opts |= PCRE_EXTENDED;
+ opts |= PCRE2_EXTENDED;
break;
case 'O':
* PCRE will let us know.
*/
if (capture_names == NULL || strlen(capture_names) == 0)
- opts |= PCRE_NO_AUTO_CAPTURE;
-
- pd->parse_regex.regex = pcre_compile2(re, opts, &ec, &eb, &eo, NULL);
- if (pd->parse_regex.regex == NULL && ec == 15) { // reference to non-existent subpattern
- opts &= ~PCRE_NO_AUTO_CAPTURE;
- pd->parse_regex.regex = pcre_compile(re, opts, &eb, &eo, NULL);
+ opts |= PCRE2_NO_AUTO_CAPTURE;
+
+ pd->parse_regex.regex =
+ pcre2_compile((PCRE2_SPTR8)re, PCRE2_ZERO_TERMINATED, opts, &en, &eo2, NULL);
+ if (pd->parse_regex.regex == NULL && en == 115) { // reference to non-existent subpattern
+ opts &= ~PCRE2_NO_AUTO_CAPTURE;
+ pd->parse_regex.regex =
+ pcre2_compile((PCRE2_SPTR8)re, PCRE2_ZERO_TERMINATED, opts, &en, &eo2, NULL);
}
-
if (pd->parse_regex.regex == NULL) {
- SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed "
- "at offset %" PRId32 ": %s", regexstr, eo, eb);
+ PCRE2_UCHAR errbuffer[256];
+ pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
+ SCLogError(SC_ERR_PCRE_COMPILE,
+ "pcre2 compile of \"%s\" failed at "
+ "offset %d: %s",
+ regexstr, (int)eo2, errbuffer);
goto error;
}
- int options = 0;
-#ifdef PCRE_HAVE_JIT
- if (pcre_use_jit)
- options |= PCRE_STUDY_JIT_COMPILE;
-#endif
- pd->parse_regex.study = pcre_study(pd->parse_regex.regex, options, &eb);
- if(eb != NULL) {
- SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed : %s", eb);
- goto error;
+#ifdef PCRE2_HAVE_JIT
+ if (pcre2_use_jit) {
+ ret = pcre2_jit_compile(pd->parse_regex.regex, PCRE2_JIT_COMPLETE);
+ if (ret != 0) {
+ /* warning, so we won't print the sig after this. Adding
+ * file and line to the message so the admin can figure
+ * out what sig this is about */
+ SCLogDebug("PCRE2 JIT compiler does not support: %s. "
+ "Falling back to regular PCRE2 handling (%s:%d)",
+ regexstr, de_ctx->rule_file, de_ctx->rule_line);
+ }
}
+#endif /*PCRE2_HAVE_JIT*/
-#ifdef PCRE_HAVE_JIT
- int jit = 0;
- ret = pcre_fullinfo(pd->parse_regex.regex, pd->parse_regex.study, PCRE_INFO_JIT, &jit);
- if (ret != 0 || jit != 1) {
- /* warning, so we won't print the sig after this. Adding
- * file and line to the message so the admin can figure
- * out what sig this is about */
- SCLogDebug("PCRE JIT compiler does not support: %s. "
- "Falling back to regular PCRE handling (%s:%d)",
- regexstr, de_ctx->rule_file, de_ctx->rule_line);
+ pd->parse_regex.context = pcre2_match_context_create(NULL);
+ if (pd->parse_regex.context == NULL) {
+ SCLogError(SC_ERR_PCRE_COMPILE, "pcre2 could not create match context");
+ goto error;
}
+ pd->parse_regex.match = pcre2_match_data_create_from_pattern(pd->parse_regex.regex, NULL);
-#endif /*PCRE_HAVE_JIT*/
-
- if (pd->parse_regex.study == NULL)
- pd->parse_regex.study = (pcre_extra *) SCCalloc(1,sizeof(pcre_extra));
-
- if (pd->parse_regex.study) {
- if(pd->flags & DETECT_PCRE_MATCH_LIMIT) {
- if(pcre_match_limit >= -1) {
- pd->parse_regex.study->match_limit = pcre_match_limit;
- pd->parse_regex.study->flags |= PCRE_EXTRA_MATCH_LIMIT;
- }
-#ifndef NO_PCRE_MATCH_RLIMIT
- if(pcre_match_limit_recursion >= -1) {
- pd->parse_regex.study->match_limit_recursion = pcre_match_limit_recursion;
- pd->parse_regex.study->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
- }
-#endif /* NO_PCRE_MATCH_RLIMIT */
- } else {
- pd->parse_regex.study->match_limit = SC_MATCH_LIMIT_DEFAULT;
- pd->parse_regex.study->flags |= PCRE_EXTRA_MATCH_LIMIT;
-#ifndef NO_PCRE_MATCH_RLIMIT
- pd->parse_regex.study->match_limit_recursion = SC_MATCH_LIMIT_RECURSION_DEFAULT;
- pd->parse_regex.study->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
-#endif /* NO_PCRE_MATCH_RLIMIT */
+ if (pd->flags & DETECT_PCRE_MATCH_LIMIT) {
+ if (pcre_match_limit >= -1) {
+ pcre2_set_match_limit(pd->parse_regex.context, pcre_match_limit);
+ }
+ if (pcre_match_limit_recursion >= -1) {
+ // pcre2_set_depth_limit unsupported on ubuntu 16.04
+ pcre2_set_recursion_limit(pd->parse_regex.context, pcre_match_limit_recursion);
}
} else {
- goto error;
+ pcre2_set_match_limit(pd->parse_regex.context, SC_MATCH_LIMIT_DEFAULT);
+ pcre2_set_recursion_limit(pd->parse_regex.context, PCRE_EXTRA_MATCH_LIMIT_RECURSION);
}
return pd;
SCLogDebug("regexstr %s, pd %p", regexstr, pd);
- ret = pcre_fullinfo(pd->parse_regex.regex, pd->parse_regex.study, PCRE_INFO_CAPTURECOUNT, &capture_cnt);
+ ret = pcre2_pattern_info(pd->parse_regex.regex, PCRE2_INFO_CAPTURECOUNT, &capture_cnt);
SCLogDebug("ret %d capture_cnt %d", ret, capture_cnt);
if (ret == 0 && capture_cnt && strlen(capture_names) > 0)
{
return -1;
}
-#ifdef PCRE_HAVE_JIT_EXEC
-static void *DetectPcreThreadInit(void *data /*@unused@*/)
-{
- pcre_jit_stack *jit_stack = pcre_jit_stack_alloc(PCRE_JIT_MIN_STACK, PCRE_JIT_MAX_STACK);
-
- if (jit_stack == NULL) {
- SCLogWarning(SC_WARN_PCRE_JITSTACK, "Unable to allocate PCRE JIT stack; will continue without JIT stack");
- }
- SCLogDebug("Using jit_stack %p", jit_stack);
-
- return (void *)jit_stack;
-}
-
-static void DetectPcreThreadFree(void *ctx)
-{
- SCLogDebug("freeing jit_stack %p", ctx);
- if (ctx != NULL)
- pcre_jit_stack_free((pcre_jit_stack *)ctx);
-}
-
-#endif
static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, const char *regexstr)
{
SCEnter();
if (DetectPcreParseCapture(regexstr, de_ctx, pd, capture_names) < 0)
goto error;
-#ifdef PCRE_HAVE_JIT_EXEC
- /* Deliberately silent on failures. Not having a context id means
- * JIT will be bypassed */
- pd->thread_ctx_jit_stack_id = DetectRegisterThreadCtxFuncs(de_ctx, "pcre",
- DetectPcreThreadInit, (void *)pd,
- DetectPcreThreadFree, 1);
-#endif
-
int sm_list = -1;
if (s->init_data->list != DETECT_SM_LIST_NOTSET) {
if (parsed_sm_list != DETECT_SM_LIST_NOTSET && parsed_sm_list != s->init_data->list) {
return;
DetectPcreData *pd = (DetectPcreData *)ptr;
- DetectParseFreeRegex(&pd->parse_regex);
+ pcre2_code_free(pd->parse_regex.regex);
+ pcre2_match_context_free(pd->parse_regex.context);
+ pcre2_match_data_free(pd->parse_regex.match);
SCFree(pd);
return;