aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--net/snort/Makefile6
-rw-r--r--net/snort/patches/900-Convert-project-to-PCRE2.patch2114
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");
+