diff options
-rw-r--r-- | net/snort/Makefile | 6 | ||||
-rw-r--r-- | net/snort/patches/900-Convert-project-to-PCRE2.patch | 2114 |
2 files changed, 2117 insertions, 3 deletions
diff --git a/net/snort/Makefile b/net/snort/Makefile index f4ac02761..66a8806cf 100644 --- a/net/snort/Makefile +++ b/net/snort/Makefile @@ -31,7 +31,7 @@ define Package/snort SUBMENU:=Firewall SECTION:=net CATEGORY:=Network - DEPENDS:=+libdaq +libdnet +libnghttp2 +libopenssl +libpcap +libpcre +libpthread +libtirpc +libuuid +zlib @HAS_LUAJIT_ARCH +luajit +SNORT_LZMA:liblzma + DEPENDS:=+libdaq +libdnet +libnghttp2 +libopenssl +libpcap +libpcre2 +libpthread +libtirpc +libuuid +zlib @HAS_LUAJIT_ARCH +luajit +SNORT_LZMA:liblzma TITLE:=Lightweight Network Intrusion Detection System URL:=http://www.snort.org/ CONFLICTS:=snort3 @@ -57,8 +57,8 @@ CONFIGURE_ARGS += \ --with-dnet-libraries="$(STAGING_DIR)/usr/lib" \ --with-libpcap-includes="$(STAGING_DIR)/usr/include" \ --with-libpcap-libraries="$(STAGING_DIR)/usr/lib" \ - --with-libpcre-includes="$(STAGING_DIR)/usr/include" \ - --with-libpcre-libraries="$(STAGING_DIR)/usr/lib" \ + --with-libpcre2-includes="$(STAGING_DIR)/usr/include" \ + --with-libpcre2-libraries="$(STAGING_DIR)/usr/lib" \ --with-daq-includes="$(STAGING_DIR)/usr/include/daq2" \ --with-daq-libraries="$(STAGING_DIR)/usr/lib/daq2" \ --disable-static-daq diff --git a/net/snort/patches/900-Convert-project-to-PCRE2.patch b/net/snort/patches/900-Convert-project-to-PCRE2.patch new file mode 100644 index 000000000..4e01347af --- /dev/null +++ b/net/snort/patches/900-Convert-project-to-PCRE2.patch @@ -0,0 +1,2114 @@ +From 514af7b25f1f49d87963baf4fd057d9c85f518a7 Mon Sep 17 00:00:00 2001 +From: Christian Marangi <ansuelsmth@gmail.com> +Date: Sat, 4 Nov 2023 01:30:37 +0100 +Subject: [PATCH] Convert project to PCRE2 + +Convert project to PCRE2. Convert every example to PCRE2. + +Due to API changes examples needs to be updated accordingly with the new +struct and API. + +The API name were voluntary changes to make sure the user of plugins is +aware of the change and manually refresh the plugin with new code. + +Most of the time it's just PcreMatch to Pcre2Match and PCREInfo to +PCRE2Info and the relative options (that are 1:1 compared to PCRE +library). + +For complex case where ovector extraction is needed, refer to example +36733 where new way with match data is used. Follow comments there for +additional info. + +Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> +--- + config.h.in | 8 +- + configure.in | 67 ++++---- + src/detection-plugins/sp_pcre.c | 149 +++++++++--------- + src/detection-plugins/sp_pcre.h | 9 +- + src/dynamic-plugins/sf_convert_dynamic.c | 59 ++++--- + src/dynamic-plugins/sf_dynamic_engine.h | 32 ++-- + src/dynamic-plugins/sf_dynamic_plugins.c | 109 +++++++------ + src/dynamic-plugins/sf_engine/examples/3036.c | 8 +- + src/dynamic-plugins/sf_engine/examples/3052.c | 8 +- + src/dynamic-plugins/sf_engine/examples/3099.c | 8 +- + .../sf_engine/examples/36733.c | 40 +++-- + src/dynamic-plugins/sf_engine/examples/3682.c | 11 +- + .../sf_engine/examples/bug31842.c | 9 +- + .../sf_engine/examples/bug35218.c | 15 +- + .../sf_engine/examples/sid1902.c | 9 +- + .../sf_engine/examples/sid2389.c | 9 +- + .../sf_engine/examples/sid9999.c | 2 +- + .../sf_engine/examples/web-client_test.c | 18 +-- + .../sf_engine/sf_snort_detection_engine.c | 20 +-- + .../sf_engine/sf_snort_detection_engine.h | 2 +- + .../sf_engine/sf_snort_plugin_api.c | 10 +- + .../sf_engine/sf_snort_plugin_api.h | 39 +++-- + .../sf_engine/sf_snort_plugin_pcre.c | 132 ++++++++++------ + .../appid/luaDetectorApi.c | 63 +++++--- + src/dynamic-preprocessors/imap/snort_imap.h | 6 +- + src/dynamic-preprocessors/pop/snort_pop.h | 3 +- + src/dynamic-preprocessors/smtp/snort_smtp.h | 3 +- + src/snort.c | 3 - + src/snort.h | 1 - + src/util.c | 9 +- + 30 files changed, 497 insertions(+), 364 deletions(-) + mode change 100755 => 100644 src/dynamic-plugins/sf_engine/sf_snort_plugin_api.h + mode change 100755 => 100644 src/dynamic-plugins/sf_engine/sf_snort_plugin_pcre.c + +--- a/config.h.in ++++ b/config.h.in +@@ -133,8 +133,8 @@ + /* Define to 1 if you have the `pcap' library (-lpcap). */ + #undef HAVE_LIBPCAP + +-/* Define to 1 if you have the `pcre' library (-lpcre). */ +-#undef HAVE_LIBPCRE ++/* Define to 1 if you have the `pcre2' library (-lpcre2-8). */ ++#undef HAVE_LIBPCRE2 + + /* Define to 1 if you have the `pfring' library (-lpfring). */ + #undef HAVE_LIBPFRING +@@ -190,8 +190,8 @@ + /* Can output the library version. */ + #undef HAVE_PCAP_LIB_VERSION + +-/* Define to 1 if you have the <pcre.h> header file. */ +-#undef HAVE_PCRE_H ++/* Define to 1 if you have the <pcre2.h> header file. */ ++#undef HAVE_PCRE2_H + + /* Define to 1 if you have the <pfring.h> header file. */ + #undef HAVE_PFRING_H +--- a/configure.in ++++ b/configure.in +@@ -455,65 +455,70 @@ AC_DEFUN([FAIL_MESSAGE],[ + exit 1 + ]) + +-AC_ARG_WITH(libpcre_includes, +- [ --with-libpcre-includes=DIR libpcre include directory], +- [with_libpcre_includes="$withval"],[with_libpcre_includes="no"]) +- +-AC_ARG_WITH(libpcre_libraries, +- [ --with-libpcre-libraries=DIR libpcre library directory], +- [with_libpcre_libraries="$withval"],[with_libpcre_libraries="no"]) +- +-if test "x$with_libpcre_includes" != "xno"; then +- CPPFLAGS="${CPPFLAGS} -I${with_libpcre_includes}" +- ICONFIGFLAGS="${ICONFIGFLAGS} -I${with_libpcre_includes}" ++AC_ARG_WITH(libpcre2_includes, ++ [ --with-libpcre2-includes=DIR libpcre2 include directory], ++ [with_libpcre2_includes="$withval"],[with_libpcre2_includes="no"]) ++ ++AC_ARG_WITH(libpcre2_libraries, ++ [ --with-libpcre2-libraries=DIR libpcre2 library directory], ++ [with_libpcre2_libraries="$withval"],[with_libpcre2_libraries="no"]) ++ ++if test "x$with_libpcre2_includes" != "xno"; then ++ CPPFLAGS="${CPPFLAGS} -I${with_libpcre2_includes}" ++ ICONFIGFLAGS="${ICONFIGFLAGS} -I${with_libpcre2_includes}" + else +- CPPFLAGS="${CPPFLAGS} `pcre-config --cflags`" ++ CPPFLAGS="${CPPFLAGS} `pcre2-config --cflags`" + fi + +-if test "x$with_libpcre_libraries" != "xno"; then +- LDFLAGS="${LDFLAGS} -L${with_libpcre_libraries}" ++if test "x$with_libpcre2_libraries" != "xno"; then ++ LDFLAGS="${LDFLAGS} -L${with_libpcre2_libraries}" + else +- LDFLAGS="${LDFLAGS} `pcre-config --libs`" ++ LDFLAGS="${LDFLAGS} `pcre2-config --libs8`" + fi + +-# PCRE configuration (required) ++# PCRE2 configuration (required) + # Verify that we have the headers +-PCRE_H="" +-AC_CHECK_HEADERS(pcre.h,, PCRE_H="no") +-if test "x$PCRE_H" = "xno"; then ++PCRE2_H="" ++AC_CHECK_HEADERS(pcre2.h,, PCRE2_H="no",[#define PCRE2_CODE_UNIT_WIDTH 8]) ++if test "x$PCRE2_H" = "xno"; then + echo +- echo " ERROR! Libpcre header not found." ++ echo " ERROR! Libpcre2 header not found." + echo " Get it from http://www.pcre.org" + exit 1 + fi + + # Verify that we have the library +-PCRE_L="" +-pcre_version_six="" +-AC_CHECK_LIB(pcre, pcre_compile, ,PCRE_L="no") ++PCRE2_L="" ++pcre2_version_six="" ++AC_CHECK_LIB(pcre2-8, pcre2_compile_8, ,PCRE2_L="no") + if test "x$PCRE_L" = "xno"; then + echo +- echo " ERROR! Libpcre library not found." ++ echo " ERROR! Libpcre2 library not found." + echo " Get it from http://www.pcre.org" + echo + exit 1 + else +- AC_MSG_CHECKING(for libpcre version 6.0 or greater) +- AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pcre.h>]], [[ +- #if (PCRE_MAJOR < 6) ++ AC_MSG_CHECKING(for libpcre2 version 10.0 or greater) ++ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ ++ #define PCRE2_CODE_UNIT_WIDTH 8 ++ #include <pcre2.h> ++ ]], [[ ++ #if (PCRE2_MAJOR < 10) + #error "Version failure" + #else +- int a, b = 0, c = 0, d = 0; +- pcre *tmp = NULL; +- a = pcre_copy_named_substring(tmp, "", &b, c, "", "", d); ++ int a; ++ PCRE2_UCHAR b = { 0 }; ++ PCRE2_SIZE c; ++ pcre2_match_data *match_data = NULL; ++ a = pcre2_substring_copy_byname(match_data, (PCRE2_SPTR )"", &b, &c); + #endif +- ]])],[pcre_version_six="yes"],[pcre_version_six="no"]) ++ ]])],[pcre2_version_ten="yes"],[pcre2_version_ten="no"]) + fi + +-if test "x$pcre_version_six" != "xyes"; then ++if test "x$pcre2_version_ten" != "xyes"; then + AC_MSG_RESULT(no) + echo +- echo " ERROR! Libpcre library version >= 6.0 not found." ++ echo " ERROR! Libpcre2 library version >= 10.0 not found." + echo " Get it from http://www.pcre.org" + echo + exit 1 +--- a/src/detection-plugins/sp_pcre.c ++++ b/src/detection-plugins/sp_pcre.c +@@ -46,7 +46,8 @@ + + #include "sp_pcre.h" + +-#include <pcre.h> ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + + #include "snort.h" + #include "profiler.h" +@@ -60,7 +61,7 @@ extern PreprocStats ruleOTNEvalPerfStats + #include "detection_util.h" + + /* +- * we need to specify the vector length for our pcre_exec call. we only care ++ * we need to specify the vector length for our pcre2_match call. we only care + * about the first vector, which if the match is successful will include the + * offset to the end of the full pattern match. If we decide to store other + * matches, make *SURE* that this is a multiple of 3 as pcre requires it. +@@ -77,8 +78,8 @@ void PcreFree(void *d) + PcreData *data = (PcreData *)d; + + free(data->expression); +- free(data->re); +- free(data->pe); ++ pcre2_match_context_free(data->match_context); ++ pcre2_code_free(data->re); + free(data); + } + +@@ -161,7 +162,6 @@ void PcreDuplicatePcreData(void *src, Pc + pcre_dup->expression = pcre_src->expression; + pcre_dup->options = pcre_src->options; + pcre_dup->search_offset = 0; +- pcre_dup->pe = pcre_src->pe; + pcre_dup->re = pcre_src->re; + } + +@@ -197,7 +197,7 @@ static void Ovector_Init(struct _SnortCo + * configuraton, we won't pcre capture count again, so save the max. */ + static int s_ovector_max = 0; + +- /* The pcre_fullinfo() function can be used to find out how many ++ /* The pcre2_pattern_info() function can be used to find out how many + * capturing subpatterns there are in a compiled pattern. The + * smallest size for ovector that will allow for n captured + * substrings, in addition to the offsets of the substring matched +@@ -207,8 +207,6 @@ static void Ovector_Init(struct _SnortCo + + if (sc->pcre_ovector_size > s_ovector_max) + s_ovector_max = sc->pcre_ovector_size; +- +- sc->pcre_ovector = (int *) SnortAlloc(s_ovector_max*sizeof(int)); + } + + #if SNORT_RELOAD +@@ -218,12 +216,12 @@ static void Ovector_Reload(struct _Snort + } + #endif + +-void PcreCapture(struct _SnortConfig *sc, const void *code, const void *extra) ++void Pcre2Capture(struct _SnortConfig *sc, const void *code) + { + int tmp_ovector_size = 0; + +- pcre_fullinfo((const pcre *)code, (const pcre_extra *)extra, +- PCRE_INFO_CAPTURECOUNT, &tmp_ovector_size); ++ pcre2_pattern_info((const pcre2_code *)code, ++ PCRE2_INFO_CAPTURECOUNT, &tmp_ovector_size); + + if (tmp_ovector_size > sc->pcre_ovector_size) + sc->pcre_ovector_size = tmp_ovector_size; +@@ -268,10 +266,10 @@ void SnortPcreInit(struct _SnortConfig * + + if (pcre_data->expression) + free(pcre_data->expression); +- if (pcre_data->pe) +- free(pcre_data->pe); ++ if (pcre_data->match_context) ++ pcre2_match_context_free(pcre_data->match_context); + if (pcre_data->re) +- free(pcre_data->re); ++ pcre2_code_free(pcre_data->re); + + free(pcre_data); + pcre_data = pcre_dup; +@@ -305,11 +303,12 @@ static inline void ValidatePcreHttpConte + + void SnortPcreParse(struct _SnortConfig *sc, char *data, PcreData *pcre_data, OptTreeNode *otn) + { +- const char *error; ++ PCRE2_UCHAR error[128]; + char *re, *free_me; + char *opts; + char delimit = '/'; +- int erroffset; ++ int errorcode; ++ PCRE2_SIZE erroffset; + int compile_flags = 0; + unsigned http = 0; + +@@ -381,17 +380,17 @@ void SnortPcreParse(struct _SnortConfig + /* process any /regex/ismxR options */ + while(*opts != '\0') { + switch(*opts) { +- case 'i': compile_flags |= PCRE_CASELESS; break; +- case 's': compile_flags |= PCRE_DOTALL; break; +- case 'm': compile_flags |= PCRE_MULTILINE; break; +- case 'x': compile_flags |= PCRE_EXTENDED; break; ++ case 'i': compile_flags |= PCRE2_CASELESS; break; ++ case 's': compile_flags |= PCRE2_DOTALL; break; ++ case 'm': compile_flags |= PCRE2_MULTILINE; break; ++ case 'x': compile_flags |= PCRE2_EXTENDED; break; + + /* + * these are pcre specific... don't work with perl + */ +- case 'A': compile_flags |= PCRE_ANCHORED; break; +- case 'E': compile_flags |= PCRE_DOLLAR_ENDONLY; break; +- case 'G': compile_flags |= PCRE_UNGREEDY; break; ++ case 'A': compile_flags |= PCRE2_ANCHORED; break; ++ case 'E': compile_flags |= PCRE2_DOLLAR_ENDONLY; break; ++ case 'G': compile_flags |= PCRE2_UNGREEDY; break; + + /* + * these are snort specific don't work with pcre or perl +@@ -424,45 +423,37 @@ void SnortPcreParse(struct _SnortConfig + + /* now compile the re */ + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "pcre: compiling %s\n", re);); +- pcre_data->re = pcre_compile(re, compile_flags, &error, &erroffset, NULL); ++ pcre_data->re = pcre2_compile((PCRE2_SPTR)re, PCRE2_ZERO_TERMINATED, compile_flags, &errorcode, &erroffset, NULL); + + if(pcre_data->re == NULL) + { ++ pcre2_get_error_message(errorcode, error, 128); + FatalError("%s(%d) : pcre compile of \"%s\" failed at offset " +- "%d : %s\n", file_name, file_line, re, erroffset, error); ++ "%zu : %s\n", file_name, file_line, re, erroffset, error); + } + ++ /* now create match context */ ++ pcre_data->match_context = pcre2_match_context_create(NULL); ++ if(pcre_data->match_context == NULL) ++ { ++ FatalError("%s(%d) : failed to allocate memory for match context\n", ++ file_name, file_line); ++ } + + /* now study it... */ +- pcre_data->pe = pcre_study(pcre_data->re, 0, &error); ++ errorcode = pcre2_jit_compile(pcre_data->re, PCRE2_JIT_COMPLETE); + +- if (pcre_data->pe) ++ if (!errorcode) + { + if ((ScPcreMatchLimitNewConf(sc) != -1) && !(pcre_data->options & SNORT_OVERRIDE_MATCH_LIMIT)) + { +- if (pcre_data->pe->flags & PCRE_EXTRA_MATCH_LIMIT) +- { +- pcre_data->pe->match_limit = ScPcreMatchLimitNewConf(sc); +- } +- else +- { +- pcre_data->pe->flags |= PCRE_EXTRA_MATCH_LIMIT; +- pcre_data->pe->match_limit = ScPcreMatchLimitNewConf(sc); +- } ++ pcre2_set_match_limit(pcre_data->match_context, ScPcreMatchLimitNewConf(sc)); + } + + #ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION + if ((ScPcreMatchLimitRecursionNewConf(sc) != -1) && !(pcre_data->options & SNORT_OVERRIDE_MATCH_LIMIT)) + { +- if (pcre_data->pe->flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION) +- { +- pcre_data->pe->match_limit_recursion = ScPcreMatchLimitRecursionNewConf(sc); +- } +- else +- { +- pcre_data->pe->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; +- pcre_data->pe->match_limit_recursion = ScPcreMatchLimitRecursionNewConf(sc); +- } ++ pcre2_set_depth_limit(pcre_data->match_context, ScPcreMatchLimitRecursionNewConf(sc)); + } + #endif + } +@@ -471,30 +462,28 @@ void SnortPcreParse(struct _SnortConfig + if (!(pcre_data->options & SNORT_OVERRIDE_MATCH_LIMIT) && + ((ScPcreMatchLimitNewConf(sc) != -1) || (ScPcreMatchLimitRecursionNewConf(sc) != -1))) + { +- pcre_data->pe = (pcre_extra *)SnortAlloc(sizeof(pcre_extra)); + if (ScPcreMatchLimitNewConf(sc) != -1) + { +- pcre_data->pe->flags |= PCRE_EXTRA_MATCH_LIMIT; +- pcre_data->pe->match_limit = ScPcreMatchLimitNewConf(sc); ++ pcre2_set_match_limit(pcre_data->match_context, ScPcreMatchLimitNewConf(sc)); + } + + #ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION + if (ScPcreMatchLimitRecursionNewConf(sc) != -1) + { +- pcre_data->pe->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; +- pcre_data->pe->match_limit_recursion = ScPcreMatchLimitRecursionNewConf(sc); ++ pcre2_set_depth_limit(pcre_data->match_context, ScPcreMatchLimitRecursionNewConf(sc)); + } + #endif + } + } + +- if(error != NULL) ++ if(errorcode) + { ++ pcre2_get_error_message(errorcode, error, 128); + FatalError("%s(%d) : pcre study failed : %s\n", file_name, + file_line, error); + } + +- PcreCapture(sc, pcre_data->re, pcre_data->pe); ++ Pcre2Capture(sc, pcre_data->re); + + PcreCheckAnchored(pcre_data); + +@@ -515,13 +504,13 @@ void PcreCheckAnchored(PcreData *pcre_da + int rc; + unsigned long int options = 0; + +- if ((pcre_data == NULL) || (pcre_data->re == NULL) || (pcre_data->pe == NULL)) ++ if ((pcre_data == NULL) || (pcre_data->re == NULL) || (pcre_data->match_context == NULL)) + return; + +- rc = pcre_fullinfo(pcre_data->re, pcre_data->pe, PCRE_INFO_OPTIONS, (void *)&options); ++ rc = pcre2_pattern_info(pcre_data->re, PCRE2_INFO_ARGOPTIONS, (void *)&options); + switch (rc) + { +- /* pcre_fullinfo fails for the following: ++ /* pcre2_pattern_info fails for the following: + * PCRE_ERROR_NULL - the argument code was NULL + * the argument where was NULL + * PCRE_ERROR_BADMAGIC - the "magic number" was not found +@@ -533,24 +522,24 @@ void PcreCheckAnchored(PcreData *pcre_da + /* This is the success code */ + break; + +- case PCRE_ERROR_NULL: +- FatalError("%s(%d) pcre_fullinfo: code and/or where were NULL.\n", ++ case PCRE2_ERROR_NULL: ++ FatalError("%s(%d) pcre2_pattern_info: code and/or where were NULL.\n", + __FILE__, __LINE__); + +- case PCRE_ERROR_BADMAGIC: +- FatalError("%s(%d) pcre_fullinfo: compiled code didn't have " ++ case PCRE2_ERROR_BADMAGIC: ++ FatalError("%s(%d) pcre2_pattern_info: compiled code didn't have " + "correct magic.\n", __FILE__, __LINE__); + +- case PCRE_ERROR_BADOPTION: +- FatalError("%s(%d) pcre_fullinfo: option type is invalid.\n", ++ case PCRE2_ERROR_BADOPTION: ++ FatalError("%s(%d) pcre2_pattern_info: option type is invalid.\n", + __FILE__, __LINE__); + + default: +- FatalError("%s(%d) pcre_fullinfo: Unknown error code.\n", ++ FatalError("%s(%d) pcre2_pattern_info: Unknown error code.\n", + __FILE__, __LINE__); + } + +- if ((options & PCRE_ANCHORED) && !(options & PCRE_MULTILINE)) ++ if ((options & PCRE2_ANCHORED) && !(options & PCRE2_MULTILINE)) + { + /* This means that this pcre rule option shouldn't be reevaluted + * even if any of it's relative children should fail to match. +@@ -579,6 +568,8 @@ static int pcre_search(const PcreData *p + int start_offset, + int *found_offset) + { ++ pcre2_match_data *match_data; ++ PCRE2_SIZE *ovector; + int matched; + int result; + +@@ -596,14 +587,19 @@ static int pcre_search(const PcreData *p + + *found_offset = -1; + +- result = pcre_exec(pcre_data->re, /* result of pcre_compile() */ +- pcre_data->pe, /* result of pcre_study() */ +- buf, /* the subject string */ +- len, /* the length of the subject string */ +- start_offset, /* start at offset 0 in the subject */ +- 0, /* options(handled at compile time */ +- snort_conf->pcre_ovector, /* vector for substring information */ +- snort_conf->pcre_ovector_size);/* number of elements in the vector */ ++ match_data = pcre2_match_data_create(snort_conf->pcre_ovector_size, NULL); ++ if (!match_data) { ++ DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "pcre2_match_data_create failed to alloc mem!\n");); ++ return 0; ++ } ++ ++ result = pcre2_match(pcre_data->re, /* result of pcre2_compile() */ ++ (PCRE2_SPTR)buf, /* the subject string */ ++ (PCRE2_SIZE)len, /* the length of the subject string */ ++ (PCRE2_SIZE)start_offset, /* start at offset 0 in the subject */ ++ 0, /* options(handled at compile time */ ++ match_data, /* match data for results */ ++ pcre_data->match_context); /* match context for JIT limits */ + + if(result >= 0) + { +@@ -615,23 +611,25 @@ static int pcre_search(const PcreData *p + * second is set to the offset of the first character after the end of a substring. The first pair, + * ovector[0] and ovector[1], identify the portion of the subject string matched by the entire pattern. + * The next pair is used for the first capturing subpattern, and so on. The value returned by +- * pcre_exec() is the number of pairs that have been set. If there are no capturing subpatterns, the ++ * pcre_match() is the number of pairs that have been set. If there are no capturing subpatterns, the + * return value from a successful match is 1, indicating that just the first pair of offsets has been set. + * + * In Snort's case, the ovector size only allows for the first pair and a single int for scratch space. + */ +- *found_offset = snort_conf->pcre_ovector[1]; ++ ovector = pcre2_get_ovector_pointer(match_data); ++ *found_offset = ovector[1]; + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, + "Setting Doe_ptr and found_offset: %p %d\n", + doe_ptr, found_offset);); + } +- else if(result == PCRE_ERROR_NOMATCH) ++ else if(result == PCRE2_ERROR_NOMATCH) + { + matched = 0; + } + else + { +- DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "pcre_exec error : %d \n", result);); ++ pcre2_match_data_free(match_data); ++ DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "pcre2_match error : %d \n", result);); + return 0; + } + +@@ -641,6 +639,7 @@ static int pcre_search(const PcreData *p + matched = !matched; + } + ++ pcre2_match_data_free(match_data); + return matched; + } + +--- a/src/detection-plugins/sp_pcre.h ++++ b/src/detection-plugins/sp_pcre.h +@@ -49,17 +49,18 @@ + + void SetupPcre(void); + +-#include <pcre.h> ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + typedef struct _PcreData + { +- pcre *re; /* compiled regex */ +- pcre_extra *pe; /* studied regex foo */ ++ pcre2_code *re; /* compiled regex */ ++ pcre2_match_context *match_context; /* regex match context */ + int options; /* sp_pcre specfic options (relative & inverse) */ + char *expression; + uint32_t search_offset; + } PcreData; + +-void PcreCapture(struct _SnortConfig *sc, const void *code, const void *extra); ++void Pcre2Capture(struct _SnortConfig *sc, const void *code); + void PcreFree(void *d); + uint32_t PcreHash(void *d); + int PcreCompare(void *l, void *r); +--- a/src/dynamic-plugins/sf_convert_dynamic.c ++++ b/src/dynamic-plugins/sf_convert_dynamic.c +@@ -52,9 +52,11 @@ + + extern void ParsePattern(char *, OptTreeNode *, int); + extern void ParseProtectedPattern(char *, OptTreeNode *, int); +-extern void *pcreCompile(const char *pattern, int options, const char **errptr, +- int *erroffset, const unsigned char *tableptr); +-extern void *pcreStudy(struct _SnortConfig *sc, const void *code, int options, const char **errptr); ++extern void *pcre2MatchContextCreate(const void *gcontext); ++extern void *pcre2Compile(const char *pattern, int options, int *errorcode, size_t *erroffset, void *matchcontext); ++extern int pcre2JITCompile(struct _SnortConfig *sc, const void *code, const void *matchcontext, int options); ++extern void pcre2MatchContextFree(const void *match_context); ++extern void pcre2CodeFree(const void *code); + + extern int SnortPcre(void *option_data, Packet *p); + extern int FlowBitsCheck(void *option_data, Packet *p); +@@ -517,20 +519,20 @@ static int ConvertProtectedContentOption + static int ConvertPcreOption(SnortConfig *sc, Rule *rule, int index, OptTreeNode *otn) + { + PcreData *pcre_data = (PcreData *) SnortAlloc(sizeof(PcreData)); +- PCREInfo *pcre_info = rule->options[index]->option_u.pcre; ++ PCRE2Info *pcre2_info = rule->options[index]->option_u.pcre2; + OptFpList *fpl; + void *pcre_dup; +- const char *error; +- int erroroffset; ++ int errorcode; ++ size_t erroroffset; + + /* Need to recompile the expression so double free doesn't occur + * during reload */ + + /* Compile & Study PCRE */ +- pcre_data->re = pcreCompile( +- pcre_info->expr, +- pcre_info->compile_flags, +- &error, ++ pcre_data->re = pcre2Compile( ++ pcre2_info->expr, ++ pcre2_info->compile_flags, ++ &errorcode, + &erroroffset, + NULL + ); +@@ -541,37 +543,46 @@ static int ConvertPcreOption(SnortConfig + return -1; + } + +- pcre_data->pe = pcreStudy(sc, ++ pcre_data->match_context = pcre2MatchContextCreate(NULL); ++ if (pcre_data->match_context == NULL) { ++ pcre2CodeFree(pcre_data->re); ++ free(pcre_data); ++ return -1; ++ } ++ ++ errorcode = pcre2JITCompile( ++ sc, + pcre_data->re, +- pcre_info->compile_flags, +- &error ++ pcre_data->match_context, ++ pcre2_info->compile_flags + ); + +- if (error) ++ if (errorcode) + { +- free(pcre_data->re); ++ pcre2MatchContextFree(pcre_data->match_context); ++ pcre2CodeFree(pcre_data->re); + free(pcre_data); + return -1; + } + + /* Copy to struct used for normal PCRE rules */ +- pcre_data->expression = SnortStrdup(pcre_info->expr); ++ pcre_data->expression = SnortStrdup(pcre2_info->expr); + + /* Option values differ between PCREInfo and PcreData, + * so a straight copy of the options variable won't work. */ +- if (pcre_info->flags & CONTENT_RELATIVE) ++ if (pcre2_info->flags & CONTENT_RELATIVE) + pcre_data->options |= SNORT_PCRE_RELATIVE; + +- if (pcre_info->flags & NOT_FLAG) ++ if (pcre2_info->flags & NOT_FLAG) + pcre_data->options |= SNORT_PCRE_INVERT; + +- if (pcre_info->flags & CONTENT_BUF_RAW) ++ if (pcre2_info->flags & CONTENT_BUF_RAW) + pcre_data->options |= SNORT_PCRE_RAWBYTES; + +- if (pcre_info->flags & CONTENT_BUF_NORMALIZED) ++ if (pcre2_info->flags & CONTENT_BUF_NORMALIZED) + pcre_data->options &= ~SNORT_PCRE_RAWBYTES; + +- pcre_data->options |= HTTP_CONTENT(pcre_info->flags); ++ pcre_data->options |= HTTP_CONTENT(pcre2_info->flags); + + PcreCheckAnchored(pcre_data); + +@@ -584,10 +595,10 @@ static int ConvertPcreOption(SnortConfig + { + if (pcre_data->expression) + free(pcre_data->expression); +- if (pcre_data->pe) +- free(pcre_data->pe); ++ if (pcre_data->match_context) ++ pcre2MatchContextFree(pcre_data->match_context); + if (pcre_data->re) +- free(pcre_data->re); ++ pcre2CodeFree(pcre_data->re); + + free(pcre_data); + pcre_data = pcre_dup; +--- a/src/dynamic-plugins/sf_dynamic_engine.h ++++ b/src/dynamic-plugins/sf_dynamic_engine.h +@@ -139,11 +139,18 @@ typedef int (*DynamicDecompressFunc)(voi + + #define ENGINE_DATA_VERSION 10 + +-typedef void *(*PCRECompileFunc)(const char *, int, const char **, int *, const unsigned char *); +-typedef void *(*PCREStudyFunc)(struct _SnortConfig *, const void *, int, const char **); +-typedef int (*PCREExecFunc)(const void *, const void *, const char *, int, int, int, int *, int); +-typedef void (*PCRECapture)(struct _SnortConfig *, const void *, const void *); +-typedef void(*PCREOvectorInfo)(int **, int *); ++typedef void *(*PCRE2CompileFunc)(const char *, int, int *, size_t *, void *); ++typedef void *(*PCRE2MatchContextCreate)(const void *); ++typedef int (*PCRE2JITCompileFunc)(struct _SnortConfig *, const void *, const void *, int); ++typedef int (*PCRE2OvectorSizeFunc)(void); ++typedef void *(*PCRE2MatchDataCreateFunc)(int, const void *); ++typedef unsigned int (*PCRE2GetOvectorCountFunc)(const void *); ++typedef void *(*PCRE2GetOvectorPointerFunc)(const void *); ++typedef int (*PCRE2MatchRealFunc)(const void *, const char *, int, int, int, const void *, const void *); ++typedef void (*PCRE2MatchDataFreeFunc)(const void *); ++typedef void (*PCRE2MatchContextFreeFunc)(const void *); ++typedef void (*PCRE2CodeFreeFunc)(const void *); ++typedef void (*PCRE2Capture)(struct _SnortConfig *, const void *); + + typedef struct _DynamicEngineData + { +@@ -175,9 +182,15 @@ typedef struct _DynamicEngineData + char **debugMsgFile; + int *debugMsgLine; + +- PCRECompileFunc pcreCompile; +- PCREStudyFunc pcreStudy; +- PCREExecFunc pcreExec; ++ PCRE2CompileFunc pcre2Compile; ++ PCRE2MatchContextCreate pcre2MatchContextCreate; ++ PCRE2JITCompileFunc pcre2JITCompile; ++ PCRE2OvectorSizeFunc pcre2OvectorSize; ++ PCRE2MatchDataCreateFunc pcre2MatchDataCreate; ++ PCRE2GetOvectorCountFunc pcre2GetOvectorCount; ++ PCRE2GetOvectorPointerFunc pcre2GetOvectorPointer; ++ PCRE2MatchRealFunc pcre2MatchReal; ++ PCRE2MatchDataFreeFunc pcre2MatchDataFree; + SfUnfold sfUnfold; + SfBase64Decode sfbase64decode; + GetAltDetectFunc GetAltDetect; +@@ -190,8 +203,7 @@ typedef struct _DynamicEngineData + + UnregisterBit flowbitUnregister; + +- PCRECapture pcreCapture; +- PCREOvectorInfo pcreOvectorInfo; ++ PCRE2Capture pcre2Capture; + + GetHttpBufferFunc getHttpBuffer; + DynamicDecompressInitFunc decompressInit; +--- a/src/dynamic-plugins/sf_dynamic_plugins.c ++++ b/src/dynamic-plugins/sf_dynamic_plugins.c +@@ -92,7 +92,8 @@ typedef HANDLE PluginHandle; + #include "sf_iph.h" + #include "fpdetect.h" + #include "sfportobject.h" +-#include <pcre.h> ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + #include "parser.h" + #include "event_wrapper.h" + #include "util.h" +@@ -1250,46 +1251,35 @@ void DynamicGetRuleData(void *p, const R + } + } + +-void *pcreCompile(const char *pattern, int options, const char **errptr, int *erroffset, const unsigned char *tableptr) ++void *pcre2Compile(const char *pattern, int options, int *errorcode, size_t *erroffset, void *compilecontect) + { + options &= ~SNORT_PCRE_OVERRIDE_MATCH_LIMIT; +- return (void *)pcre_compile(pattern, options, errptr, erroffset, tableptr); ++ return (void *)pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, options, errorcode, (PCRE2_SIZE *)erroffset, (pcre2_compile_context *)compilecontect); + } + +-void *pcreStudy(struct _SnortConfig *sc, const void *code, int options, const char **errptr) ++void *pcre2MatchContextCreate(const void *generalcontext) ++{ ++ return (void *)pcre2_match_context_create((pcre2_general_context *)generalcontext); ++} ++ ++int pcre2JITCompile(struct _SnortConfig *sc, const void *code, const void *matchcontext, int options) + { +- pcre_extra *extra_extra; + int snort_options = options & SNORT_PCRE_OVERRIDE_MATCH_LIMIT; ++ int errorcode; + +- extra_extra = pcre_study((const pcre*)code, 0, errptr); ++ errorcode = pcre2_jit_compile((pcre2_code*)code, PCRE2_JIT_COMPLETE); + +- if (extra_extra) ++ if (errorcode) + { + if ((ScPcreMatchLimitNewConf(sc) != -1) && !(snort_options & SNORT_PCRE_OVERRIDE_MATCH_LIMIT)) + { +- if (extra_extra->flags & PCRE_EXTRA_MATCH_LIMIT) +- { +- extra_extra->match_limit = ScPcreMatchLimitNewConf(sc); +- } +- else +- { +- extra_extra->flags |= PCRE_EXTRA_MATCH_LIMIT; +- extra_extra->match_limit = ScPcreMatchLimitNewConf(sc); +- } ++ pcre2_set_match_limit((pcre2_match_context*)matchcontext, ScPcreMatchLimitNewConf(sc)); + } + + #ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION + if ((ScPcreMatchLimitRecursionNewConf(sc) != -1) && !(snort_options & SNORT_PCRE_OVERRIDE_MATCH_LIMIT)) + { +- if (extra_extra->flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION) +- { +- extra_extra->match_limit_recursion = ScPcreMatchLimitRecursionNewConf(sc); +- } +- else +- { +- extra_extra->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; +- extra_extra->match_limit_recursion = ScPcreMatchLimitRecursionNewConf(sc); +- } ++ pcre2_set_depth_limit((pcre2_match_context*)matchcontext, ScPcreMatchLimitRecursionNewConf(sc)); + } + #endif + } +@@ -1298,40 +1288,62 @@ void *pcreStudy(struct _SnortConfig *sc, + if (!(snort_options & SNORT_PCRE_OVERRIDE_MATCH_LIMIT) && + ((ScPcreMatchLimitNewConf(sc) != -1) || (ScPcreMatchLimitRecursionNewConf(sc) != -1))) + { +- extra_extra = (pcre_extra *)SnortAlloc(sizeof(pcre_extra)); + if (ScPcreMatchLimitNewConf(sc) != -1) + { +- extra_extra->flags |= PCRE_EXTRA_MATCH_LIMIT; +- extra_extra->match_limit = ScPcreMatchLimitNewConf(sc); ++ pcre2_set_match_limit((pcre2_match_context*)matchcontext, ScPcreMatchLimitNewConf(sc)); + } + + #ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION + if (ScPcreMatchLimitRecursionNewConf(sc) != -1) + { +- extra_extra->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; +- extra_extra->match_limit_recursion = ScPcreMatchLimitRecursionNewConf(sc); ++ pcre2_set_depth_limit((pcre2_match_context*)matchcontext, ScPcreMatchLimitRecursionNewConf(sc)); + } + #endif + } + } + +- return extra_extra; ++ return errorcode; ++} ++ ++int pcre2OvectorSize(void) ++{ ++ return snort_conf->pcre_ovector_size; ++} ++ ++void *pcre2MatchDataCreate(int size, const void *generalcontext) ++{ ++ return pcre2_match_data_create(size, (pcre2_general_context *)generalcontext); ++} ++ ++unsigned int pcre2GetOvectorCount(const void *match_data) ++{ ++ return pcre2_get_ovector_count((pcre2_match_data *)match_data); ++} ++ ++void *pcre2GetOvectorPointer(const void *match_data) ++{ ++ return pcre2_get_ovector_pointer((pcre2_match_data *)match_data); ++} ++ ++int pcre2MatchReal(const void *code, const char *subj, ++ int len, int start, int options, const void *matchdata, const void *matchcontext) ++{ ++ return pcre2_match((const pcre2_code *)code, (PCRE2_SPTR)subj, len, start, options, (pcre2_match_data *)matchdata, (pcre2_match_context *)matchcontext); ++} ++ ++void pcre2MatchDataFree(const void *match_data) ++{ ++ pcre2_match_data_free((pcre2_match_data *)match_data); + } + +-/* pcreOvectorInfo +- * +- * Get the Ovector configuration for PCRE from the snort.conf +- */ +-void pcreOvectorInfo(int **ovector, int *ovector_size) ++void pcre2MatchContextFree(const void *code) + { +- *ovector = snort_conf->pcre_ovector; +- *ovector_size = snort_conf->pcre_ovector_size; ++ pcre2_match_context_free((pcre2_match_context *)code); + } + +-int pcreExec(const void *code, const void *extra, const char *subj, +- int len, int start, int options, int *ovec, int ovecsize) ++void pcre2CodeFree(const void *code) + { +- return pcre_exec((const pcre *)code, (const pcre_extra *)extra, subj, len, start, options, ovec, ovecsize); ++ pcre2_code_free((pcre2_code *)code); + } + + static int setFlowId(const void* p, uint32_t id) +@@ -1415,17 +1427,22 @@ int InitDynamicEngines(char *dynamic_rul + engineData.debugMsgLine = &no_line; + #endif + +- engineData.pcreStudy = &pcreStudy; +- engineData.pcreCompile = &pcreCompile; +- engineData.pcreExec = &pcreExec; ++ engineData.pcre2JITCompile = &pcre2JITCompile; ++ engineData.pcre2MatchContextCreate = &pcre2MatchContextCreate; ++ engineData.pcre2Compile = &pcre2Compile; ++ engineData.pcre2OvectorSize = &pcre2OvectorSize; ++ engineData.pcre2MatchDataCreate = &pcre2MatchDataCreate; ++ engineData.pcre2GetOvectorCount = &pcre2GetOvectorCount; ++ engineData.pcre2GetOvectorPointer = &pcre2GetOvectorPointer; ++ engineData.pcre2MatchReal = &pcre2MatchReal; ++ engineData.pcre2MatchDataFree = &pcre2MatchDataFree; + + engineData.allocRuleData = &DynamicRuleDataAlloc; + engineData.freeRuleData = &DynamicRuleDataFree; + + engineData.flowbitUnregister = &DynamicFlowbitUnregister; + +- engineData.pcreCapture = &PcreCapture; +- engineData.pcreOvectorInfo = &pcreOvectorInfo; ++ engineData.pcre2Capture = &Pcre2Capture; + engineData.getHttpBuffer = getHttpBuffer; + + engineData.decompressInit = &DynamicDecompressInit; +--- a/src/dynamic-plugins/sf_engine/examples/3036.c ++++ b/src/dynamic-plugins/sf_engine/examples/3036.c +@@ -104,7 +104,7 @@ static RuleOption rule3036option3 = + { &rule3036byte_test3 } + }; + // pcre:"^.{27}", relative; +-static PCREInfo rule3036pcre4 = ++static PCRE2Info rule3036pcre4 = + { + "^.{27}", /* pattern */ + NULL, /* holder for compiled pattern */ +@@ -166,7 +166,7 @@ static RuleOption rule3036option6 = + { &rule3036byte_jump6 } + }; + // pcre:"^.{4}", relative; +-static PCREInfo rule3036pcre7 = ++static PCRE2Info rule3036pcre7 = + { + "^.{4}", /* pattern */ + NULL, /* holder for compiled pattern */ +@@ -325,13 +325,13 @@ int rule3036eval(void *p) { + // byte_test:size 1, value 128, operator &, offset 6, relative; + if (byteTest(p, rule3036options[3]->option_u.byte, cursor_normal) > 0) { + // pcre:"^.{27}", relative; +- if (pcreMatch(p, rule3036options[4]->option_u.pcre, &cursor_normal)) { ++ if (pcre2Match(p, rule3036options[4]->option_u.pcre2, &cursor_normal)) { + // content:"|01 00|", offset 37, depth 2, relative; + if (contentMatch(p, rule3036options[5]->option_u.content, &cursor_normal) > 0) { + // byte_jump:size 4, offset -7, relative, endian little; + if (byteJump(p, rule3036options[6]->option_u.byte, &cursor_normal) > 0) { + // pcre:"^.{4}", relative; +- if (pcreMatch(p, rule3036options[7]->option_u.pcre, &cursor_normal)) { ++ if (pcre2Match(p, rule3036options[7]->option_u.pcre2, &cursor_normal)) { + // content:"|00 00 00 00|", offset 16, depth 4, relative; + if (!(contentMatch(p, rule3036options[8]->option_u.content, &cursor_normal) > 0)) { + // byte_jump:size 4, offset 16, relative, endian little; +--- a/src/dynamic-plugins/sf_engine/examples/3052.c ++++ b/src/dynamic-plugins/sf_engine/examples/3052.c +@@ -93,7 +93,7 @@ static RuleOption rule3052option2 = + { &rule3052byte_test2 } + }; + // pcre:"^.{27}", relative; +-static PCREInfo rule3052pcre3 = ++static PCRE2Info rule3052pcre3 = + { + "^.{27}", /* pattern */ + NULL, /* holder for compiled pattern */ +@@ -155,7 +155,7 @@ static RuleOption rule3052option5 = + { &rule3052byte_jump5 } + }; + // pcre:"^.{4}", relative; +-static PCREInfo rule3052pcre6 = ++static PCRE2Info rule3052pcre6 = + { + "^.{4}", /* pattern */ + NULL, /* holder for compiled pattern */ +@@ -307,13 +307,13 @@ int rule3052eval(void *p) { + // byte_test:size 1, value 128, operator &, offset 6, relative; + if (byteTest(p, rule3052options[2]->option_u.byte, cursor_normal) > 0) { + // pcre:"^.{27}", relative; +- if (pcreMatch(p, rule3052options[3]->option_u.pcre, &cursor_normal)) { ++ if (pcre2Match(p, rule3052options[3]->option_u.pcre2, &cursor_normal)) { + // content:"|01 00|", offset 37, depth 2, relative; + if (contentMatch(p, rule3052options[4]->option_u.content, &cursor_normal) > 0) { + // byte_jump:size 4, offset -7, relative, endian little; + if (byteJump(p, rule3052options[5]->option_u.byte, &cursor_normal) > 0) { + // pcre:"^.{4}", relative; +- if (pcreMatch(p, rule3052options[6]->option_u.pcre, &cursor_normal)) { ++ if (pcre2Match(p, rule3052options[6]->option_u.pcre2, &cursor_normal)) { + // content:"|00 00 00 00|", offset 16, depth 4, relative; + if (!(contentMatch(p, rule3052options[7]->option_u.content, &cursor_normal) > 0)) { + // byte_jump:size 4, offset 16, relative, endian little; +--- a/src/dynamic-plugins/sf_engine/examples/3099.c ++++ b/src/dynamic-plugins/sf_engine/examples/3099.c +@@ -104,7 +104,7 @@ static RuleOption rule3099option3 = + { &rule3099byte_test3 } + }; + // pcre:"^.{27}", relative; +-static PCREInfo rule3099pcre4 = ++static PCRE2Info rule3099pcre4 = + { + "^.{27}", /* pattern */ + NULL, /* holder for compiled pattern */ +@@ -191,7 +191,7 @@ static RuleOption rule3099option7 = + { &rule3099byte_jump7 } + }; + // pcre:"^.{4}", relative; +-static PCREInfo rule3099pcre8 = ++static PCRE2Info rule3099pcre8 = + { + "^.{4}", /* pattern */ + NULL, /* holder for compiled pattern */ +@@ -392,7 +392,7 @@ int rule3099eval(void *p) { + // byte_test:size 1, value 128, operator &, offset 6, relative; + if (!(byteTest(p, rule3099options[3]->option_u.byte, cursor_normal) > 0)) { + // pcre:"^.{27}", relative; +- if (pcreMatch(p, rule3099options[4]->option_u.pcre, &cursor_normal)) { ++ if (pcre2Match(p, rule3099options[4]->option_u.pcre2, &cursor_normal)) { + // content:"&|00|", offset 29, depth 2, relative; + if (contentMatch(p, rule3099options[5]->option_u.content, &cursor_normal) > 0) { + // content:"|5C|PIPE|5C 00|", offset 4, nocase, relative; +@@ -400,7 +400,7 @@ int rule3099eval(void *p) { + // byte_jump:size 2, offset -17, relative, endian little; + if (byteJump(p, rule3099options[7]->option_u.byte, &cursor_normal) > 0) { + // pcre:"^.{4}", relative; +- if (pcreMatch(p, rule3099options[8]->option_u.pcre, &cursor_normal)) { ++ if (pcre2Match(p, rule3099options[8]->option_u.pcre2, &cursor_normal)) { + // content:"|05|", depth 1, relative; + if (contentMatch(p, rule3099options[9]->option_u.content, &cursor_normal) > 0) { + // byte_test:size 1, value 16, operator &, offset 3, relative; +--- a/src/dynamic-plugins/sf_engine/examples/36733.c ++++ b/src/dynamic-plugins/sf_engine/examples/36733.c +@@ -25,7 +25,8 @@ + #include "config.h" + #endif + +-#include "pcre.h" ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + #include "sf_snort_plugin_api.h" + #include "sf_snort_packet.h" + #include "web-misc_base64_decode.h" +@@ -80,12 +81,12 @@ static RuleOption ruleAPACHEAUTHLDAPopti + }; + + // pcre:"/^Authorization:\s*Basic/mi"; +-static PCREInfo ruleAPACHEAUTHLDAPpcre0 = ++static PCRE2Info ruleAPACHEAUTHLDAPpcre0 = + { + "^Authorization:\\s*Basic\\s+", /* pattern (now in snort content format) */ + 0, /* compiled expression */ + 0, /* compiled extra */ +- PCRE_CASELESS | PCRE_MULTILINE, /* compile flags */ ++ PCRE2_CASELESS | PCRE2_MULTILINE, /* compile flags */ + CONTENT_BUF_NORMALIZED, /* flags */ // XXX - need to add CONTENT_FAST_PATTERN support + 0 /* offset */ + }; +@@ -99,7 +100,7 @@ static RuleOption ruleAPACHEAUTHLDAPopti + }; + + // pcre:"/%[0-9]*\.?[0-9]*[:formatspecifiers:]/"; +-static PCREInfo ruleAPACHEAUTHLDAPpcre1 = ++static PCRE2Info ruleAPACHEAUTHLDAPpcre1 = + { + // "%[-# +'I]*[0-9]*\\.?[0-9]*[qjzthdiouxefgcrslnp]", /* pattern (now in snort content format) */ // ZDNOTE + "%.+%.", /* regex. The above is technically more correct, but this is faster and good enough */ +@@ -191,7 +192,7 @@ static int ruleAPACHEAUTHLDAPeval(void * + + // manual pcre stuff + int result; +- int ovector[3]; // Needs to be a multiple of 3 ++ void *match_data; + + if(sp == NULL) + return RULE_NOMATCH; +@@ -221,7 +222,7 @@ static int ruleAPACHEAUTHLDAPeval(void * + //DEBUG_WRAP(printf("found content:\"Authorization:\" %p\n", cursor)); + + // pcre:"/^Authorization:\s*Basic\s+/mi" +- if(pcreMatch(p, ruleAPACHEAUTHLDAPoptions[2]->option_u.pcre, &cursor) <= 0) ++ if(pcre2Match(p, ruleAPACHEAUTHLDAPoptions[2]->option_u.pcre2, &cursor) <= 0) + return RULE_NOMATCH; + + //DEBUG_WRAP(printf("found pcre:\"/^Authorization:\\s*Basic\\s+/mi\" %p\n", cursor)); +@@ -238,14 +239,35 @@ static int ruleAPACHEAUTHLDAPeval(void * + + //DEBUG_WRAP(printf("Successfully base64 decoded (%s)(%d)\n", decodedbuf, decodedbytes)); + ++ match_data = pcre2MatchDataCreateWrapper(); ++ if (!match_data) ++ return RULE_NOMATCH; ++ + // Now run our regex on the base64 decoding to find an attack +- result = pcreExecWrapper(ruleAPACHEAUTHLDAPoptions[3]->option_u.pcre, ++ result = pcre2MatchWrapper(ruleAPACHEAUTHLDAPoptions[3]->option_u.pcre2, + (char *)decodedbuf, // subject string + decodedbytes, // subject length + 0, // start offset + 0, // options (handled at compile time) +- ovector, // ovector for storing result substrings +- sizeof(ovector)/sizeof(int)); // size of ovector ++ match_data); // size of ovector ++ ++ /* If ovector is required: ++ * 1. declare a size_t *ovector ++ * 2. after pcre2ExecWrapper... ++ * 3. ovector = pcre2GetOvectorPointer(match_data); ++ * 4. Use ovector as old implementation ++ * ++ * If required ovector_size: ++ * 1. declare a unsigned int ovector_size ++ * 2. after pcre2ExecWrapper... ++ * 3. ovector_size = pcre2GetOvectorCount(match_data); ++ * 4. User ovector_size as old implementation ++ * ++ * ALWAYS REMEMBER TO USE THE MATCH DATA CREATE AND FREE BEFORE ++ * EXEC WRAPPER ++ */ ++ ++ pcre2MatchDataFreeWrapper(match_data); + + //DEBUG_WRAP(printf("result = %d\n", result)); + +--- a/src/dynamic-plugins/sf_engine/examples/3682.c ++++ b/src/dynamic-plugins/sf_engine/examples/3682.c +@@ -9,7 +9,8 @@ + #include "config.h" + #endif + +-#include "pcre.h" ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + #include "sf_snort_plugin_api.h" + #include "sf_snort_packet.h" + #include "detection_lib_meta.h" +@@ -103,12 +104,12 @@ static RuleOption rule3682option3 = + + /* pcre for sid 3682 */ + //pcre:"/Content-Type\x3A\s+audio\/(x-wav|mpeg|x-midi)/i"; +-static PCREInfo rule3682pcre4 = ++static PCRE2Info rule3682pcre4 = + { + "Content-Type\\x3A\\s+audio\\/(x-wav|mpeg|x-midi)", /* expression */ + NULL, /* Holder for compiled expr */ + NULL, /* Holder for compiled expr extra flags */ +- PCRE_CASELESS, /* Compile Flags */ ++ PCRE2_CASELESS, /* Compile Flags */ + CONTENT_BUF_NORMALIZED, /* Flags */ + 0 /* offset */ + }; +@@ -148,12 +149,12 @@ static RuleOption rule3682option5 = + + /* pcre for sid 3682 */ + //pcre:"/filename=[\x22\x27]?.{1,221}\.(vbs|exe|scr|pif|bat)/i"; +-static PCREInfo rule3682pcre6 = ++static PCRE2Info rule3682pcre6 = + { + "filename=[\\x22\\x27]?.{1,221}\\.(vbs|exe|scr|pif|bat)", /* expression */ + NULL, /* Holder for compiled expr */ + NULL, /* Holder for compiled expr extra flags */ +- PCRE_CASELESS, /* Compile Flags */ ++ PCRE2_CASELESS, /* Compile Flags */ + CONTENT_BUF_NORMALIZED, /* Flags */ + 0 /* offset */ + }; +--- a/src/dynamic-plugins/sf_engine/examples/bug31842.c ++++ b/src/dynamic-plugins/sf_engine/examples/bug31842.c +@@ -25,7 +25,8 @@ + #include "config.h" + #endif + +-#include "pcre.h" ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + #include "sf_snort_plugin_api.h" + #include "sf_snort_packet.h" + +@@ -89,12 +90,12 @@ static RuleOption ruleSQUID_NTLM_AUTHopt + } + }; + +-static PCREInfo ruleSQUID_NTLM_AUTHpcre = ++static PCRE2Info ruleSQUID_NTLM_AUTHpcre = + { + "^Proxy-Authorization:\\s*NTLM\\s+", /* pattern to search for */ + NULL, /* holder for compiled pattern */ + NULL, /* holder for compiled pattern flags */ +- PCRE_CASELESS | PCRE_DOTALL | PCRE_MULTILINE, /* compile flags */ ++ PCRE2_CASELESS | PCRE2_DOTALL | PCRE2_MULTILINE, /* compile flags */ + CONTENT_BUF_NORMALIZED, /* content flags */ + 0 /* offset */ + }; +@@ -336,7 +337,7 @@ int ruleSQUID_NTLM_AUTHeval(void *p) { + } + + /* call pcre match */ +- if (pcreMatch(p, ruleSQUID_NTLM_AUTHoptions[2]->option_u.pcre, &cursor) <= 0) { ++ if (pcre2Match(p, ruleSQUID_NTLM_AUTHoptions[2]->option_u.pcre2, &cursor) <= 0) { + return RULE_NOMATCH; + } + +--- a/src/dynamic-plugins/sf_engine/examples/bug35218.c ++++ b/src/dynamic-plugins/sf_engine/examples/bug35218.c +@@ -26,7 +26,8 @@ + #include "config.h" + #endif + +-#include "pcre.h" ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + #include "sf_snort_plugin_api.h" + #include "sf_snort_packet.h" + +@@ -97,12 +98,12 @@ static RuleOption ruleEXCHANGE_BASE64_DE + } + }; + +-static PCREInfo ruleEXCHANGE_BASE64_DECODEpcre0 = ++static PCRE2Info ruleEXCHANGE_BASE64_DECODEpcre0 = + { + "^Content-Transfer-Encoding:\\s*base64\\s*$", /* pattern to search for */ + NULL, /* compiled_expr */ + 0, /* compiled_extra */ +- PCRE_CASELESS | PCRE_MULTILINE, /* compile_flags */ ++ PCRE2_CASELESS | PCRE2_MULTILINE, /* compile_flags */ + CONTENT_BUF_RAW, /* flags: must include a CONTENT_BUF_X */ + 0 /* offset */ + }; +@@ -119,12 +120,12 @@ static RuleOption ruleEXCHANGE_BASE64_DE + /* Second PCRE just like above but with CONTENT_RELATIVE so we can find + additional base64 sections if they exist. + */ +-static PCREInfo ruleEXCHANGE_BASE64_DECODEpcre1 = ++static PCRE2Info ruleEXCHANGE_BASE64_DECODEpcre1 = + { + "^Content-Transfer-Encoding:\\s*base64\\s*$", /* pattern to search for */ + NULL, /* compiled_expr */ + 0, /* compiled_extra */ +- PCRE_CASELESS | PCRE_MULTILINE, /* compile_flags */ ++ PCRE2_CASELESS | PCRE2_MULTILINE, /* compile_flags */ + CONTENT_BUF_RAW | CONTENT_RELATIVE, /* flags: must include a CONTENT_BUF_X */ + 0 /* offset */ + }; +@@ -214,7 +215,7 @@ int ruleEXCHANGE_BASE64_DECODEeval(void + } + + /* call pcre match */ +- if (pcreMatch(sp, ruleEXCHANGE_BASE64_DECODEoptions[2]->option_u.pcre, &cursor_normal) <= 0) { ++ if (pcre2Match(sp, ruleEXCHANGE_BASE64_DECODEoptions[2]->option_u.pcre2, &cursor_normal) <= 0) { + return RULE_NOMATCH; + } + +@@ -286,7 +287,7 @@ int ruleEXCHANGE_BASE64_DECODEeval(void + + } else { /* !in_base64_content */ + // Find the next base64 content the easy way +- if(pcreMatch(sp, ruleEXCHANGE_BASE64_DECODEoptions[3]->option_u.pcre, &cursor_normal) <= 0) ++ if(pcre2Match(sp, ruleEXCHANGE_BASE64_DECODEoptions[3]->option_u.pcre2, &cursor_normal) <= 0) + return RULE_NOMATCH; + + // Another base64 section was found, set up for another loop +--- a/src/dynamic-plugins/sf_engine/examples/sid1902.c ++++ b/src/dynamic-plugins/sf_engine/examples/sid1902.c +@@ -12,7 +12,8 @@ + #include "config.h" + #endif + +-#include "pcre.h" ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + #include "sf_snort_plugin_api.h" + #include "sf_snort_packet.h" + +@@ -59,12 +60,12 @@ static RuleOption rule1902option1 = + { &rule1902content1 } + }; + // pcre:"\sLSUB\s[^\n]*?\s\{", dotall, multiline, nocase; +-static PCREInfo rule1902pcre2 = ++static PCRE2Info rule1902pcre2 = + { + "\\sLSUB\\s[^\\n]*?\\s\\{", /* pattern */ + NULL, /* holder for compiled pattern */ + NULL, /* holder for compiled pattern flags */ +- PCRE_CASELESS|PCRE_DOTALL|PCRE_MULTILINE, /* compile flags */ ++ PCRE2_CASELESS|PCRE2_DOTALL|PCRE2_MULTILINE, /* compile flags */ + CONTENT_BUF_NORMALIZED, /* content flags */ + 0 /* offset */ + }; +@@ -177,7 +178,7 @@ int rule1902eval(void *p) { + // content:"LSUB", nocase; + if (contentMatch(p, rule1902options[1]->option_u.content, &cursor_normal) > 0) { + // pcre:"\sLSUB\s[^\n]*?\s\{", dotall, multiline, nocase; +- if (pcreMatch(p, rule1902options[2]->option_u.pcre, &cursor_normal)) { ++ if (pcre2Match(p, rule1902options[2]->option_u.pcre2, &cursor_normal)) { + // byte_test:size 5, value 256, operator >, relative, representation dec; + if (byteTest(p, rule1902options[3]->option_u.byte, cursor_normal) > 0) { + return RULE_MATCH; +--- a/src/dynamic-plugins/sf_engine/examples/sid2389.c ++++ b/src/dynamic-plugins/sf_engine/examples/sid2389.c +@@ -6,7 +6,8 @@ + #include "config.h" + #endif + +-#include "pcre.h" ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + #include "sf_snort_plugin_api.h" + #include "detection_lib_meta.h" + +@@ -113,12 +114,12 @@ static RuleOption option2 = + { &content1 } + }; + +-static PCREInfo pcre1 = ++static PCRE2Info pcre1 = + { /* PCRE */ + "^RNTO\\s[^\\n]{100}", /* expression */ + NULL, /* Holder for compiled expr */ + NULL, /* Holder for compiled expr extra flags */ +- PCRE_DOTALL | PCRE_MULTILINE | PCRE_CASELESS, /* Compile Flags */ ++ PCRE2_DOTALL | PCRE2_MULTILINE | PCRE2_CASELESS, /* Compile Flags */ + CONTENT_BUF_NORMALIZED, /* Flags */ + 0 /* offset */ + }; +@@ -178,7 +179,7 @@ int sid2389Eval(void *p) + if (contentMatch(p, sid2389.options[1]->option_u.content, &norm_cur)>0) + { + /* Not relative to norm cursor */ +- if (pcreMatch(p, sid2389.options[2]->option_u.pcre, NULL)) ++ if (pcre2Match(p, sid2389.options[2]->option_u.pcre2, NULL)) + { + return RULE_MATCH; + } +--- a/src/dynamic-plugins/sf_engine/examples/sid9999.c ++++ b/src/dynamic-plugins/sf_engine/examples/sid9999.c +@@ -159,7 +159,7 @@ static CursorInfo loopCursor = + /* these don't get structures... lets hope this works :) */ + /* pcre for sid 9999 */ + // pcre:"^[rbg]XYZ", relative; +-static PCREInfo rule9999pcre7 = ++static PCRE2Info rule9999pcre7 = + { + "^[rbg]XYZ", /* pattern */ + NULL, /* holder for compiled pattern */ +--- a/src/dynamic-plugins/sf_engine/examples/web-client_test.c ++++ b/src/dynamic-plugins/sf_engine/examples/web-client_test.c +@@ -85,12 +85,12 @@ static RuleOption rule64111option1 = + }; + + // pcre:"IIS 7\x2e5 Detailed Error - 404\x2e0 - Not Found", nocase; +-static PCREInfo rule64111pcre2 = ++static PCRE2Info rule64111pcre2 = + { + "IIS 7\\x2e5 Detailed Error - 404\\x2e0 - Not Found", /* pattern */ + NULL, /* holder for compiled pattern */ + NULL, /* holder for compiled pattern flags */ +- PCRE_CASELESS, /* compile flags */ ++ PCRE2_CASELESS, /* compile flags */ + CONTENT_BUF_NORMALIZED, /* content flags */ + 0 /* offset */ + }; +@@ -256,12 +256,12 @@ static RuleOption rule64222option2 = + }; + + // pcre:"SignUrl=[^\x26\s]*[\x22\x27\x28\x29\x3C\x3E]", payload uri, nocase; +-static PCREInfo rule64222pcre3 = ++static PCRE2Info rule64222pcre3 = + { + "SignUrl=[^\\x26\\s]*[\\x22\\x27\\x28\\x29\\x3C\\x3E]", /* pattern */ + NULL, /* holder for compiled pattern */ + NULL, /* holder for compiled pattern flags */ +- PCRE_CASELESS, /* compile flags */ ++ PCRE2_CASELESS, /* compile flags */ + CONTENT_BUF_URI, /* content flags */ + 0 /* offset */ + }; +@@ -428,12 +428,12 @@ static RuleOption rule64333option2 = + }; + + // pcre:"SignUrl=[^\\x26\\s]*[\\x22\\x27\\x28\\x29\\x3C\\x3E]", payload uri, nocase; +-static PCREInfo rule64333pcre3 = ++static PCRE2Info rule64333pcre3 = + { + "SignUrl=[^\\\\x26\\\\s]*[\\\\x22\\\\x27\\\\x28\\\\x29\\\\x3C\\\\x3E]", /* pattern */ + NULL, /* holder for compiled pattern */ + NULL, /* holder for compiled pattern flags */ +- PCRE_CASELESS, /* compile flags */ ++ PCRE2_CASELESS, /* compile flags */ + CONTENT_BUF_URI, /* content flags */ + 0 /* offset */ + }; +@@ -550,7 +550,7 @@ int rule64111eval(void *p) { + // content:"IIS 7.5 Detailed Error - 404.0 - Not Found", depth 0, nocase, fast_pattern; + if (contentMatch(p, rule64111options[1]->option_u.content, &cursor_normal) > 0) { + // pcre:"IIS 7\x2e5 Detailed Error - 404\x2e0 - Not Found", nocase; +- if (pcreMatch(p, rule64111options[2]->option_u.pcre, &cursor_normal)) { ++ if (pcre2Match(p, rule64111options[2]->option_u.pcre2, &cursor_normal)) { + return RULE_MATCH; + } + } +@@ -576,7 +576,7 @@ int rule64222eval(void *p) { + // content:"SignUrl=", payload http_uri, depth 0, nocase; + if (contentMatch(p, rule64222options[2]->option_u.content, &cursor_http_uri) > 0) { + // pcre:"SignUrl=[^\x26\s]*[\x22\x27\x28\x29\x3C\x3E]", payload uri, nocase; +- if (pcreMatch(p, rule64222options[3]->option_u.pcre, &cursor_uri)) { ++ if (pcre2Match(p, rule64222options[3]->option_u.pcre2, &cursor_uri)) { + return RULE_MATCH; + } + } +@@ -603,7 +603,7 @@ int rule64333eval(void *p) { + // content:"SignUrl=", payload http_uri, depth 0, nocase; + if (contentMatch(p, rule64333options[2]->option_u.content, &cursor_http_uri) > 0) { + // pcre:"SignUrl=[^\\x26\\s]*[\\x22\\x27\\x28\\x29\\x3C\\x3E]", payload uri, nocase; +- if (pcreMatch(p, rule64333options[3]->option_u.pcre, &cursor_uri)) { ++ if (pcre2Match(p, rule64333options[3]->option_u.pcre2, &cursor_uri)) { + return RULE_MATCH; + } + } +--- a/src/dynamic-plugins/sf_engine/sf_snort_detection_engine.c ++++ b/src/dynamic-plugins/sf_engine/sf_snort_detection_engine.c +@@ -899,11 +899,11 @@ int RegisterOneRule(struct _SnortConfig + break; + case OPTION_TYPE_PCRE: + { +- PCREInfo *pcre = option->option_u.pcre; ++ PCRE2Info *pcre2 = option->option_u.pcre2; + +- if (pcre->compiled_expr == NULL) ++ if (pcre2->compiled_expr == NULL) + { +- if (PCRESetup(sc, rule, pcre)) ++ if (PCRE2Setup(sc, rule, pcre2)) + { + rule->initialized = 0; + FreeOneRule(rule); +@@ -1120,18 +1120,18 @@ static void FreeOneRule(void *data) + + case OPTION_TYPE_PCRE: + { +- PCREInfo *pcre = option->option_u.pcre; ++ PCRE2Info *pcre2 = option->option_u.pcre2; + +- if (pcre->compiled_expr != NULL) ++ if (pcre2->match_context != NULL) + { +- free(pcre->compiled_expr); +- pcre->compiled_expr = NULL; ++ pcre2_match_context_free(pcre2->match_context); ++ pcre2->match_context = NULL; + } + +- if (pcre->compiled_extra != NULL) ++ if (pcre2->compiled_expr != NULL) + { +- free(pcre->compiled_extra); +- pcre->compiled_extra = NULL; ++ pcre2_code_free(pcre2->compiled_expr); ++ pcre2->compiled_expr = NULL; + } + } + +--- a/src/dynamic-plugins/sf_engine/sf_snort_detection_engine.h ++++ b/src/dynamic-plugins/sf_engine/sf_snort_detection_engine.h +@@ -30,7 +30,7 @@ + #define SF_SNORT_DETECTION_ENGINE__H + + int BoyerContentSetup(Rule *rule, ContentInfo *content); +-int PCRESetup(struct _SnortConfig *sc, Rule *rule, PCREInfo *pcreInfo); ++int PCRE2Setup(struct _SnortConfig *sc, Rule *rule, PCRE2Info *pcre2Info); + int ValidateHeaderCheck(Rule *rule, HdrOptCheck *optData); + void ContentSetup(void); + int ByteExtractInitialize(Rule *rule, ByteExtract *extractData); +--- a/src/dynamic-plugins/sf_engine/sf_snort_plugin_api.c ++++ b/src/dynamic-plugins/sf_engine/sf_snort_plugin_api.c +@@ -640,7 +640,7 @@ int isRelativeOption(RuleOption *option) + relative = option->option_u.content->flags & CONTENT_RELATIVE; + break; + case OPTION_TYPE_PCRE: +- relative = option->option_u.pcre->flags & CONTENT_RELATIVE; ++ relative = option->option_u.pcre2->flags & CONTENT_RELATIVE; + break; + case OPTION_TYPE_FLOWBIT: + /* Never relative */ +@@ -716,7 +716,7 @@ int ruleMatchInternal(SFSnortPacket *p, + int32_t origOffset = 0; + uint32_t origDepth = 0; + int continueLoop = 1; +- PCREInfo *thisPCREInfo = NULL; ++ PCRE2Info *thisPCREInfo = NULL; + + if (cursor) + startCursor = thisCursor = *cursor; +@@ -736,7 +736,7 @@ int ruleMatchInternal(SFSnortPacket *p, + origOffset = thisContentInfo->offset; + break; + case OPTION_TYPE_PCRE: +- thisPCREInfo = rule->options[optIndex]->option_u.pcre; ++ thisPCREInfo = rule->options[optIndex]->option_u.pcre2; + origFlags = thisPCREInfo->flags; + origOffset = thisPCREInfo->offset; + break; +@@ -760,8 +760,8 @@ int ruleMatchInternal(SFSnortPacket *p, + notFlag = rule->options[optIndex]->option_u.protectedContent->flags & NOT_FLAG; + break; + case OPTION_TYPE_PCRE: +- retVal = pcreMatch(p, rule->options[optIndex]->option_u.pcre, &thisCursor); +- notFlag = rule->options[optIndex]->option_u.pcre->flags & NOT_FLAG; ++ retVal = pcre2Match(p, rule->options[optIndex]->option_u.pcre2, &thisCursor); ++ notFlag = rule->options[optIndex]->option_u.pcre2->flags & NOT_FLAG; + break; + case OPTION_TYPE_FLOWBIT: + retVal = processFlowbits(p, rule->options[optIndex]->option_u.flowBit); +--- a/src/dynamic-plugins/sf_engine/sf_snort_plugin_api.h ++++ b/src/dynamic-plugins/sf_engine/sf_snort_plugin_api.h +@@ -30,7 +30,8 @@ + #ifndef SF_SNORT_PLUGIN_API_H_ + #define SF_SNORT_PLUGIN_API_H_ + +-#include "pcre.h" ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + #include "stdio.h" + + #ifndef WIN32 +@@ -211,26 +212,26 @@ typedef struct _CursorInfo + } CursorInfo; + + /* +-pcre.h provides flags: ++pcre2.h provides flags: + +-PCRE_CASELESS +-PCRE_MULTILINE +-PCRE_DOTALL +-PCRE_EXTENDED +-PCRE_ANCHORED +-PCRE_DOLLAR_ENDONLY +-PCRE_UNGREEDY ++PCRE2_CASELESS ++PCRE2_MULTILINE ++PCRE2_DOTALL ++PCRE2_EXTENDED ++PCRE2_ANCHORED ++PCRE2_DOLLAR_ENDONLY ++PCRE2_UNGREEDY + */ + +-typedef struct _PCREInfo ++typedef struct _PCRE2Info + { + char *expr; + void *compiled_expr; +- void *compiled_extra; ++ void *match_context; + uint32_t compile_flags; + uint32_t flags; /* must include a CONTENT_BUF_X */ + int32_t offset; +-} PCREInfo; ++} PCRE2Info; + + #define FLOWBIT_SET 0x01 + #define FLOWBIT_UNSET 0x02 +@@ -393,7 +394,7 @@ typedef struct _RuleOption + ContentInfo *content; + ProtectedContentInfo *protectedContent; + CursorInfo *cursor; +- PCREInfo *pcre; ++ PCRE2Info *pcre2; + FlowBitsInfo *flowBit; + ByteData *byte; + ByteExtract *byteExtract; +@@ -482,7 +483,7 @@ ENGINE_LINKAGE int byteTest(void *p, Byt + ENGINE_LINKAGE int byteMath(void *p, ByteData *byteData, const uint8_t *cursor); + /* Same as extractValue plus setCursor */ + ENGINE_LINKAGE int byteJump(void *p, ByteData *byteData, const uint8_t **cursor); +-ENGINE_LINKAGE int pcreMatch(void *p, PCREInfo* pcre, const uint8_t **cursor); ++ENGINE_LINKAGE int pcre2Match(void *p, PCRE2Info* pcre2, const uint8_t **cursor); + ENGINE_LINKAGE int detectAsn1(void *p, Asn1Context* asn1, const uint8_t *cursor); + ENGINE_LINKAGE int checkHdrOpt(void *p, HdrOptCheck *optData); + ENGINE_LINKAGE int loopEval(void *p, LoopInfo *loop, const uint8_t **cursor); +@@ -506,8 +507,12 @@ ENGINE_LINKAGE void detectFlagDisable(SF + ENGINE_LINKAGE int getAltDetect(uint8_t **bufPtr, uint16_t *altLenPtr); + ENGINE_LINKAGE void setAltDetect(uint8_t *buf, uint16_t altLen); + +-ENGINE_LINKAGE int pcreExecWrapper(const PCREInfo *pcre_info, const char *buf, int len, int start_offset, +- int options, int *ovector, int ovecsize); ++ENGINE_LINKAGE void *pcre2MatchDataCreateWrapper(void); ++ENGINE_LINKAGE void pcre2MatchDataFreeWrapper(void *match_data); ++ENGINE_LINKAGE int pcre2GetOvectorCountWrapper(void *match_data); ++ENGINE_LINKAGE void *pcre2GetOvectorPointerWrapper(void *match_data); ++ENGINE_LINKAGE int pcre2MatchWrapper(const PCRE2Info *pcre2_info, const char *buf, int len, int start_offset, ++ int options, const void *match_data); + + static inline int invertMatchResult(int retVal) + { +--- a/src/dynamic-plugins/sf_engine/sf_snort_plugin_pcre.c ++++ b/src/dynamic-plugins/sf_engine/sf_snort_plugin_pcre.c +@@ -25,13 +25,14 @@ + * Date: 5/2005 + * + * +- * PCRE operations for dynamic rule engine ++ * PCRE2 operations for dynamic rule engine + */ + #ifdef HAVE_CONFIG_H + #include "config.h" + #endif + +-#include "pcre.h" ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + #include "sf_types.h" + #include "snort_debug.h" + #include "sf_dynamic_define.h" +@@ -43,32 +44,38 @@ + /* Need access to the snort-isms that were passed to the engine */ + extern int checkCursorSimple(const uint8_t *cursor, int flags, const uint8_t *start, const uint8_t *end, int offset); + extern int checkCursorInternal(void *p, int flags, int offset, const uint8_t *cursor); +-static int pcreMatchInternal(void *, PCREInfo*, const uint8_t **); ++static int pcreMatchInternal(void *, PCRE2Info*, const uint8_t **); + +-int PCRESetup(struct _SnortConfig *sc, Rule *rule, PCREInfo *pcreInfo) ++int PCRE2Setup(struct _SnortConfig *sc, Rule *rule, PCRE2Info *pcre2Info) + { +- const char *error; +- int erroffset; ++ size_t erroffset; ++ int errorcode; + +- pcreInfo->compiled_expr = (void *)_ded.pcreCompile(pcreInfo->expr, +- pcreInfo->compile_flags, +- &error, ++ pcre2Info->compiled_expr = (void *)_ded.pcre2Compile(pcre2Info->expr, ++ pcre2Info->compile_flags, ++ &errorcode, + &erroffset, + NULL); + +- if (!pcreInfo->compiled_expr) ++ if (!pcre2Info->compiled_expr) + { + /* error doing compilation. */ +- _ded.errMsg("Failed to compile PCRE in dynamic rule [%d:%d]\n", ++ _ded.errMsg("Failed to compile PCRE2 in dynamic rule [%d:%d]\n", + rule->info.genID, rule->info.sigID); + return -1; + } +- else ++ ++ pcre2Info->match_context = _ded.pcre2MatchContextCreate(NULL); ++ if (!pcre2Info->match_context) + { +- pcreInfo->compiled_extra = (void *)_ded.pcreStudy(sc, pcreInfo->compiled_expr, pcreInfo->compile_flags, &error); ++ /* error doing match context */ ++ _ded.errMsg("Failed to allocate mem for PCRE2 match context [%d:%d]\n", ++ rule->info.genID, rule->info.sigID); ++ return -1; + } + +- if (error) ++ errorcode = _ded.pcre2JITCompile(sc, pcre2Info->compiled_expr, pcre2Info->match_context, pcre2Info->compile_flags); ++ if (errorcode) + { + /* error doing study. */ + _ded.errMsg("Failed to study PCRE in dynamic rule [%d:%d]\n", +@@ -76,51 +83,82 @@ int PCRESetup(struct _SnortConfig *sc, R + return -1; + } + +- _ded.pcreCapture(sc, pcreInfo->compiled_expr, pcreInfo->compiled_extra); ++ _ded.pcre2Capture(sc, pcre2Info->compiled_expr); + + + return 0; + } + + /** +- * * Wrapper for pcre_exec to expose ovector. ++ * * Wrapper for pcre2_match_data_create to run match_data. ++ * */ ++ENGINE_LINKAGE void *pcre2MatchDataCreateWrapper(void) ++{ ++ return _ded.pcre2MatchDataCreate(_ded.pcre2OvectorSize(), NULL); ++} ++ ++/** ++ * * Wrapper for pcre2_match_data_free to run match_data. ++ * */ ++ENGINE_LINKAGE void pcre2MatchDataFreeWrapper(void *match_data) ++{ ++ _ded.pcre2MatchDataFree(match_data); ++} ++ ++/** ++ * * Wrapper for pcre2_get_ovector_count to run match_data. ++ * */ ++ENGINE_LINKAGE int pcre2GetOvectorCountWrapper(void *match_data) ++{ ++ return _ded.pcre2GetOvectorCount(match_data); ++} ++ ++/** ++ * * Wrapper for pcre2_get_ovector_pointer to run match_data. + * */ +-ENGINE_LINKAGE int pcreExecWrapper(const PCREInfo *pcre_info, const char *buf, int len, int start_offset, +- int options, int *ovector, int ovecsize) ++ENGINE_LINKAGE void *pcre2GetOvectorPointerWrapper(void *match_data) ++{ ++ return _ded.pcre2GetOvectorPointer(match_data); ++} ++ ++/** ++ * * Wrapper for pcre2_match to run match_data. ++ * */ ++ENGINE_LINKAGE int pcre2ExecWrapper(const PCRE2Info *pcre2_info, const char *buf, int len, int start_offset, ++ int options, const void *match_data) + { + int result; + int matched; + +- if(pcre_info == NULL ++ if(pcre2_info == NULL + || buf == NULL + || len <= 0 + || start_offset < 0 + || start_offset >= len +- || ovector == NULL) ++ || match_data == NULL) + { + return 0; + } + +- result = _ded.pcreExec(pcre_info->compiled_expr, /* result of pcre_compile() */ +- pcre_info->compiled_extra, /* result of pcre_study() */ ++ result = _ded.pcre2MatchReal(pcre2_info->compiled_expr, /* result of pcre_compile() */ + buf, /* the subject string */ + len, /* the length of the subject string */ + start_offset, /* start at offset 0 in the subject */ + options, /* options(handled at compile time */ +- ovector, /* vector for substring information */ +- ovecsize); /* number of elements in the vector */ ++ match_data, /* match_data for results */ ++ pcre2_info->match_context); /* match_context for JIT limits */ + + if(result >= 0) + { + matched = 1; + } +- else if(result == PCRE_ERROR_NOMATCH) ++ else if(result == PCRE2_ERROR_NOMATCH) + { + matched = 0; + } + else + { +- DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "pcre_exec error : %d \n", result);); ++ DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "pcre_match error : %d \n", result);); + return 0; + } + +@@ -128,7 +166,7 @@ ENGINE_LINKAGE int pcreExecWrapper(const + } + + /* +- * we need to specify the vector length for our pcre_exec call. we only care ++ * we need to specify the vector length for our pcre2_match call. we only care + * about the first vector, which if the match is successful will include the + * offset to the end of the full pattern match. If we decide to store other + * matches, make *SURE* that this is a multiple of 3 as pcre requires it. +@@ -136,7 +174,7 @@ ENGINE_LINKAGE int pcreExecWrapper(const + #define SNORT_PCRE_OVECTOR_SIZE 3 + + /** +- * Perform a search of the PCRE data. ++ * Perform a search of the PCRE2 data. + * + * @param pcre_data structure that options and patterns are passed in + * @param buf buffer to search +@@ -148,21 +186,18 @@ ENGINE_LINKAGE int pcreExecWrapper(const + * + * @return 1 when we find the string, 0 when we don't (unless we've been passed a flag to invert) + */ +-static int pcre_test(const PCREInfo *pcre_info, ++static int pcre2_test(const PCRE2Info *pcre2_info, + const char *buf, + int len, + int start_offset, + int *found_offset) + { ++ void *match_data; ++ size_t *ovector; + int matched; + int result; + +- int *ovector; +- int ovector_size; +- +- _ded.pcreOvectorInfo(&ovector, &ovector_size); +- +- if(pcre_info == NULL ++ if(pcre2_info == NULL + || buf == NULL + || len <= 0 + || start_offset < 0 +@@ -174,50 +209,59 @@ static int pcre_test(const PCREInfo *pcr + return 0; + } + ++ match_data = _ded.pcre2MatchDataCreate(_ded.pcre2OvectorSize(), NULL); ++ if (!match_data) { ++ DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, ++ "Returning 0 because match data failed!\n");); ++ return 0; ++ } ++ + *found_offset = -1; + +- result = _ded.pcreExec(pcre_info->compiled_expr,/* result of pcre_compile() */ +- pcre_info->compiled_extra, /* result of pcre_study() */ ++ result = _ded.pcre2MatchReal(pcre2_info->compiled_expr,/* result of pcre_compile() */ + buf, /* the subject string */ + len, /* the length of the subject string */ + start_offset, /* start at offset 0 in the subject */ + 0, /* options(handled at compile time */ +- ovector, /* vector for substring information */ +- ovector_size); /* number of elements in the vector */ ++ match_data, /* match_data vector */ ++ pcre2_info->match_context); /* match context for limits */ + + if(result >= 0) + { + matched = 1; + } +- else if(result == PCRE_ERROR_NOMATCH) ++ else if(result == PCRE2_ERROR_NOMATCH) + { + matched = 0; + } + else + { +- DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "pcre_exec error : %d \n", result);); ++ _ded.pcre2MatchDataFree(match_data); ++ DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "pcre_match error : %d \n", result);); + return 0; + } + + if (found_offset) + { ++ ovector = _ded.pcre2GetOvectorPointer(match_data); + *found_offset = ovector[1]; + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, + "Setting buffer and found_offset: %p %d\n", + buf, found_offset);); + } + ++ _ded.pcre2MatchDataFree(match_data); + return matched; + } + +-ENGINE_LINKAGE int pcreMatch(void *p, PCREInfo* pcre_info, const uint8_t **cursor) ++ENGINE_LINKAGE int pcre2Match(void *p, PCRE2Info* pcre_info, const uint8_t **cursor) + { + if (pcre_info->flags & NOT_FLAG) + return invertMatchResult(pcreMatchInternal(p, pcre_info, cursor)); + return pcreMatchInternal(p, pcre_info, cursor); + } + +-static int pcreMatchInternal(void *p, PCREInfo* pcre_info, const uint8_t **cursor) ++static int pcreMatchInternal(void *p, PCRE2Info* pcre_info, const uint8_t **cursor) + { + const uint8_t *buffer_start; + int buffer_len; +@@ -295,7 +339,7 @@ static int pcreMatchInternal(void *p, PC + } + + +- pcre_found = pcre_test(pcre_info, (const char *)buffer_start, buffer_len, pcre_info->offset, &pcre_offset); ++ pcre_found = pcre2_test(pcre_info, (const char *)buffer_start, buffer_len, pcre_info->offset, &pcre_offset); + + if (pcre_found) + { +--- a/src/dynamic-preprocessors/appid/luaDetectorApi.c ++++ b/src/dynamic-preprocessors/appid/luaDetectorApi.c +@@ -38,7 +38,8 @@ + #include "luaDetectorModule.h" + #include "luaDetectorApi.h" + #include "luaDetectorFlowApi.h" +-#include <pcre.h> ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + #include "httpCommon.h" + #include "sf_multi_mpse.h" + #include "fw_appid.h" +@@ -54,7 +55,6 @@ + #include "detector_cip.h" + + #define DETECTOR "Detector" +-#define OVECCOUNT 30 /* should be a multiple of 3 */ + #define URL_LIST_STEP_SIZE 5000 + + typedef enum { +@@ -1355,7 +1355,7 @@ static int Detector_getPacketDir( + return 1; + } + +-/**Perform a pcre match with grouping. A simple regular expression match with no grouping ++/**Perform a pcre2 match with grouping. A simple regular expression match with no grouping + * can also be performed. + * + * @param Lua_State* - Lua state variable. +@@ -1371,12 +1371,15 @@ static int Detector_getPcreGroups( + Detector *detector; + char *pattern; + unsigned int offset; +- pcre *re; +- int ovector[OVECCOUNT]; +- const char *error; +- int erroffset; ++ pcre2_code *re; ++ pcre2_match_data *match_data; ++ PCRE2_UCHAR error[128]; ++ int errorcode; ++ PCRE2_SIZE erroffset; + int rc, i; + DetectorUserData *detectorUserData = checkDetectorUserData(L, 1); ++ unsigned int oveccount; ++ size_t *ovector; + + pattern = (char *)lua_tostring(L, 2); + offset = lua_tonumber(L, 3); /*offset can be zero, no check necessary. */ +@@ -1390,49 +1393,56 @@ static int Detector_getPcreGroups( + + { + /*compile the regular expression pattern, and handle errors */ +- re = pcre_compile( +- pattern, /*the pattern */ +- PCRE_DOTALL, /*default options - dot matches everything including newline */ +- &error, /*for error message */ +- &erroffset, /*for error offset */ +- NULL); /*use default character tables */ ++ re = pcre2_compile( ++ (PCRE2_SPTR)pattern, /*the pattern */ ++ PCRE2_ZERO_TERMINATED, /*zero terminated string*/ ++ PCRE2_DOTALL, /*default options - dot matches everything including newline */ ++ &errorcode, /*for error message */ ++ &erroffset, /*for error offset */ ++ NULL); /*use default character tables */ + + if (re == NULL) + { +- _dpd.errMsg("PCRE compilation failed at offset %d: %s\n",erroffset, error); ++ pcre2_get_error_message(errorcode, error, 128); ++ _dpd.errMsg("PCRE2 compilation failed at offset %zu: %s\n",erroffset, error); + return 0; + } + ++ match_data = pcre2_match_data_create_from_pattern(re, NULL); ++ if (!match_data) { ++ _dpd.errMsg("PCRE2 failed to alloc data for match data\n"); ++ return 0; ++ } + + /*pattern match against the subject string. */ +- rc = pcre_exec( ++ rc = pcre2_match( + re, /*compiled pattern */ +- NULL, /*no extra data */ +- (char *)detector->validateParams.data, /*subject string */ +- detector->validateParams.size, /*length of the subject */ +- offset, /*offset 0 */ ++ (PCRE2_SPTR)detector->validateParams.data, /*subject string */ ++ (PCRE2_SIZE)detector->validateParams.size, /*length of the subject */ ++ (PCRE2_SIZE)offset, /*offset 0 */ + 0, /*default options */ +- ovector, /*output vector for substring information */ +- OVECCOUNT); /*number of elements in the output vector */ +- ++ match_data, /*output vector for substring information */ ++ NULL); /*number of elements in the output vector */ + + if (rc < 0) + { + /*Matching failed: clubbing PCRE_ERROR_NOMATCH with other errors. */ +- pcre_free(re); ++ pcre2_match_data_free(match_data); ++ pcre2_code_free(re); + return 0; + } + + /*Match succeded */ + + /*printf("\nMatch succeeded at offset %d", ovector[0]); */ +- pcre_free(re); + ++ oveccount = pcre2_get_ovector_count(match_data); ++ ovector = pcre2_get_ovector_pointer(match_data); + + if (rc == 0) + { + /*overflow of matches */ +- rc = OVECCOUNT/3; ++ rc = oveccount/3; + /*printf("ovector only has room for %d captured substrings", rc - 1); */ + _dpd.errMsg("ovector only has room for %d captured substrings\n",rc - 1); + } +@@ -1447,6 +1457,9 @@ static int Detector_getPcreGroups( + lua_pushlstring(L, (char *)detector->validateParams.data + ovector[2*i], ovector[2*i+1] - ovector[2*i]); + } + ++ pcre2_match_data_free(match_data); ++ pcre2_code_free(re); ++ + return rc; + } + +--- a/src/dynamic-preprocessors/imap/snort_imap.h ++++ b/src/dynamic-preprocessors/imap/snort_imap.h +@@ -38,7 +38,8 @@ + + /* Includes ***************************************************************/ + +-#include <pcre.h> ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + + #include "sf_snort_packet.h" + #include "imap_config.h" +@@ -216,8 +217,7 @@ typedef struct _IMAPMimeBoundary + + typedef struct _IMAPPcre + { +- pcre *re; +- pcre_extra *pe; ++ pcre2_code *re; + + } IMAPPcre; + +--- a/src/dynamic-preprocessors/pop/snort_pop.h ++++ b/src/dynamic-preprocessors/pop/snort_pop.h +@@ -38,7 +38,8 @@ + + /* Includes ***************************************************************/ + +-#include <pcre.h> ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + + #include "sf_snort_packet.h" + #include "pop_config.h" +--- a/src/dynamic-preprocessors/smtp/snort_smtp.h ++++ b/src/dynamic-preprocessors/smtp/snort_smtp.h +@@ -39,7 +39,8 @@ + + /* Includes ***************************************************************/ + +-#include <pcre.h> ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + + #include "sf_snort_packet.h" + #include "ssl.h" +--- a/src/snort.c ++++ b/src/snort.c +@@ -4449,9 +4449,6 @@ void SnortConfFree(SnortConfig *sc) + + OtnxMatchDataFree(sc->omd); + +- if (sc->pcre_ovector != NULL) +- free(sc->pcre_ovector); +- + if ( sc->event_queue_config ) + EventQueueConfigFree(sc->event_queue_config); + +--- a/src/snort.h ++++ b/src/snort.h +@@ -826,7 +826,6 @@ typedef struct _SnortConfig + long int tagged_packet_limit; /* config tagged_packet_limit */ + long int pcre_match_limit; /* config pcre_match_limit */ + long int pcre_match_limit_recursion; /* config pcre_match_limit_recursion */ +- int *pcre_ovector; + int pcre_ovector_size; + + #ifdef PERF_PROFILING +--- a/src/util.c ++++ b/src/util.c +@@ -78,7 +78,8 @@ static struct mallinfo mi; + #include "plugbase.h" + #include "sf_types.h" + #include "sflsq.h" +-#include "pcre.h" ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include "pcre2.h" + #include "mpse.h" + #include "ppm.h" + #include "active.h" +@@ -175,7 +176,7 @@ double CalcPct(uint64_t cnt, uint64_t to + int DisplayBanner(void) + { + const char * info; +- const char * pcre_ver; ++ PCRE2_UCHAR buffer[32]; + const char * zlib_ver; + + info = getenv("HOSTTYPE"); +@@ -184,7 +185,7 @@ int DisplayBanner(void) + info=""; + } + +- pcre_ver = pcre_version(); ++ pcre2_config(PCRE2_CONFIG_VERSION, buffer); + zlib_ver = zlib_version; + + LogMessage("\n"); +@@ -204,7 +205,7 @@ int DisplayBanner(void) + #ifdef HAVE_PCAP_LIB_VERSION + LogMessage(" Using %s\n", pcap_lib_version()); + #endif +- LogMessage(" Using PCRE version: %s\n", pcre_ver); ++ LogMessage(" Using PCRE2 version: %s\n", buffer); + LogMessage(" Using ZLIB version: %s\n", zlib_ver); + LogMessage("\n"); + |