2053 lines
70 KiB
Diff
2053 lines
70 KiB
Diff
From a71cca137eb33f659354ce0ebda4951cb26485df Mon Sep 17 00:00:00 2001
|
|
From: Christian Marangi <ansuelsmth@gmail.com>
|
|
Date: Mon, 6 Nov 2023 22:43:59 +0100
|
|
Subject: [PATCH] core: convert project to PCRE2
|
|
|
|
Convert project to PCRE2 as PCRE is EOL and won't receive any security
|
|
updates anymore.
|
|
|
|
PCRE2 changed some API and concept. Mainly there isn't the concept of
|
|
study anymore, replaced by match_context concept and match_data is used
|
|
instead of ovector to handle results. Because of this the scratcher is
|
|
not needed anymore and is replaced by a simple function to setup the max
|
|
ovector size on end module init.
|
|
|
|
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
|
---
|
|
README.md | 17 +-
|
|
cmake/FindPCRE.cmake | 32 --
|
|
cmake/FindPCRE2.cmake | 32 ++
|
|
cmake/create_pkg_config.cmake | 4 +-
|
|
cmake/include_libraries.cmake | 2 +-
|
|
configure_cmake.sh | 16 +-
|
|
lua/balanced.lua | 2 +-
|
|
lua/max_detect.lua | 6 +-
|
|
lua/security.lua | 4 +-
|
|
snort.pc.in | 4 +-
|
|
src/CMakeLists.txt | 4 +-
|
|
src/detection/detection_module.cc | 48 +--
|
|
src/detection/detection_options.cc | 6 +-
|
|
src/ips_options/ips_options.cc | 4 +-
|
|
src/ips_options/ips_pcre.cc | 391 ++++++++----------
|
|
src/main/shell.cc | 9 +-
|
|
src/main/snort_config.h | 26 +-
|
|
.../appid/lua_detector_api.cc | 62 +--
|
|
src/parser/parse_rule.cc | 4 +-
|
|
src/parser/parse_stream.cc | 2 +-
|
|
src/search_engines/test/hyperscan_test.cc | 2 +-
|
|
src/utils/stats.cc | 6 +-
|
|
src/utils/stats.h | 6 +-
|
|
src/utils/util.cc | 8 +-
|
|
tools/snort2lua/config_states/config_api.cc | 12 +-
|
|
.../config_states/config_no_option.cc | 14 +-
|
|
.../config_states/config_one_int_option.cc | 24 +-
|
|
tools/snort2lua/rule_states/CMakeLists.txt | 2 +-
|
|
tools/snort2lua/rule_states/rule_api.cc | 4 +-
|
|
.../{rule_pcre.cc => rule_pcre2.cc} | 40 +-
|
|
.../snort2lua/rule_states/rule_sd_pattern.cc | 4 +-
|
|
31 files changed, 393 insertions(+), 404 deletions(-)
|
|
delete mode 100644 cmake/FindPCRE.cmake
|
|
create mode 100644 cmake/FindPCRE2.cmake
|
|
rename tools/snort2lua/rule_states/{rule_pcre.cc => rule_pcre2.cc} (80%)
|
|
|
|
--- a/README.md
|
|
+++ b/README.md
|
|
@@ -8,13 +8,14 @@ topics:
|
|
|
|
---
|
|
|
|
-* [Overview](#overview)
|
|
-* [Dependencies](#dependencies)
|
|
-* [Download](#download)
|
|
-* [Build Snort](#build-snort)
|
|
-* [Run Snort](#run-snort)
|
|
-* [Documentation](#documentation)
|
|
-* [Squeal](#squeal)
|
|
+- [Snort++](#snort)
|
|
+- [OVERVIEW](#overview)
|
|
+- [DEPENDENCIES](#dependencies)
|
|
+- [DOWNLOAD](#download)
|
|
+- [BUILD SNORT](#build-snort)
|
|
+- [RUN SNORT](#run-snort)
|
|
+- [DOCUMENTATION](#documentation)
|
|
+- [SQUEAL](#squeal)
|
|
|
|
# OVERVIEW
|
|
|
|
@@ -61,7 +62,7 @@ the latest:
|
|
* OpenSSL from https://www.openssl.org/source/ for SHA and MD5 file signatures,
|
|
the protected_content rule option, and SSL service detection
|
|
* pcap from http://www.tcpdump.org for tcpdump style logging
|
|
-* pcre from http://www.pcre.org for regular expression pattern matching
|
|
+* pcre2 from http://www.pcre.org for regular expression pattern matching
|
|
* pkgconfig from https://www.freedesktop.org/wiki/Software/pkg-config/ to locate build dependencies
|
|
* zlib from http://www.zlib.net for decompression
|
|
|
|
--- a/cmake/FindPCRE.cmake
|
|
+++ /dev/null
|
|
@@ -1,32 +0,0 @@
|
|
-# - Find pcre
|
|
-# Find the native PCRE includes and library
|
|
-#
|
|
-# PCRE_INCLUDE_DIR - where to find pcre.h, etc.
|
|
-# PCRE_LIBRARIES - List of libraries when using pcre.
|
|
-# PCRE_FOUND - True if pcre found.
|
|
-
|
|
-set(ERROR_MESSAGE
|
|
- "\n\tERROR! Libpcre library not found.
|
|
- \tGet it from http://www.pcre.org\n"
|
|
-)
|
|
-
|
|
-find_package(PkgConfig)
|
|
-pkg_check_modules(PC_PCRE libpcre)
|
|
-
|
|
-# Use PCRE_INCLUDE_DIR_HINT and PCRE_LIBRARIES_DIR_HINT from configure_cmake.sh as primary hints
|
|
-# and then package config information after that.
|
|
-find_path(PCRE_INCLUDE_DIR pcre.h
|
|
- HINTS ${PCRE_INCLUDE_DIR_HINT} ${PC_PCRE_INCLUDEDIR} ${PC_PCRE_INCLUDE_DIRS})
|
|
-find_library(PCRE_LIBRARIES NAMES pcre
|
|
- HINTS ${PCRE_LIBRARIES_DIR_HINT} ${PC_PCRE_LIBDIR} ${PC_PCRE_LIBRARY_DIRS})
|
|
-
|
|
-include(FindPackageHandleStandardArgs)
|
|
-find_package_handle_standard_args(PCRE
|
|
- REQUIRED_VARS PCRE_INCLUDE_DIR PCRE_LIBRARIES
|
|
- FAIL_MESSAGE "${ERROR_MESSAGE}"
|
|
-)
|
|
-
|
|
-mark_as_advanced(
|
|
- PCRE_LIBRARIES
|
|
- PCRE_INCLUDE_DIR
|
|
-)
|
|
--- /dev/null
|
|
+++ b/cmake/FindPCRE2.cmake
|
|
@@ -0,0 +1,32 @@
|
|
+# - Find pcre2
|
|
+# Find the native PCRE2 includes and library
|
|
+#
|
|
+# PCRE2_INCLUDE_DIR - where to find pcre2.h, etc.
|
|
+# PCRE2_LIBRARIES - List of libraries when using pcre2.
|
|
+# PCRE2_FOUND - True if pcre2 found.
|
|
+
|
|
+set(ERROR_MESSAGE
|
|
+ "\n\tERROR! Libpcre2 library not found.
|
|
+ \tGet it from http://www.pcre.org\n"
|
|
+)
|
|
+
|
|
+find_package(PkgConfig)
|
|
+pkg_check_modules(PC_PCRE2 libpcre2-8)
|
|
+
|
|
+# Use PCRE2_INCLUDE_DIR_HINT and PCRE_LIBRARIES_DIR_HINT from configure_cmake.sh as primary hints
|
|
+# and then package config information after that.
|
|
+find_path(PCRE2_INCLUDE_DIR pcre2.h
|
|
+ HINTS ${PCRE2_INCLUDE_DIR_HINT} ${PC_PCRE2_INCLUDEDIR} ${PC_PCRE2_INCLUDE_DIRS})
|
|
+find_library(PCRE2_LIBRARIES NAMES pcre2-8
|
|
+ HINTS ${PCRE2_LIBRARIES_DIR_HINT} ${PC_PCRE2_LIBDIR} ${PC_PCRE2_LIBRARY_DIRS})
|
|
+
|
|
+include(FindPackageHandleStandardArgs)
|
|
+find_package_handle_standard_args(PCRE2-8
|
|
+ REQUIRED_VARS PCRE2_INCLUDE_DIR PCRE2_LIBRARIES
|
|
+ FAIL_MESSAGE "${ERROR_MESSAGE}"
|
|
+)
|
|
+
|
|
+mark_as_advanced(
|
|
+ PCRE2_LIBRARIES
|
|
+ PCRE2_INCLUDE_DIR
|
|
+)
|
|
--- a/cmake/create_pkg_config.cmake
|
|
+++ b/cmake/create_pkg_config.cmake
|
|
@@ -72,8 +72,8 @@ if(PCAP_INCLUDE_DIR)
|
|
set(PCAP_CPPFLAGS "-I${PCAP_INCLUDE_DIR}")
|
|
endif()
|
|
|
|
-if(PCRE_INCLUDE_DIR)
|
|
- set(PCRE_CPPFLAGS "-I${PCRE_INCLUDE_DIR}")
|
|
+if(PCRE2_INCLUDE_DIR)
|
|
+ set(PCRE2_CPPFLAGS "-I${PCRE2_INCLUDE_DIR}")
|
|
endif()
|
|
|
|
if(UUID_INCLUDE_DIR)
|
|
--- a/cmake/include_libraries.cmake
|
|
+++ b/cmake/include_libraries.cmake
|
|
@@ -8,7 +8,7 @@ find_package(HWLOC REQUIRED)
|
|
find_package(LuaJIT REQUIRED)
|
|
find_package(OpenSSL 1.1.1 REQUIRED)
|
|
find_package(PCAP REQUIRED)
|
|
-find_package(PCRE REQUIRED)
|
|
+find_package(PCRE2 REQUIRED)
|
|
find_package(ZLIB REQUIRED)
|
|
if (ENABLE_UNIT_TESTS)
|
|
find_package(CppUTest REQUIRED)
|
|
--- a/configure_cmake.sh
|
|
+++ b/configure_cmake.sh
|
|
@@ -90,10 +90,10 @@ Optional Packages:
|
|
luajit include directory
|
|
--with-luajit-libraries=DIR
|
|
luajit library directory
|
|
- --with-pcre-includes=DIR
|
|
- libpcre include directory
|
|
- --with-pcre-libraries=DIR
|
|
- libpcre library directory
|
|
+ --with-pcre2-includes=DIR
|
|
+ libpcre2 include directory
|
|
+ --with-pcre2-libraries=DIR
|
|
+ libpcre2 library directory
|
|
--with-dnet-includes=DIR
|
|
libdnet include directory
|
|
--with-dnet-libraries=DIR
|
|
@@ -417,11 +417,11 @@ while [ $# -ne 0 ]; do
|
|
--with-luajit-libraries=*)
|
|
append_cache_entry LUAJIT_LIBRARIES_DIR_HINT PATH $optarg
|
|
;;
|
|
- --with-pcre-includes=*)
|
|
- append_cache_entry PCRE_INCLUDE_DIR_HINT PATH $optarg
|
|
+ --with-pcre2-includes=*)
|
|
+ append_cache_entry PCRE2_INCLUDE_DIR_HINT PATH $optarg
|
|
;;
|
|
- --with-pcre-libraries=*)
|
|
- append_cache_entry PCRE_LIBRARIES_DIR_HINT PATH $optarg
|
|
+ --with-pcre2-libraries=*)
|
|
+ append_cache_entry PCRE2_LIBRARIES_DIR_HINT PATH $optarg
|
|
;;
|
|
--with-dnet-includes=*)
|
|
append_cache_entry DNET_INCLUDE_DIR_HINT PATH $optarg
|
|
--- a/lua/balanced.lua
|
|
+++ b/lua/balanced.lua
|
|
@@ -5,7 +5,7 @@
|
|
|
|
arp_spoof = nil
|
|
|
|
-detection = { pcre_override = false }
|
|
+detection = { pcre2_override = false }
|
|
|
|
http_inspect.request_depth = 300
|
|
http_inspect.response_depth = 500
|
|
--- a/lua/max_detect.lua
|
|
+++ b/lua/max_detect.lua
|
|
@@ -10,13 +10,13 @@ ftp_server.check_encrypted = true
|
|
|
|
detection =
|
|
{
|
|
- pcre_match_limit = 3500,
|
|
- pcre_match_limit_recursion = 3500,
|
|
+ pcre2_match_limit = 3500,
|
|
+ pcre2_match_limit_recursion = 3500,
|
|
|
|
-- enable for hyperscan for best throughput
|
|
-- use multiple packet threads for fast startup
|
|
--hyperscan_literals = true,
|
|
- --pcre_to_regex = true
|
|
+ --pcre2_to_regex = true
|
|
}
|
|
|
|
http_inspect.decompress_pdf = true
|
|
--- a/lua/security.lua
|
|
+++ b/lua/security.lua
|
|
@@ -9,8 +9,8 @@ ftp_server.check_encrypted = true
|
|
|
|
detection =
|
|
{
|
|
- pcre_match_limit = 3500,
|
|
- pcre_match_limit_recursion = 3500
|
|
+ pcre2_match_limit = 3500,
|
|
+ pcre2_match_limit_recursion = 3500
|
|
}
|
|
|
|
http_inspect.decompress_pdf = true
|
|
--- a/snort.pc.in
|
|
+++ b/snort.pc.in
|
|
@@ -9,7 +9,7 @@ mandir=@mandir@
|
|
infodir=@infodir@
|
|
|
|
cpp_opts=DAQ LUAJIT
|
|
-cpp_opts_other=DNET HWLOC HYPERSCAN LZMA OPENSSL PCAP PCRE UUID
|
|
+cpp_opts_other=DNET HWLOC HYPERSCAN LZMA OPENSSL PCAP PCRE2 UUID
|
|
|
|
PCAP_CPPFLAGS=@PCAP_CPPFLAGS@
|
|
LUAJIT_CPPFLAGS=@LUAJIT_CPPFLAGS@
|
|
@@ -18,7 +18,7 @@ DAQ_CPPFLAGS=@DAQ_CPPFLAGS@
|
|
FLEX_CPPFLAGS=@FLEX_CPPFLAGS@
|
|
OPENSSL_CPPFLAGS=@OPENSSL_CPPFLAGS@
|
|
HWLOC_CPPFLAGS=@HWLOC_CPPFLAGS@
|
|
-PCRE_CPPFLAGS=@PCRE_CPPFLAGS@
|
|
+PCRE2_CPPFLAGS=@PCRE2_CPPFLAGS@
|
|
LZMA_CPPFLAGS=@LZMA_CPPFLAGS@
|
|
HYPERSCAN_CPPFLAGS=@HYPERSCAN_CPPFLAGS@
|
|
UUID_CPPFLAGS=@UUID_CPPFLAGS@
|
|
--- a/src/CMakeLists.txt
|
|
+++ b/src/CMakeLists.txt
|
|
@@ -10,7 +10,7 @@ set(EXTERNAL_LIBRARIES
|
|
${LUAJIT_LIBRARIES}
|
|
${OPENSSL_CRYPTO_LIBRARY}
|
|
${PCAP_LIBRARIES}
|
|
- ${PCRE_LIBRARIES}
|
|
+ ${PCRE2_LIBRARIES}
|
|
${ZLIB_LIBRARIES}
|
|
)
|
|
|
|
@@ -21,7 +21,7 @@ set(EXTERNAL_INCLUDES
|
|
${HWLOC_INCLUDE_DIRS}
|
|
${OPENSSL_INCLUDE_DIR}
|
|
${PCAP_INCLUDE_DIR}
|
|
- ${PCRE_INCLUDE_DIR}
|
|
+ ${PCRE2_INCLUDE_DIR}
|
|
${ZLIB_INCLUDE_DIRS}
|
|
)
|
|
|
|
--- a/src/detection/detection_module.cc
|
|
+++ b/src/detection/detection_module.cc
|
|
@@ -96,21 +96,21 @@ static const Parameter detection_params[
|
|
{ "offload_threads", Parameter::PT_INT, "0:max32", "0",
|
|
"maximum number of simultaneous offloads (defaults to disabled)" },
|
|
|
|
- { "pcre_enable", Parameter::PT_BOOL, nullptr, "true",
|
|
- "enable pcre pattern matching" },
|
|
+ { "pcre2_enable", Parameter::PT_BOOL, nullptr, "true",
|
|
+ "enable pcre2 pattern matching" },
|
|
|
|
- { "pcre_match_limit", Parameter::PT_INT, "0:max32", "1500",
|
|
- "limit pcre backtracking, 0 = off" },
|
|
+ { "pcre2_match_limit", Parameter::PT_INT, "0:max32", "1500",
|
|
+ "limit pcre2 backtracking, 0 = off" },
|
|
|
|
- { "pcre_match_limit_recursion", Parameter::PT_INT, "0:max32", "1500",
|
|
- "limit pcre stack consumption, 0 = off" },
|
|
+ { "pcre2_match_limit_recursion", Parameter::PT_INT, "0:max32", "1500",
|
|
+ "limit pcre2 stack consumption, 0 = off" },
|
|
|
|
- { "pcre_override", Parameter::PT_BOOL, nullptr, "true",
|
|
- "enable pcre match limit overrides when pattern matching (ie ignore /O)" },
|
|
+ { "pcre2_override", Parameter::PT_BOOL, nullptr, "true",
|
|
+ "enable pcre2 match limit overrides when pattern matching (ie ignore /O)" },
|
|
|
|
#ifdef HAVE_HYPERSCAN
|
|
- { "pcre_to_regex", Parameter::PT_BOOL, nullptr, "false",
|
|
- "enable the use of regex instead of pcre for compatible expressions" },
|
|
+ { "pcre2_to_regex", Parameter::PT_BOOL, nullptr, "false",
|
|
+ "enable the use of regex instead of pcre2 for compatible expressions" },
|
|
#endif
|
|
|
|
{ "enable_address_anomaly_checks", Parameter::PT_BOOL, nullptr, "false",
|
|
@@ -221,13 +221,13 @@ bool DetectionModule::set(const char*, V
|
|
else if ( v.is("offload_threads") )
|
|
sc->offload_threads = v.get_uint32();
|
|
|
|
- else if ( v.is("pcre_enable") )
|
|
- v.update_mask(sc->run_flags, RUN_FLAG__NO_PCRE, true);
|
|
+ else if ( v.is("pcre2_enable") )
|
|
+ v.update_mask(sc->run_flags, RUN_FLAG__NO_PCRE2, true);
|
|
|
|
- else if ( v.is("pcre_match_limit") )
|
|
- sc->pcre_match_limit = v.get_uint32();
|
|
+ else if ( v.is("pcre2_match_limit") )
|
|
+ sc->pcre2_match_limit = v.get_uint32();
|
|
|
|
- else if ( v.is("pcre_match_limit_recursion") )
|
|
+ else if ( v.is("pcre2_match_limit_recursion") )
|
|
{
|
|
// Cap the pcre recursion limit to not exceed the stack size.
|
|
//
|
|
@@ -252,21 +252,21 @@ bool DetectionModule::set(const char*, V
|
|
if (max_rec < 0)
|
|
max_rec = 0;
|
|
|
|
- sc->pcre_match_limit_recursion = v.get_uint32();
|
|
- if (sc->pcre_match_limit_recursion > max_rec)
|
|
+ sc->pcre2_match_limit_recursion = v.get_uint32();
|
|
+ if (sc->pcre2_match_limit_recursion > max_rec)
|
|
{
|
|
- sc->pcre_match_limit_recursion = max_rec;
|
|
- LogMessage("Capping pcre_match_limit_recursion to %ld, thread stack_size %ld.\n",
|
|
- sc->pcre_match_limit_recursion, thread_stack_size);
|
|
+ sc->pcre2_match_limit_recursion = max_rec;
|
|
+ LogMessage("Capping pcre2_match_limit_recursion to %ld, thread stack_size %llu.\n",
|
|
+ sc->pcre2_match_limit_recursion, thread_stack_size);
|
|
}
|
|
}
|
|
|
|
- else if ( v.is("pcre_override") )
|
|
- sc->pcre_override = v.get_bool();
|
|
+ else if ( v.is("pcre2_override") )
|
|
+ sc->pcre2_override = v.get_bool();
|
|
|
|
#ifdef HAVE_HYPERSCAN
|
|
- else if ( v.is("pcre_to_regex") )
|
|
- sc->pcre_to_regex = v.get_bool();
|
|
+ else if ( v.is("pcre2_to_regex") )
|
|
+ sc->pcre2_to_regex = v.get_bool();
|
|
#endif
|
|
|
|
else if ( v.is("enable_address_anomaly_checks") )
|
|
--- a/src/detection/detection_options.cc
|
|
+++ b/src/detection/detection_options.cc
|
|
@@ -595,7 +595,7 @@ int detection_option_node_evaluate(
|
|
{
|
|
if ( !child_node->is_relative )
|
|
{
|
|
- // If it's a non-relative content or pcre, no reason
|
|
+ // If it's a non-relative content or pcre2, no reason
|
|
// to check again. Only increment result once.
|
|
// Should hit this condition on first loop iteration.
|
|
if ( loop_count == 1 )
|
|
@@ -661,10 +661,10 @@ int detection_option_node_evaluate(
|
|
}
|
|
|
|
// If all children branches matched, we don't need to reeval any of
|
|
- // the children so don't need to reeval this content/pcre rule
|
|
+ // the children so don't need to reeval this content/pcre2 rule
|
|
// option at a new offset.
|
|
// Else, reset the DOE ptr to last eval for offset/depth,
|
|
- // distance/within adjustments for this same content/pcre rule option.
|
|
+ // distance/within adjustments for this same content/pcre2 rule option.
|
|
// If the node and its sub-tree propagate MATCH back,
|
|
// then all its continuations are recalled.
|
|
if ( result == node->num_children )
|
|
--- a/src/ips_options/ips_options.cc
|
|
+++ b/src/ips_options/ips_options.cc
|
|
@@ -72,7 +72,7 @@ extern const BaseApi* ips_ip_proto[];
|
|
extern const BaseApi* ips_isdataat[];
|
|
extern const BaseApi* ips_itype[];
|
|
extern const BaseApi* ips_msg[];
|
|
-extern const BaseApi* ips_pcre[];
|
|
+extern const BaseApi* ips_pcre2[];
|
|
extern const BaseApi* ips_priority[];
|
|
extern const BaseApi* ips_raw_data[];
|
|
extern const BaseApi* ips_rem[];
|
|
@@ -146,7 +146,7 @@ void load_ips_options()
|
|
PluginManager::load_plugins(ips_isdataat);
|
|
PluginManager::load_plugins(ips_itype);
|
|
PluginManager::load_plugins(ips_msg);
|
|
- PluginManager::load_plugins(ips_pcre);
|
|
+ PluginManager::load_plugins(ips_pcre2);
|
|
PluginManager::load_plugins(ips_priority);
|
|
PluginManager::load_plugins(ips_raw_data);
|
|
PluginManager::load_plugins(ips_rem);
|
|
--- a/src/ips_options/ips_pcre.cc
|
|
+++ b/src/ips_options/ips_pcre.cc
|
|
@@ -23,7 +23,8 @@
|
|
#include "config.h"
|
|
#endif
|
|
|
|
-#include <pcre.h>
|
|
+#define PCRE2_CODE_UNIT_WIDTH 8
|
|
+#include <pcre2.h>
|
|
|
|
#include <cassert>
|
|
|
|
@@ -43,33 +44,31 @@
|
|
|
|
using namespace snort;
|
|
|
|
-#ifndef PCRE_STUDY_JIT_COMPILE
|
|
-#define PCRE_STUDY_JIT_COMPILE 0
|
|
+#ifndef PCRE2_STUDY_JIT_COMPILE
|
|
+#define PCRE2_STUDY_JIT_COMPILE 0
|
|
#endif
|
|
|
|
//#define NO_JIT // uncomment to disable JIT for Xcode
|
|
|
|
#ifdef NO_JIT
|
|
-#define PCRE_STUDY_FLAGS 0
|
|
-#define pcre_release(x) pcre_free(x)
|
|
+#define PCRE2_JIT 0
|
|
#else
|
|
-#define PCRE_STUDY_FLAGS PCRE_STUDY_JIT_COMPILE
|
|
-#define pcre_release(x) pcre_free_study(x)
|
|
+#define PCRE2_JIT PCRE2_STUDY_JIT_COMPILE
|
|
#endif
|
|
+#define pcre2_release(x) pcre2_code_free(x)
|
|
|
|
#define SNORT_PCRE_RELATIVE 0x00010 // relative to the end of the last match
|
|
#define SNORT_PCRE_INVERT 0x00020 // invert detect
|
|
#define SNORT_PCRE_ANCHORED 0x00040
|
|
#define SNORT_OVERRIDE_MATCH_LIMIT 0x00080 // Override default limits on match & match recursion
|
|
|
|
-#define s_name "pcre"
|
|
+#define s_name "pcre2"
|
|
#define mod_regex_name "regex"
|
|
|
|
-struct PcreData
|
|
+struct Pcre2Data
|
|
{
|
|
- pcre* re; /* compiled regex */
|
|
- pcre_extra* pe; /* studied regex foo */
|
|
- bool free_pe;
|
|
+ pcre2_code* re; /* compiled regex */
|
|
+ pcre2_match_context* match_context; /* match_context for limits */
|
|
int options; /* sp_pcre specific options (relative & inverse) */
|
|
char* expression;
|
|
};
|
|
@@ -83,36 +82,32 @@ struct PcreData
|
|
// by verify; search uses the value in snort conf
|
|
static int s_ovector_max = -1;
|
|
|
|
-static unsigned scratch_index;
|
|
-static ScratchAllocator* scratcher = nullptr;
|
|
-
|
|
-static THREAD_LOCAL ProfileStats pcrePerfStats;
|
|
+static THREAD_LOCAL ProfileStats pcre2PerfStats;
|
|
|
|
//-------------------------------------------------------------------------
|
|
// implementation foo
|
|
//-------------------------------------------------------------------------
|
|
|
|
-static void pcre_capture(
|
|
- const void* code, const void* extra)
|
|
+static void pcre2_capture(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 > s_ovector_max)
|
|
s_ovector_max = tmp_ovector_size;
|
|
}
|
|
|
|
-static void pcre_check_anchored(PcreData* pcre_data)
|
|
+static void pcre2_check_anchored(Pcre2Data* pcre2_data)
|
|
{
|
|
int rc;
|
|
unsigned long int options = 0;
|
|
|
|
- if ((pcre_data == nullptr) || (pcre_data->re == nullptr) || (pcre_data->pe == nullptr))
|
|
+ if ((pcre2_data == nullptr) || (pcre2_data->re == nullptr))
|
|
return;
|
|
|
|
- rc = pcre_fullinfo(pcre_data->re, pcre_data->pe, PCRE_INFO_OPTIONS, (void*)&options);
|
|
+ rc = pcre2_pattern_info(pcre2_data->re, PCRE2_INFO_ARGOPTIONS, (void*)&options);
|
|
switch (rc)
|
|
{
|
|
/* pcre_fullinfo fails for the following:
|
|
@@ -127,40 +122,41 @@ static void pcre_check_anchored(PcreData
|
|
/* This is the success code */
|
|
break;
|
|
|
|
- case PCRE_ERROR_NULL:
|
|
- ParseError("pcre_fullinfo: code and/or where were null.");
|
|
+ case PCRE2_ERROR_NULL:
|
|
+ ParseError("pcre2_fullinfo: code and/or where were null.");
|
|
return;
|
|
|
|
- case PCRE_ERROR_BADMAGIC:
|
|
- ParseError("pcre_fullinfo: compiled code didn't have correct magic.");
|
|
+ case PCRE2_ERROR_BADMAGIC:
|
|
+ ParseError("pcre2_fullinfo: compiled code didn't have correct magic.");
|
|
return;
|
|
|
|
- case PCRE_ERROR_BADOPTION:
|
|
- ParseError("pcre_fullinfo: option type is invalid.");
|
|
+ case PCRE2_ERROR_BADOPTION:
|
|
+ ParseError("pcre2_fullinfo: option type is invalid.");
|
|
return;
|
|
|
|
default:
|
|
- ParseError("pcre_fullinfo: Unknown error code.");
|
|
+ ParseError("pcre2_fullinfo: Unknown error code.");
|
|
return;
|
|
}
|
|
|
|
- if ((options & PCRE_ANCHORED) && !(options & PCRE_MULTILINE))
|
|
+ if ((options & PCRE2_ANCHORED) && !(options & PCRE2_MULTILINE))
|
|
{
|
|
/* This means that this pcre rule option shouldn't be EvalStatus
|
|
* even if any of it's relative children should fail to match.
|
|
* It is anchored to the cursor set by the previous cursor setting
|
|
* rule option */
|
|
- pcre_data->options |= SNORT_PCRE_ANCHORED;
|
|
+ pcre2_data->options |= SNORT_PCRE_ANCHORED;
|
|
}
|
|
}
|
|
|
|
-static void pcre_parse(const SnortConfig* sc, const char* data, PcreData* pcre_data)
|
|
+static void pcre2_parse(const SnortConfig* sc, const char* data, Pcre2Data* pcre2_data)
|
|
{
|
|
- 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;
|
|
|
|
if (data == nullptr)
|
|
@@ -180,7 +176,7 @@ static void pcre_parse(const SnortConfig
|
|
|
|
if (*re == '!')
|
|
{
|
|
- pcre_data->options |= SNORT_PCRE_INVERT;
|
|
+ pcre2_data->options |= SNORT_PCRE_INVERT;
|
|
re++;
|
|
while (isspace((int)*re))
|
|
re++;
|
|
@@ -212,7 +208,7 @@ static void pcre_parse(const SnortConfig
|
|
else if (*re != delimit)
|
|
goto syntax;
|
|
|
|
- pcre_data->expression = snort_strdup(re);
|
|
+ pcre2_data->expression = snort_strdup(re);
|
|
|
|
/* find ending delimiter, trim delimit chars */
|
|
opts = strrchr(re, delimit);
|
|
@@ -230,25 +226,25 @@ static void pcre_parse(const SnortConfig
|
|
{
|
|
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
|
|
+ * these are snort specific don't work with pcre2 or perl
|
|
*/
|
|
- case 'R': pcre_data->options |= SNORT_PCRE_RELATIVE; break;
|
|
+ case 'R': pcre2_data->options |= SNORT_PCRE_RELATIVE; break;
|
|
case 'O':
|
|
- if ( sc->pcre_override )
|
|
- pcre_data->options |= SNORT_OVERRIDE_MATCH_LIMIT;
|
|
+ if ( sc->pcre2_override )
|
|
+ pcre2_data->options |= SNORT_OVERRIDE_MATCH_LIMIT;
|
|
break;
|
|
|
|
default:
|
|
@@ -259,71 +255,68 @@ static void pcre_parse(const SnortConfig
|
|
}
|
|
|
|
/* now compile the re */
|
|
- pcre_data->re = pcre_compile(re, compile_flags, &error, &erroffset, nullptr);
|
|
+ pcre2_data->re = pcre2_compile((PCRE2_SPTR)re, PCRE2_ZERO_TERMINATED, compile_flags, &errorcode, &erroffset, nullptr);
|
|
+
|
|
+ if (pcre2_data->re == nullptr)
|
|
+ {
|
|
+ pcre2_get_error_message(errorcode, error, 128);
|
|
+ ParseError(": pcre2 compile of '%s' failed at offset "
|
|
+ "%zu : %s", re, erroffset, error);
|
|
+ return;
|
|
+ }
|
|
|
|
- if (pcre_data->re == nullptr)
|
|
+ /* now create match context */
|
|
+ pcre2_data->match_context = pcre2_match_context_create(NULL);
|
|
+ if(pcre2_data->match_context == NULL)
|
|
{
|
|
- ParseError(": pcre compile of '%s' failed at offset "
|
|
- "%d : %s", re, erroffset, error);
|
|
+ ParseError(": failed to allocate memory for match context");
|
|
return;
|
|
}
|
|
|
|
/* now study it... */
|
|
- pcre_data->pe = pcre_study(pcre_data->re, PCRE_STUDY_FLAGS, &error);
|
|
+ if (PCRE2_JIT)
|
|
+ errorcode = pcre2_jit_compile(pcre2_data->re, PCRE2_JIT_COMPLETE);
|
|
|
|
- if (pcre_data->pe)
|
|
+ if (PCRE2_JIT || errorcode)
|
|
{
|
|
- if ((sc->get_pcre_match_limit() != 0) &&
|
|
- !(pcre_data->options & SNORT_OVERRIDE_MATCH_LIMIT))
|
|
+ if ((sc->get_pcre2_match_limit() != 0) &&
|
|
+ !(pcre2_data->options & SNORT_OVERRIDE_MATCH_LIMIT))
|
|
{
|
|
- if ( !(pcre_data->pe->flags & PCRE_EXTRA_MATCH_LIMIT) )
|
|
- pcre_data->pe->flags |= PCRE_EXTRA_MATCH_LIMIT;
|
|
-
|
|
- pcre_data->pe->match_limit = sc->get_pcre_match_limit();
|
|
+ pcre2_set_match_limit(pcre2_data->match_context, sc->get_pcre2_match_limit());
|
|
}
|
|
|
|
- if ((sc->get_pcre_match_limit_recursion() != 0) &&
|
|
- !(pcre_data->options & SNORT_OVERRIDE_MATCH_LIMIT))
|
|
+ if ((sc->get_pcre2_match_limit_recursion() != 0) &&
|
|
+ !(pcre2_data->options & SNORT_OVERRIDE_MATCH_LIMIT))
|
|
{
|
|
- if ( !(pcre_data->pe->flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION) )
|
|
- pcre_data->pe->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
|
|
-
|
|
- pcre_data->pe->match_limit_recursion =
|
|
- sc->get_pcre_match_limit_recursion();
|
|
+ pcre2_set_match_limit(pcre2_data->match_context, sc->get_pcre2_match_limit_recursion());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
- if (!(pcre_data->options & SNORT_OVERRIDE_MATCH_LIMIT) &&
|
|
- ((sc->get_pcre_match_limit() != 0) ||
|
|
- (sc->get_pcre_match_limit_recursion() != 0)))
|
|
+ if (!(pcre2_data->options & SNORT_OVERRIDE_MATCH_LIMIT) &&
|
|
+ ((sc->get_pcre2_match_limit() != 0) ||
|
|
+ (sc->get_pcre2_match_limit_recursion() != 0)))
|
|
{
|
|
- pcre_data->pe = (pcre_extra*)snort_calloc(sizeof(pcre_extra));
|
|
- pcre_data->free_pe = true;
|
|
-
|
|
- if (sc->get_pcre_match_limit() != 0)
|
|
+ if (sc->get_pcre2_match_limit() != 0)
|
|
{
|
|
- pcre_data->pe->flags |= PCRE_EXTRA_MATCH_LIMIT;
|
|
- pcre_data->pe->match_limit = sc->get_pcre_match_limit();
|
|
+ pcre2_set_match_limit(pcre2_data->match_context, sc->get_pcre2_match_limit());
|
|
}
|
|
|
|
- if (sc->get_pcre_match_limit_recursion() != 0)
|
|
+ if (sc->get_pcre2_match_limit_recursion() != 0)
|
|
{
|
|
- pcre_data->pe->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
|
|
- pcre_data->pe->match_limit_recursion =
|
|
- sc->get_pcre_match_limit_recursion();
|
|
+ pcre2_set_match_limit(pcre2_data->match_context, sc->get_pcre2_match_limit_recursion());
|
|
}
|
|
}
|
|
}
|
|
|
|
- if (error != nullptr)
|
|
+ if (PCRE2_JIT && errorcode)
|
|
{
|
|
- ParseError("pcre study failed : %s", error);
|
|
+ ParseError("pcre2 JIT failed : %s", error);
|
|
return;
|
|
}
|
|
|
|
- pcre_capture(pcre_data->re, pcre_data->pe);
|
|
- pcre_check_anchored(pcre_data);
|
|
+ pcre2_capture(pcre2_data->re);
|
|
+ pcre2_check_anchored(pcre2_data);
|
|
|
|
snort_free(free_me);
|
|
return;
|
|
@@ -332,40 +325,44 @@ syntax:
|
|
snort_free(free_me);
|
|
|
|
// ensure integrity from parse error to fatal error
|
|
- if ( !pcre_data->expression )
|
|
- pcre_data->expression = snort_strdup("");
|
|
+ if ( !pcre2_data->expression )
|
|
+ pcre2_data->expression = snort_strdup("");
|
|
|
|
- ParseError("unable to parse pcre %s", data);
|
|
+ ParseError("unable to parse pcre2 %s", data);
|
|
}
|
|
|
|
/*
|
|
- * Perform a search of the PCRE data.
|
|
+ * Perform a search of the PCRE2 data.
|
|
* found_offset will be set to -1 when the find is unsuccessful OR the routine is inverted
|
|
*/
|
|
-static bool pcre_search(
|
|
+static bool pcre2_search(
|
|
Packet* p,
|
|
- const PcreData* pcre_data,
|
|
+ const Pcre2Data* pcre2_data,
|
|
const uint8_t* buf,
|
|
unsigned len,
|
|
unsigned start_offset,
|
|
int& found_offset)
|
|
{
|
|
+ pcre2_match_data *match_data;
|
|
+ PCRE2_SIZE *ovector;
|
|
bool matched;
|
|
|
|
found_offset = -1;
|
|
|
|
- std::vector<void *> ss = p->context->conf->state[get_instance_id()];
|
|
- assert(ss[scratch_index]);
|
|
+ match_data = pcre2_match_data_create(p->context->conf->pcre2_ovector_size, NULL);
|
|
+ if (match_data == nullptr) {
|
|
+ pc.pcre2_error++;
|
|
+ return false;
|
|
+ }
|
|
|
|
- int result = pcre_exec(
|
|
- pcre_data->re, /* result of pcre_compile() */
|
|
- pcre_data->pe, /* result of pcre_study() */
|
|
- (const char*)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 */
|
|
- (int*)ss[scratch_index], /* vector for substring information */
|
|
- p->context->conf->pcre_ovector_size); /* number of elements in the vector */
|
|
+ int result = pcre2_match(
|
|
+ pcre2_data->re, /* result of pcre_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 to store the match results */
|
|
+ pcre2_data->match_context); /* match context for limits */
|
|
|
|
if (result >= 0)
|
|
{
|
|
@@ -390,34 +387,37 @@ static bool pcre_search(
|
|
* and a single int for scratch space.
|
|
*/
|
|
|
|
- found_offset = ((int*)ss[scratch_index])[1];
|
|
+ ovector = pcre2_get_ovector_pointer(match_data);
|
|
+ found_offset = ovector[1];
|
|
}
|
|
- else if (result == PCRE_ERROR_NOMATCH)
|
|
+ else if (result == PCRE2_ERROR_NOMATCH)
|
|
{
|
|
matched = false;
|
|
}
|
|
- else if (result == PCRE_ERROR_MATCHLIMIT)
|
|
+ else if (result == PCRE2_ERROR_MATCHLIMIT)
|
|
{
|
|
- pc.pcre_match_limit++;
|
|
+ pc.pcre2_match_limit++;
|
|
matched = false;
|
|
}
|
|
- else if (result == PCRE_ERROR_RECURSIONLIMIT)
|
|
+ else if (result == PCRE2_ERROR_RECURSIONLIMIT)
|
|
{
|
|
- pc.pcre_recursion_limit++;
|
|
+ pc.pcre2_recursion_limit++;
|
|
matched = false;
|
|
}
|
|
else
|
|
{
|
|
- pc.pcre_error++;
|
|
+ pc.pcre2_error++;
|
|
return false;
|
|
}
|
|
|
|
/* invert sense of match */
|
|
- if (pcre_data->options & SNORT_PCRE_INVERT)
|
|
+ if (pcre2_data->options & SNORT_PCRE_INVERT)
|
|
{
|
|
matched = !matched;
|
|
}
|
|
|
|
+ pcre2_match_data_free(match_data);
|
|
+
|
|
return matched;
|
|
}
|
|
|
|
@@ -425,14 +425,14 @@ static bool pcre_search(
|
|
// class methods
|
|
//-------------------------------------------------------------------------
|
|
|
|
-class PcreOption : public IpsOption
|
|
+class Pcre2Option : public IpsOption
|
|
{
|
|
public:
|
|
- PcreOption(PcreData* c) :
|
|
+ Pcre2Option(Pcre2Data* c) :
|
|
IpsOption(s_name, RULE_OPTION_TYPE_CONTENT)
|
|
{ config = c; }
|
|
|
|
- ~PcreOption() override;
|
|
+ ~Pcre2Option() override;
|
|
|
|
uint32_t hash() const override;
|
|
bool operator==(const IpsOption&) const override;
|
|
@@ -446,17 +446,17 @@ public:
|
|
EvalStatus eval(Cursor&, Packet*) override;
|
|
bool retry(Cursor&, const Cursor&) override;
|
|
|
|
- PcreData* get_data()
|
|
+ Pcre2Data* get_data()
|
|
{ return config; }
|
|
|
|
- void set_data(PcreData* pcre)
|
|
+ void set_data(Pcre2Data* pcre)
|
|
{ config = pcre; }
|
|
|
|
private:
|
|
- PcreData* config;
|
|
+ Pcre2Data* config;
|
|
};
|
|
|
|
-PcreOption::~PcreOption()
|
|
+Pcre2Option::~Pcre2Option()
|
|
{
|
|
if ( !config )
|
|
return;
|
|
@@ -464,21 +464,16 @@ PcreOption::~PcreOption()
|
|
if ( config->expression )
|
|
snort_free(config->expression);
|
|
|
|
- if ( config->pe )
|
|
- {
|
|
- if ( config->free_pe )
|
|
- snort_free(config->pe);
|
|
- else
|
|
- pcre_release(config->pe);
|
|
- }
|
|
+ if ( config->match_context )
|
|
+ pcre2_match_context_free(config->match_context);
|
|
|
|
if ( config->re )
|
|
- free(config->re); // external allocation
|
|
+ pcre2_code_free(config->re); // external allocation
|
|
|
|
snort_free(config);
|
|
}
|
|
|
|
-uint32_t PcreOption::hash() const
|
|
+uint32_t Pcre2Option::hash() const
|
|
{
|
|
uint32_t a = 0, b = 0, c = 0;
|
|
int expression_len = strlen(config->expression);
|
|
@@ -532,14 +527,14 @@ uint32_t PcreOption::hash() const
|
|
return c;
|
|
}
|
|
|
|
-bool PcreOption::operator==(const IpsOption& ips) const
|
|
+bool Pcre2Option::operator==(const IpsOption& ips) const
|
|
{
|
|
if ( !IpsOption::operator==(ips) )
|
|
return false;
|
|
|
|
- const PcreOption& rhs = (const PcreOption&)ips;
|
|
- PcreData* left = config;
|
|
- PcreData* right = rhs.config;
|
|
+ const Pcre2Option& rhs = (const Pcre2Option&)ips;
|
|
+ Pcre2Data* left = config;
|
|
+ Pcre2Data* right = rhs.config;
|
|
|
|
if (( strcmp(left->expression, right->expression) == 0) &&
|
|
( left->options == right->options))
|
|
@@ -550,13 +545,13 @@ bool PcreOption::operator==(const IpsOpt
|
|
return false;
|
|
}
|
|
|
|
-IpsOption::EvalStatus PcreOption::eval(Cursor& c, Packet* p)
|
|
+IpsOption::EvalStatus Pcre2Option::eval(Cursor& c, Packet* p)
|
|
{
|
|
// cppcheck-suppress unreadVariable
|
|
- RuleProfile profile(pcrePerfStats);
|
|
+ RuleProfile profile(pcre2PerfStats);
|
|
|
|
- // short circuit this for testing pcre performance impact
|
|
- if ( p->context->conf->no_pcre() )
|
|
+ // short circuit this for testing pcre2 performance impact
|
|
+ if ( p->context->conf->no_pcre2() )
|
|
return NO_MATCH;
|
|
|
|
unsigned pos = c.get_delta();
|
|
@@ -570,7 +565,7 @@ IpsOption::EvalStatus PcreOption::eval(C
|
|
|
|
int found_offset = -1; // where is the ending location of the pattern
|
|
|
|
- if ( pcre_search(p, config, c.buffer()+adj, c.size()-adj, pos, found_offset) )
|
|
+ if ( pcre2_search(p, config, c.buffer()+adj, c.size()-adj, pos, found_offset) )
|
|
{
|
|
if ( found_offset > 0 )
|
|
{
|
|
@@ -585,17 +580,17 @@ IpsOption::EvalStatus PcreOption::eval(C
|
|
}
|
|
|
|
// we always advance by found_offset so no adjustments to cursor are done
|
|
-// here; note also that this means relative pcre matches on overlapping
|
|
+// here; note also that this means relative pcre2 matches on overlapping
|
|
// patterns won't work. given the test pattern "ABABACD":
|
|
//
|
|
// ( sid:1; content:"ABA"; content:"C"; within:1; )
|
|
-// ( sid:2; pcre:"/ABA/"; content:"C"; within:1; )
|
|
+// ( sid:2; pcre2:"/ABA/"; content:"C"; within:1; )
|
|
//
|
|
// sid 1 will fire but sid 2 will NOT. this example is easily fixed by
|
|
-// using content, but more advanced pcre won't work for the relative /
|
|
+// using content, but more advanced pcre2 won't work for the relative /
|
|
// overlap case.
|
|
|
|
-bool PcreOption::retry(Cursor&, const Cursor&)
|
|
+bool Pcre2Option::retry(Cursor&, const Cursor&)
|
|
{
|
|
if ((config->options & (SNORT_PCRE_INVERT | SNORT_PCRE_ANCHORED)))
|
|
{
|
|
@@ -616,46 +611,43 @@ static const Parameter s_params[] =
|
|
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
|
|
};
|
|
|
|
-struct PcreStats
|
|
+struct Pcre2Stats
|
|
{
|
|
- PegCount pcre_rules;
|
|
+ PegCount pcre2_rules;
|
|
#ifdef HAVE_HYPERSCAN
|
|
- PegCount pcre_to_hyper;
|
|
+ PegCount pcre2_to_hyper;
|
|
#endif
|
|
- PegCount pcre_native;
|
|
- PegCount pcre_negated;
|
|
+ PegCount pcre2_native;
|
|
+ PegCount pcre2_negated;
|
|
};
|
|
|
|
const PegInfo pcre_pegs[] =
|
|
{
|
|
- { CountType::SUM, "pcre_rules", "total rules processed with pcre option" },
|
|
+ { CountType::SUM, "pcre2_rules", "total rules processed with pcre2 option" },
|
|
#ifdef HAVE_HYPERSCAN
|
|
- { CountType::SUM, "pcre_to_hyper", "total pcre rules by hyperscan engine" },
|
|
+ { CountType::SUM, "pcre2_to_hyper", "total pcre2 rules by hyperscan engine" },
|
|
#endif
|
|
- { CountType::SUM, "pcre_native", "total pcre rules compiled by pcre engine" },
|
|
- { CountType::SUM, "pcre_negated", "total pcre rules using negation syntax" },
|
|
+ { CountType::SUM, "pcre2_native", "total pcre2 rules compiled by pcre engine" },
|
|
+ { CountType::SUM, "pcre2_negated", "total pcre2 rules using negation syntax" },
|
|
{ CountType::END, nullptr, nullptr }
|
|
};
|
|
|
|
-PcreStats pcre_stats;
|
|
+Pcre2Stats pcre2_stats;
|
|
|
|
#define s_help \
|
|
- "rule option for matching payload data with pcre"
|
|
+ "rule option for matching payload data with pcre2"
|
|
|
|
-class PcreModule : public Module
|
|
+class Pcre2Module : public Module
|
|
{
|
|
public:
|
|
- PcreModule() : Module(s_name, s_help, s_params)
|
|
+ Pcre2Module() : Module(s_name, s_help, s_params)
|
|
{
|
|
data = nullptr;
|
|
- scratcher = new SimpleScratchAllocator(scratch_setup, scratch_cleanup);
|
|
- scratch_index = scratcher->get_id();
|
|
}
|
|
|
|
- ~PcreModule() override
|
|
+ ~Pcre2Module() override
|
|
{
|
|
delete data;
|
|
- delete scratcher;
|
|
}
|
|
|
|
#ifdef HAVE_HYPERSCAN
|
|
@@ -665,12 +657,12 @@ public:
|
|
bool end(const char*, int, SnortConfig*) override;
|
|
|
|
ProfileStats* get_profile() const override
|
|
- { return &pcrePerfStats; }
|
|
+ { return &pcre2PerfStats; }
|
|
|
|
const PegInfo* get_pegs() const override;
|
|
PegCount* get_counts() const override;
|
|
|
|
- PcreData* get_data();
|
|
+ Pcre2Data* get_data();
|
|
|
|
bool global_stats() const override
|
|
{ return true; }
|
|
@@ -682,31 +674,28 @@ public:
|
|
{ return mod_regex; }
|
|
|
|
private:
|
|
- PcreData* data;
|
|
+ Pcre2Data* data;
|
|
Module* mod_regex = nullptr;
|
|
std::string re;
|
|
-
|
|
- static bool scratch_setup(SnortConfig*);
|
|
- static void scratch_cleanup(SnortConfig*);
|
|
};
|
|
|
|
-PcreData* PcreModule::get_data()
|
|
+Pcre2Data* Pcre2Module::get_data()
|
|
{
|
|
- PcreData* tmp = data;
|
|
+ Pcre2Data* tmp = data;
|
|
data = nullptr;
|
|
return tmp;
|
|
}
|
|
|
|
-const PegInfo* PcreModule::get_pegs() const
|
|
+const PegInfo* Pcre2Module::get_pegs() const
|
|
{ return pcre_pegs; }
|
|
|
|
-PegCount* PcreModule::get_counts() const
|
|
-{ return (PegCount*)&pcre_stats; }
|
|
+PegCount* Pcre2Module::get_counts() const
|
|
+{ return (PegCount*)&pcre2_stats; }
|
|
|
|
#ifdef HAVE_HYPERSCAN
|
|
-bool PcreModule::begin(const char* name, int v, SnortConfig* sc)
|
|
+bool Pcre2Module::begin(const char* name, int v, SnortConfig* sc)
|
|
{
|
|
- if ( sc->pcre_to_regex )
|
|
+ if ( sc->pcre2_to_regex )
|
|
{
|
|
if ( !mod_regex )
|
|
mod_regex = ModuleManager::get_module(mod_regex_name);
|
|
@@ -718,7 +707,7 @@ bool PcreModule::begin(const char* name,
|
|
}
|
|
#endif
|
|
|
|
-bool PcreModule::set(const char* name, Value& v, SnortConfig* sc)
|
|
+bool Pcre2Module::set(const char* name, Value& v, SnortConfig* sc)
|
|
{
|
|
assert(v.is("~re"));
|
|
re = v.get_string();
|
|
@@ -729,50 +718,28 @@ bool PcreModule::set(const char* name, V
|
|
return true;
|
|
}
|
|
|
|
-bool PcreModule::end(const char* name, int v, SnortConfig* sc)
|
|
+bool Pcre2Module::end(const char* name, int v, SnortConfig* sc)
|
|
{
|
|
if( mod_regex )
|
|
mod_regex = mod_regex->end(name, v, sc) ? mod_regex : nullptr;
|
|
|
|
if ( !mod_regex )
|
|
{
|
|
- data = (PcreData*)snort_calloc(sizeof(*data));
|
|
- pcre_parse(sc, re.c_str(), data);
|
|
+ data = (Pcre2Data*)snort_calloc(sizeof(*data));
|
|
+ pcre2_parse(sc, re.c_str(), data);
|
|
}
|
|
|
|
- return true;
|
|
-}
|
|
-
|
|
-bool PcreModule::scratch_setup(SnortConfig* sc)
|
|
-{
|
|
- if ( s_ovector_max < 0 )
|
|
- return false;
|
|
-
|
|
// The pcre_fullinfo() 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
|
|
// by the whole pattern is 3(n+1).
|
|
-
|
|
- sc->pcre_ovector_size = 3 * (s_ovector_max + 1);
|
|
- s_ovector_max = -1;
|
|
-
|
|
- for ( unsigned i = 0; i < sc->num_slots; ++i )
|
|
- {
|
|
- std::vector<void *>& ss = sc->state[i];
|
|
- ss[scratch_index] = snort_calloc(sc->pcre_ovector_size, sizeof(int));
|
|
+ if ( s_ovector_max >= 0 ) {
|
|
+ sc->pcre2_ovector_size = 3 * (s_ovector_max + 1);
|
|
+ s_ovector_max = -1;
|
|
}
|
|
- return true;
|
|
-}
|
|
|
|
-void PcreModule::scratch_cleanup(SnortConfig* sc)
|
|
-{
|
|
- for ( unsigned i = 0; i < sc->num_slots; ++i )
|
|
- {
|
|
- std::vector<void *>& ss = sc->state[i];
|
|
- snort_free(ss[scratch_index]);
|
|
- ss[scratch_index] = nullptr;
|
|
- }
|
|
+ return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
@@ -780,21 +747,21 @@ void PcreModule::scratch_cleanup(SnortCo
|
|
//-------------------------------------------------------------------------
|
|
|
|
static Module* mod_ctor()
|
|
-{ return new PcreModule; }
|
|
+{ return new Pcre2Module; }
|
|
|
|
static void mod_dtor(Module* m)
|
|
{ delete m; }
|
|
|
|
-static IpsOption* pcre_ctor(Module* p, OptTreeNode* otn)
|
|
+static IpsOption* pcre2_ctor(Module* p, OptTreeNode* otn)
|
|
{
|
|
- pcre_stats.pcre_rules++;
|
|
- PcreModule* m = (PcreModule*)p;
|
|
+ pcre2_stats.pcre2_rules++;
|
|
+ Pcre2Module* m = (Pcre2Module*)p;
|
|
|
|
#ifdef HAVE_HYPERSCAN
|
|
Module* mod_regex = m->get_mod_regex();
|
|
if ( mod_regex )
|
|
{
|
|
- pcre_stats.pcre_to_hyper++;
|
|
+ pcre2_stats.pcre2_to_hyper++;
|
|
const IpsApi* opt_api = IpsManager::get_option_api(mod_regex_name);
|
|
return opt_api->ctor(mod_regex, otn);
|
|
}
|
|
@@ -803,16 +770,16 @@ static IpsOption* pcre_ctor(Module* p, O
|
|
UNUSED(otn);
|
|
#endif
|
|
{
|
|
- pcre_stats.pcre_native++;
|
|
- PcreData* d = m->get_data();
|
|
- return new PcreOption(d);
|
|
+ pcre2_stats.pcre2_native++;
|
|
+ Pcre2Data* d = m->get_data();
|
|
+ return new Pcre2Option(d);
|
|
}
|
|
}
|
|
|
|
-static void pcre_dtor(IpsOption* p)
|
|
+static void pcre2_dtor(IpsOption* p)
|
|
{ delete p; }
|
|
|
|
-static const IpsApi pcre_api =
|
|
+static const IpsApi pcre2_api =
|
|
{
|
|
{
|
|
PT_IPS_OPTION,
|
|
@@ -832,17 +799,17 @@ static const IpsApi pcre_api =
|
|
nullptr,
|
|
nullptr,
|
|
nullptr,
|
|
- pcre_ctor,
|
|
- pcre_dtor,
|
|
+ pcre2_ctor,
|
|
+ pcre2_dtor,
|
|
nullptr
|
|
};
|
|
|
|
#ifdef BUILDING_SO
|
|
SO_PUBLIC const BaseApi* snort_plugins[] =
|
|
#else
|
|
-const BaseApi* ips_pcre[] =
|
|
+const BaseApi* ips_pcre2[] =
|
|
#endif
|
|
{
|
|
- &pcre_api.base,
|
|
+ &pcre2_api.base,
|
|
nullptr
|
|
};
|
|
--- a/src/main/shell.cc
|
|
+++ b/src/main/shell.cc
|
|
@@ -29,7 +29,8 @@
|
|
#include <fstream>
|
|
#include <openssl/crypto.h>
|
|
#include <pcap.h>
|
|
-#include <pcre.h>
|
|
+#define PCRE2_CODE_UNIT_WIDTH 8
|
|
+#include <pcre2.h>
|
|
#include <stdexcept>
|
|
#include <vector>
|
|
#include <zlib.h>
|
|
@@ -138,13 +139,17 @@ static void install_version_strings(lua_
|
|
|
|
static void install_dependencies_strings(Shell* sh, lua_State* L)
|
|
{
|
|
+
|
|
assert(dep_versions[0]);
|
|
|
|
+ const char pcre2_version[32] = { 0 };
|
|
std::vector<const char*> vs;
|
|
const char* ljv = LUAJIT_VERSION;
|
|
const char* osv = OpenSSL_version(SSLEAY_VERSION);
|
|
const char* lpv = pcap_lib_version();
|
|
|
|
+ pcre2_config(PCRE2_CONFIG_VERSION, (PCRE2_UCHAR8 *)pcre2_version);
|
|
+
|
|
while (*ljv and !isdigit(*ljv))
|
|
++ljv;
|
|
while (*osv and !isdigit(*osv))
|
|
@@ -156,7 +161,7 @@ static void install_dependencies_strings
|
|
vs.push_back(ljv);
|
|
vs.push_back(osv);
|
|
vs.push_back(lpv);
|
|
- vs.push_back(pcre_version());
|
|
+ vs.push_back(pcre2_version);
|
|
vs.push_back(zlib_version);
|
|
#ifdef HAVE_HYPERSCAN
|
|
vs.push_back(hs_version());
|
|
--- a/src/main/snort_config.h
|
|
+++ b/src/main/snort_config.h
|
|
@@ -60,7 +60,7 @@ enum RunFlag
|
|
RUN_FLAG__PCAP_SHOW = 0x00001000,
|
|
RUN_FLAG__SHOW_FILE_CODES = 0x00002000,
|
|
RUN_FLAG__PAUSE = 0x00004000,
|
|
- RUN_FLAG__NO_PCRE = 0x00008000,
|
|
+ RUN_FLAG__NO_PCRE2 = 0x00008000,
|
|
|
|
RUN_FLAG__DUMP_RULE_STATE = 0x00010000,
|
|
RUN_FLAG__DUMP_RULE_DEPS = 0x00020000,
|
|
@@ -214,13 +214,13 @@ public:
|
|
|
|
//------------------------------------------------------
|
|
// detection module stuff
|
|
- // FIXIT-L pcre_match_limit* are interdependent
|
|
+ // FIXIT-L pcre2_match_limit* are interdependent
|
|
// somehow a packet thread needs a much lower setting
|
|
- long int pcre_match_limit = 1500;
|
|
- long int pcre_match_limit_recursion = 1500;
|
|
+ long int pcre2_match_limit = 1500;
|
|
+ long int pcre2_match_limit_recursion = 1500;
|
|
|
|
- int pcre_ovector_size = 0;
|
|
- bool pcre_override = true;
|
|
+ int pcre2_ovector_size = 0;
|
|
+ bool pcre2_override = true;
|
|
|
|
uint32_t run_flags = 0;
|
|
|
|
@@ -228,7 +228,7 @@ public:
|
|
unsigned offload_threads = 0; // disabled
|
|
|
|
bool hyperscan_literals = false;
|
|
- bool pcre_to_regex = false;
|
|
+ bool pcre2_to_regex = false;
|
|
|
|
bool global_rule_state = false;
|
|
bool global_default_rule_state = true;
|
|
@@ -600,8 +600,8 @@ public:
|
|
bool alert_before_pass() const
|
|
{ return run_flags & RUN_FLAG__ALERT_BEFORE_PASS; }
|
|
|
|
- bool no_pcre() const
|
|
- { return run_flags & RUN_FLAG__NO_PCRE; }
|
|
+ bool no_pcre2() const
|
|
+ { return run_flags & RUN_FLAG__NO_PCRE2; }
|
|
|
|
bool conf_error_out() const
|
|
{ return run_flags & RUN_FLAG__CONF_ERROR_OUT; }
|
|
@@ -616,11 +616,11 @@ public:
|
|
uint8_t new_ttl() const
|
|
{ return get_network_policy()->new_ttl; }
|
|
|
|
- long int get_pcre_match_limit() const
|
|
- { return pcre_match_limit; }
|
|
+ long int get_pcre2_match_limit() const
|
|
+ { return pcre2_match_limit; }
|
|
|
|
- long int get_pcre_match_limit_recursion() const
|
|
- { return pcre_match_limit_recursion; }
|
|
+ long int get_pcre2_match_limit_recursion() const
|
|
+ { return pcre2_match_limit_recursion; }
|
|
|
|
const ProfilerConfig* get_profiler() const
|
|
{ return profiler; }
|
|
--- a/src/network_inspectors/appid/lua_detector_api.cc
|
|
+++ b/src/network_inspectors/appid/lua_detector_api.cc
|
|
@@ -25,7 +25,8 @@
|
|
|
|
#include "lua_detector_api.h"
|
|
#include <lua.hpp>
|
|
-#include <pcre.h>
|
|
+#define PCRE2_CODE_UNIT_WIDTH 8
|
|
+#include <pcre2.h>
|
|
#include <unordered_map>
|
|
|
|
#include "detection/fp_config.h"
|
|
@@ -714,7 +715,7 @@ static int detector_get_packet_direction
|
|
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.
|
|
@@ -723,41 +724,50 @@ static int detector_get_packet_direction
|
|
* @return matchedStrings/stack - matched strings are pushed on stack starting with group 0.
|
|
* There may be 0 or more strings.
|
|
*/
|
|
-static int detector_get_pcre_groups(lua_State* L)
|
|
+static int detector_get_pcre2_groups(lua_State* L)
|
|
{
|
|
auto& ud = *UserData<LuaObject>::check(L, DETECTOR, 1);
|
|
// Verify detector user data and that we are in packet context
|
|
LuaStateDescriptor* lsd = ud->validate_lua_state(true);
|
|
|
|
- int ovector[OVECCOUNT];
|
|
- const char* error;
|
|
- int erroffset;
|
|
+ PCRE2_SIZE* ovector;
|
|
+ pcre2_match_data* match_data;
|
|
+ PCRE2_UCHAR error[128];
|
|
+ PCRE2_SIZE erroffset;
|
|
+ int errorcode;
|
|
|
|
const char* pattern = lua_tostring(L, 2);
|
|
unsigned int offset = lua_tonumber(L, 3); /*offset can be zero, no check necessary. */
|
|
|
|
/*compile the regular expression pattern, and handle errors */
|
|
- pcre* re = pcre_compile(pattern, // the pattern
|
|
- PCRE_DOTALL, // default options - dot matches all inc \n
|
|
- &error, // for error message
|
|
- &erroffset, // for error offset
|
|
- nullptr); // use default character tables
|
|
+ pcre2_code* re = pcre2_compile((PCRE2_SPTR)pattern, // the pattern
|
|
+ PCRE2_ZERO_TERMINATED, // assume zero terminated strings
|
|
+ PCRE2_DOTALL, // default options - dot matches all inc \n
|
|
+ &errorcode, // for error message
|
|
+ &erroffset, // for error offset
|
|
+ nullptr); // use default character tables
|
|
|
|
if (re == nullptr)
|
|
{
|
|
- appid_log(lsd->ldp.pkt, TRACE_ERROR_LEVEL, "PCRE compilation failed at offset %d: %s\n", erroffset, error);
|
|
+ pcre2_get_error_message(errorcode, error, 128);
|
|
+ appid_log(lsd->ldp.pkt, TRACE_ERROR_LEVEL, "PCRE2 compilation failed at offset %d: %s\n", erroffset, error);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ match_data = pcre2_match_data_create(OVECCOUNT, NULL);
|
|
+ if (match_data == nullptr) {
|
|
+ appid_log(lsd->ldp.pkt, TRACE_ERROR_LEVEL, "PCRE2 failed to allocate mem for match_data\n");
|
|
return 0;
|
|
}
|
|
|
|
/*pattern match against the subject string. */
|
|
- int rc = pcre_exec(re, // compiled pattern
|
|
- nullptr, // no extra data
|
|
- (const char*)lsd->ldp.data, // subject string
|
|
- lsd->ldp.size, // length of the subject
|
|
- offset, // offset 0
|
|
- 0, // default options
|
|
- ovector, // output vector for substring information
|
|
- OVECCOUNT); // number of elements in the output vector
|
|
+ int rc = pcre2_match(re, // compiled pattern
|
|
+ (PCRE2_SPTR)lsd->ldp.data, // subject string
|
|
+ (PCRE2_SIZE)lsd->ldp.size, // length of the subject
|
|
+ (PCRE2_SIZE)offset, // offset 0
|
|
+ 0, // default options
|
|
+ match_data, // match data for match results
|
|
+ NULL); // no match context
|
|
|
|
if (rc >= 0)
|
|
{
|
|
@@ -771,10 +781,11 @@ static int detector_get_pcre_groups(lua_
|
|
if (!lua_checkstack(L, rc))
|
|
{
|
|
appid_log(lsd->ldp.pkt, TRACE_WARNING_LEVEL, "Cannot grow Lua stack by %d slots to hold "
|
|
- "PCRE matches\n", rc);
|
|
+ "PCRE2 matches\n", rc);
|
|
return 0;
|
|
}
|
|
|
|
+ ovector = pcre2_get_ovector_pointer(match_data);
|
|
for (int i = 0; i < rc; i++)
|
|
{
|
|
lua_pushlstring(L, (const char*)lsd->ldp.data + ovector[2*i], ovector[2*i+1] -
|
|
@@ -784,12 +795,13 @@ static int detector_get_pcre_groups(lua_
|
|
else
|
|
{
|
|
// log errors except no matches
|
|
- if (rc != PCRE_ERROR_NOMATCH)
|
|
- appid_log(lsd->ldp.pkt, TRACE_WARNING_LEVEL, "PCRE regular expression group match failed. rc: %d\n", rc);
|
|
+ if (rc != PCRE2_ERROR_NOMATCH)
|
|
+ appid_log(lsd->ldp.pkt, TRACE_WARNING_LEVEL, "PCRE2 regular expression group match failed. rc: %d\n", rc);
|
|
rc = 0;
|
|
}
|
|
|
|
- pcre_free(re);
|
|
+ pcre2_match_data_free(match_data);
|
|
+ pcre2_code_free(re);
|
|
return rc;
|
|
}
|
|
|
|
@@ -3229,7 +3241,7 @@ static const luaL_Reg detector_methods[]
|
|
{ "getPacketSize", detector_get_packet_size },
|
|
{ "getPacketDir", detector_get_packet_direction },
|
|
{ "matchSimplePattern", detector_memcmp },
|
|
- { "getPcreGroups", detector_get_pcre_groups },
|
|
+ { "getPcreGroups", detector_get_pcre2_groups },
|
|
{ "getL4Protocol", detector_get_protocol_type },
|
|
{ "getPktSrcAddr", detector_get_packet_src_addr },
|
|
{ "getPktDstAddr", detector_get_packet_dst_addr },
|
|
--- a/src/parser/parse_rule.cc
|
|
+++ b/src/parser/parse_rule.cc
|
|
@@ -911,10 +911,10 @@ void parse_rule_dir(SnortConfig*, const
|
|
ParseError("illegal direction specifier: %s", s);
|
|
}
|
|
|
|
-// Values of the rule options "pcre", "regex" and "sd_pattern" are already escaped
|
|
+// Values of the rule options "pcre2", "regex" and "sd_pattern" are already escaped
|
|
// They are not unescaped during the rule parsing
|
|
static bool is_already_escaped(const std::string& opt_key)
|
|
-{ return opt_key == "pcre" or opt_key == "regex" or opt_key == "sd_pattern"; }
|
|
+{ return opt_key == "pcre2" or opt_key == "regex" or opt_key == "sd_pattern"; }
|
|
|
|
static std::string escape(const std::string& s)
|
|
{
|
|
--- a/src/parser/parse_stream.cc
|
|
+++ b/src/parser/parse_stream.cc
|
|
@@ -603,7 +603,7 @@ static bool exec(
|
|
// that individual rule options can do whatever
|
|
static int get_escape(const string& s)
|
|
{
|
|
- if ( s == "pcre" )
|
|
+ if ( s == "pcre2" )
|
|
return 0; // no escape, option goes to ;
|
|
|
|
else if ( s == "regex" || s == "sd_pattern" )
|
|
--- a/src/search_engines/test/hyperscan_test.cc
|
|
+++ b/src/search_engines/test/hyperscan_test.cc
|
|
@@ -223,7 +223,7 @@ TEST(mpse_hs_match, regex)
|
|
CHECK(hits == 3);
|
|
}
|
|
|
|
-TEST(mpse_hs_match, pcre)
|
|
+TEST(mpse_hs_match, pcre2)
|
|
{
|
|
Mpse::PatternDescriptor desc;
|
|
|
|
--- a/src/utils/stats.cc
|
|
+++ b/src/utils/stats.cc
|
|
@@ -227,9 +227,9 @@ const PegInfo pc_names[] =
|
|
{ CountType::SUM, "offload_fallback", "fast pattern offload search fallback attempts" },
|
|
{ CountType::SUM, "offload_failures", "fast pattern offload search failures" },
|
|
{ CountType::SUM, "offload_suspends", "fast pattern search suspends due to offload context chains" },
|
|
- { CountType::SUM, "pcre_match_limit", "total number of times pcre hit the match limit" },
|
|
- { CountType::SUM, "pcre_recursion_limit", "total number of times pcre hit the recursion limit" },
|
|
- { CountType::SUM, "pcre_error", "total number of times pcre returns error" },
|
|
+ { CountType::SUM, "pcre2_match_limit", "total number of times pcre2 hit the match limit" },
|
|
+ { CountType::SUM, "pcre2_recursion_limit", "total number of times pcre2 hit the recursion limit" },
|
|
+ { CountType::SUM, "pcre2_error", "total number of times pcre2 returns error" },
|
|
{ CountType::SUM, "cont_creations", "total number of continuations created" },
|
|
{ CountType::SUM, "cont_recalls", "total number of continuations recalled" },
|
|
{ CountType::SUM, "cont_flows", "total number of flows using continuation" },
|
|
--- a/src/utils/stats.h
|
|
+++ b/src/utils/stats.h
|
|
@@ -60,9 +60,9 @@ struct PacketCount
|
|
PegCount offload_fallback;
|
|
PegCount offload_failures;
|
|
PegCount offload_suspends;
|
|
- PegCount pcre_match_limit;
|
|
- PegCount pcre_recursion_limit;
|
|
- PegCount pcre_error;
|
|
+ PegCount pcre2_match_limit;
|
|
+ PegCount pcre2_recursion_limit;
|
|
+ PegCount pcre2_error;
|
|
PegCount cont_creations;
|
|
PegCount cont_recalls;
|
|
PegCount cont_flows;
|
|
--- a/src/utils/util.cc
|
|
+++ b/src/utils/util.cc
|
|
@@ -30,7 +30,8 @@
|
|
#include <netdb.h>
|
|
#include <openssl/crypto.h>
|
|
#include <pcap.h>
|
|
-#include <pcre.h>
|
|
+#define PCRE2_CODE_UNIT_WIDTH 8
|
|
+#include <pcre2.h>
|
|
#include <pwd.h>
|
|
#include <sys/file.h>
|
|
#include <sys/resource.h>
|
|
@@ -105,10 +106,13 @@ void StoreSnortInfoStrings()
|
|
|
|
int DisplayBanner()
|
|
{
|
|
+ PCRE2_UCHAR pcre2_version[32];
|
|
const char* ljv = LUAJIT_VERSION;
|
|
while ( *ljv && !isdigit(*ljv) )
|
|
++ljv;
|
|
|
|
+ pcre2_config(PCRE2_CONFIG_VERSION, pcre2_version);
|
|
+
|
|
LogMessage("\n");
|
|
LogMessage(" ,,_ -*> Snort++ <*-\n");
|
|
#ifdef BUILD
|
|
@@ -125,7 +129,7 @@ int DisplayBanner()
|
|
LogMessage(" Using LuaJIT version %s\n", ljv);
|
|
LogMessage(" Using %s\n", OpenSSL_version(SSLEAY_VERSION));
|
|
LogMessage(" Using %s\n", pcap_lib_version());
|
|
- LogMessage(" Using PCRE version %s\n", pcre_version());
|
|
+ LogMessage(" Using PCRE version %s\n", pcre2_version);
|
|
LogMessage(" Using ZLIB version %s\n", zlib_version);
|
|
#ifdef HAVE_HYPERSCAN
|
|
LogMessage(" Using Hyperscan version %s\n", hs_version());
|
|
--- a/tools/snort2lua/config_states/config_api.cc
|
|
+++ b/tools/snort2lua/config_states/config_api.cc
|
|
@@ -105,13 +105,13 @@ extern const ConvertMap* min_ttl_map;
|
|
extern const ConvertMap* na_policy_mode_map;
|
|
extern const ConvertMap* new_ttl_map;
|
|
extern const ConvertMap* nolog_map;
|
|
-extern const ConvertMap* nopcre_map;
|
|
+extern const ConvertMap* nopcre2_map;
|
|
extern const ConvertMap* no_promisc_map;
|
|
extern const ConvertMap* obfuscate_map;
|
|
extern const ConvertMap* order_map;
|
|
extern const ConvertMap* paf_max_map;
|
|
-extern const ConvertMap* pcre_match_limit_map;
|
|
-extern const ConvertMap* pcre_match_limit_recursion_map;
|
|
+extern const ConvertMap* pcre2_match_limit_map;
|
|
+extern const ConvertMap* pcre2_match_limit_recursion_map;
|
|
extern const ConvertMap* pkt_count_map;
|
|
extern const ConvertMap* ppm_map;
|
|
extern const ConvertMap* policy_id_map;
|
|
@@ -224,13 +224,13 @@ const std::vector<const ConvertMap*> con
|
|
na_policy_mode_map,
|
|
new_ttl_map,
|
|
nolog_map,
|
|
- nopcre_map,
|
|
+ nopcre2_map,
|
|
no_promisc_map,
|
|
obfuscate_map,
|
|
order_map,
|
|
paf_max_map,
|
|
- pcre_match_limit_map,
|
|
- pcre_match_limit_recursion_map,
|
|
+ pcre2_match_limit_map,
|
|
+ pcre2_match_limit_recursion_map,
|
|
pkt_count_map,
|
|
ppm_map,
|
|
policy_id_map,
|
|
--- a/tools/snort2lua/config_states/config_no_option.cc
|
|
+++ b/tools/snort2lua/config_states/config_no_option.cc
|
|
@@ -250,18 +250,18 @@ static const ConvertMap enable_mpls_over
|
|
const ConvertMap* enable_mpls_overlapping_ip_map = &enable_mpls_overlapping_ip_api;
|
|
|
|
/*************************************************
|
|
- ******************** nopcre *******************
|
|
+ ******************** nopcre2 *******************
|
|
*************************************************/
|
|
|
|
-static const std::string nopcre = "nopcre";
|
|
-static const std::string pcre_enable = "pcre_enable";
|
|
-static const ConvertMap nopcre_api =
|
|
+static const std::string nopcre2 = "nopcre2";
|
|
+static const std::string pcre2_enable = "pcre2_enable";
|
|
+static const ConvertMap nopcre2_api =
|
|
{
|
|
- nopcre,
|
|
- config_false_no_opt_ctor<& nopcre, & detection, & pcre_enable>
|
|
+ nopcre2,
|
|
+ config_false_no_opt_ctor<& nopcre2, & detection, & pcre2_enable>
|
|
};
|
|
|
|
-const ConvertMap* nopcre_map = &nopcre_api;
|
|
+const ConvertMap* nopcre2_map = &nopcre2_api;
|
|
|
|
/*************************************************
|
|
****************** obfuscate ******************
|
|
--- a/tools/snort2lua/config_states/config_one_int_option.cc
|
|
+++ b/tools/snort2lua/config_states/config_one_int_option.cc
|
|
@@ -217,30 +217,30 @@ static const ConvertMap new_ttl_api =
|
|
const ConvertMap* new_ttl_map = &new_ttl_api;
|
|
|
|
/*************************************************
|
|
- ************** pcre_match_limit **************
|
|
+ ************** pcre2_match_limit **************
|
|
*************************************************/
|
|
|
|
-static const std::string pcre_match_limit = "pcre_match_limit";
|
|
-static const ConvertMap pcre_match_limit_api =
|
|
+static const std::string pcre2_match_limit = "pcre2_match_limit";
|
|
+static const ConvertMap pcre2_match_limit_api =
|
|
{
|
|
- pcre_match_limit,
|
|
- config_int_ctor<& pcre_match_limit, & detection>,
|
|
+ pcre2_match_limit,
|
|
+ config_int_ctor<& pcre2_match_limit, & detection>,
|
|
};
|
|
|
|
-const ConvertMap* pcre_match_limit_map = &pcre_match_limit_api;
|
|
+const ConvertMap* pcre2_match_limit_map = &pcre2_match_limit_api;
|
|
|
|
/**************************************************
|
|
- ********** pcre_match_limit_recursion **********
|
|
+ ********** pcre2_match_limit_recursion **********
|
|
**************************************************/
|
|
|
|
-static const std::string pcre_match_limit_recursion = "pcre_match_limit_recursion";
|
|
-static const ConvertMap pcre_match_limit_recursion_api =
|
|
+static const std::string pcre2_match_limit_recursion = "pcre_match_limit_recursion";
|
|
+static const ConvertMap pcre2_match_limit_recursion_api =
|
|
{
|
|
- pcre_match_limit_recursion,
|
|
- config_int_ctor<& pcre_match_limit_recursion, & detection>,
|
|
+ pcre2_match_limit_recursion,
|
|
+ config_int_ctor<& pcre2_match_limit_recursion, & detection>,
|
|
};
|
|
|
|
-const ConvertMap* pcre_match_limit_recursion_map = &pcre_match_limit_recursion_api;
|
|
+const ConvertMap* pcre2_match_limit_recursion_map = &pcre2_match_limit_recursion_api;
|
|
|
|
/*************************************************
|
|
****************** pkt_count *****************
|
|
--- a/tools/snort2lua/rule_states/CMakeLists.txt
|
|
+++ b/tools/snort2lua/rule_states/CMakeLists.txt
|
|
@@ -12,7 +12,7 @@ add_library( rule_states OBJECT
|
|
rule_http_encode.cc
|
|
rule_isdataat.cc
|
|
rule_metadata.cc
|
|
- rule_pcre.cc
|
|
+ rule_pcre2.cc
|
|
rule_react.cc
|
|
rule_reference.cc
|
|
rule_replace.cc
|
|
--- a/tools/snort2lua/rule_states/rule_api.cc
|
|
+++ b/tools/snort2lua/rule_states/rule_api.cc
|
|
@@ -75,7 +75,7 @@ extern const ConvertMap* modbus_data_map
|
|
extern const ConvertMap* modbus_func_map;
|
|
extern const ConvertMap* modbus_unit_map;
|
|
extern const ConvertMap* msg_map;
|
|
-extern const ConvertMap* pcre_map;
|
|
+extern const ConvertMap* pcre2_map;
|
|
extern const ConvertMap* pkt_data_map;
|
|
extern const ConvertMap* priority_map;
|
|
extern const ConvertMap* protected_content_map;
|
|
@@ -159,7 +159,7 @@ const std::vector<const ConvertMap*> rul
|
|
modbus_func_map,
|
|
modbus_unit_map,
|
|
msg_map,
|
|
- pcre_map,
|
|
+ pcre2_map,
|
|
pkt_data_map,
|
|
priority_map,
|
|
protected_content_map,
|
|
--- a/tools/snort2lua/rule_states/rule_pcre.cc
|
|
+++ /dev/null
|
|
@@ -1,159 +0,0 @@
|
|
-//--------------------------------------------------------------------------
|
|
-// Copyright (C) 2014-2024 Cisco and/or its affiliates. All rights reserved.
|
|
-//
|
|
-// This program is free software; you can redistribute it and/or modify it
|
|
-// under the terms of the GNU General Public License Version 2 as published
|
|
-// by the Free Software Foundation. You may not use, modify or distribute
|
|
-// this program under any other version of the GNU General Public License.
|
|
-//
|
|
-// This program is distributed in the hope that it will be useful, but
|
|
-// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
-// General Public License for more details.
|
|
-//
|
|
-// You should have received a copy of the GNU General Public License along
|
|
-// with this program; if not, write to the Free Software Foundation, Inc.,
|
|
-// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
-//--------------------------------------------------------------------------
|
|
-// rule_pcre.cc author Josh Rosenbaum <jrosenba@cisco.com>
|
|
-
|
|
-#include <sstream>
|
|
-#include <vector>
|
|
-
|
|
-#include "conversion_state.h"
|
|
-#include "helpers/converter.h"
|
|
-#include "helpers/s2l_util.h"
|
|
-#include "rule_api.h"
|
|
-
|
|
-namespace rules
|
|
-{
|
|
-namespace
|
|
-{
|
|
-class Pcre : public ConversionState
|
|
-{
|
|
-public:
|
|
- Pcre(Converter& c) : ConversionState(c) { }
|
|
- bool convert(std::istringstream& data) override;
|
|
-};
|
|
-} // namespace
|
|
-
|
|
-bool Pcre::convert(std::istringstream& data_stream)
|
|
-{
|
|
- bool sticky_buffer_set = false;
|
|
- std::string buffer = "pkt_data";
|
|
-
|
|
- char delim = '/';
|
|
- std::string pcre_str = util::get_rule_option_args(data_stream);
|
|
- std::string pattern;
|
|
- std::string new_opts;
|
|
- std::string options;
|
|
-
|
|
- if (pcre_str.front() == '!')
|
|
- {
|
|
- pattern += "!";
|
|
- pcre_str.erase(pcre_str.begin());
|
|
- }
|
|
-
|
|
- if (pcre_str.front() != '"' || pcre_str.back() != '"')
|
|
- {
|
|
- rule_api.bad_rule(data_stream, "pattern must be enclosed in \"");
|
|
- return set_next_rule_state(data_stream);
|
|
- }
|
|
-
|
|
- pcre_str.erase(pcre_str.begin());
|
|
- pattern += '"';
|
|
-
|
|
- if (pcre_str.front() == 'm')
|
|
- {
|
|
- pcre_str.erase(pcre_str.begin());
|
|
- pattern += 'm';
|
|
- delim = pcre_str.front();
|
|
- }
|
|
-
|
|
- const std::size_t pattern_end = pcre_str.rfind(delim);
|
|
- if ((pcre_str.front() != delim) || (pattern_end == 0))
|
|
- {
|
|
- std::string tmp = "Regex must be enclosed in delim '";
|
|
- tmp.append(delim, 1);
|
|
- rule_api.bad_rule(data_stream, tmp + "'");
|
|
- return set_next_rule_state(data_stream);
|
|
- }
|
|
-
|
|
- pattern += pcre_str.substr(0, pattern_end + 1);
|
|
- options = pcre_str.substr(pattern_end + 1, std::string::npos);
|
|
- new_opts = "";
|
|
-
|
|
- for (char c : options )
|
|
- {
|
|
- std::string sticky_buffer = std::string(); // empty string
|
|
-
|
|
- switch (c)
|
|
- {
|
|
- case 'B': sticky_buffer = "raw_data"; break;
|
|
- case 'U': sticky_buffer = "http_uri"; break;
|
|
- case 'P': sticky_buffer = "pcre_P_option_body"; break;
|
|
- case 'H': sticky_buffer = "pcre_H_option_header"; break;
|
|
- case 'M': sticky_buffer = "http_method"; break;
|
|
- case 'C': sticky_buffer = "http_cookie"; break;
|
|
- case 'I': sticky_buffer = "http_raw_uri"; break;
|
|
- case 'D': sticky_buffer = "http_raw_header"; break;
|
|
- case 'K': sticky_buffer = "http_raw_cookie"; break;
|
|
- case 'S': sticky_buffer = "http_stat_code"; break;
|
|
- case 'Y': sticky_buffer = "http_stat_msg"; break;
|
|
- case 'i':
|
|
- case 's':
|
|
- case 'm':
|
|
- case 'x':
|
|
- case 'A':
|
|
- case 'E':
|
|
- case 'G':
|
|
- case 'O':
|
|
- case 'R':
|
|
- case '"': // end of reg_ex
|
|
- new_opts += c;
|
|
- break;
|
|
- default:
|
|
- {
|
|
- std::string dlt_opt = "unknown option - '";
|
|
- dlt_opt.append(1, c);
|
|
- dlt_opt += "'";
|
|
- rule_api.bad_rule(data_stream, dlt_opt);
|
|
- break;
|
|
- }
|
|
- }
|
|
-
|
|
- if (!sticky_buffer.empty())
|
|
- {
|
|
- buffer = sticky_buffer;
|
|
-
|
|
- if (sticky_buffer_set)
|
|
- rule_api.bad_rule(data_stream,
|
|
- "Two sticky buffers set for this regular expression!");
|
|
- else
|
|
- sticky_buffer_set = true;
|
|
- }
|
|
- }
|
|
-
|
|
- rule_api.add_option("pcre", pattern + new_opts);
|
|
-
|
|
- rule_api.set_curr_options_buffer(buffer);
|
|
-
|
|
- return set_next_rule_state(data_stream);
|
|
-}
|
|
-
|
|
-/**************************
|
|
- ******* A P I ***********
|
|
- **************************/
|
|
-
|
|
-static ConversionState* ctor(Converter& c)
|
|
-{ return new Pcre(c); }
|
|
-
|
|
-static const ConvertMap pcre_api =
|
|
-{
|
|
- "pcre",
|
|
- ctor,
|
|
-};
|
|
-
|
|
-const ConvertMap* pcre_map = &pcre_api;
|
|
-} // namespace rules
|
|
-
|
|
--- /dev/null
|
|
+++ b/tools/snort2lua/rule_states/rule_pcre2.cc
|
|
@@ -0,0 +1,159 @@
|
|
+//--------------------------------------------------------------------------
|
|
+// Copyright (C) 2014-2024 Cisco and/or its affiliates. All rights reserved.
|
|
+//
|
|
+// This program is free software; you can redistribute it and/or modify it
|
|
+// under the terms of the GNU General Public License Version 2 as published
|
|
+// by the Free Software Foundation. You may not use, modify or distribute
|
|
+// this program under any other version of the GNU General Public License.
|
|
+//
|
|
+// This program is distributed in the hope that it will be useful, but
|
|
+// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+// General Public License for more details.
|
|
+//
|
|
+// You should have received a copy of the GNU General Public License along
|
|
+// with this program; if not, write to the Free Software Foundation, Inc.,
|
|
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+//--------------------------------------------------------------------------
|
|
+// rule_pcre2.cc author Josh Rosenbaum <jrosenba@cisco.com>
|
|
+
|
|
+#include <sstream>
|
|
+#include <vector>
|
|
+
|
|
+#include "conversion_state.h"
|
|
+#include "helpers/converter.h"
|
|
+#include "helpers/s2l_util.h"
|
|
+#include "rule_api.h"
|
|
+
|
|
+namespace rules
|
|
+{
|
|
+namespace
|
|
+{
|
|
+class Pcre2 : public ConversionState
|
|
+{
|
|
+public:
|
|
+ Pcre2(Converter& c) : ConversionState(c) { }
|
|
+ bool convert(std::istringstream& data) override;
|
|
+};
|
|
+} // namespace
|
|
+
|
|
+bool Pcre2::convert(std::istringstream& data_stream)
|
|
+{
|
|
+ bool sticky_buffer_set = false;
|
|
+ std::string buffer = "pkt_data";
|
|
+
|
|
+ char delim = '/';
|
|
+ std::string pcre2_str = util::get_rule_option_args(data_stream);
|
|
+ std::string pattern;
|
|
+ std::string new_opts;
|
|
+ std::string options;
|
|
+
|
|
+ if (pcre2_str.front() == '!')
|
|
+ {
|
|
+ pattern += "!";
|
|
+ pcre2_str.erase(pcre2_str.begin());
|
|
+ }
|
|
+
|
|
+ if (pcre2_str.front() != '"' || pcre2_str.back() != '"')
|
|
+ {
|
|
+ rule_api.bad_rule(data_stream, "pattern must be enclosed in \"");
|
|
+ return set_next_rule_state(data_stream);
|
|
+ }
|
|
+
|
|
+ pcre2_str.erase(pcre2_str.begin());
|
|
+ pattern += '"';
|
|
+
|
|
+ if (pcre2_str.front() == 'm')
|
|
+ {
|
|
+ pcre2_str.erase(pcre2_str.begin());
|
|
+ pattern += 'm';
|
|
+ delim = pcre2_str.front();
|
|
+ }
|
|
+
|
|
+ const std::size_t pattern_end = pcre2_str.rfind(delim);
|
|
+ if ((pcre2_str.front() != delim) || (pattern_end == 0))
|
|
+ {
|
|
+ std::string tmp = "Regex must be enclosed in delim '";
|
|
+ tmp.append(delim, 1);
|
|
+ rule_api.bad_rule(data_stream, tmp + "'");
|
|
+ return set_next_rule_state(data_stream);
|
|
+ }
|
|
+
|
|
+ pattern += pcre2_str.substr(0, pattern_end + 1);
|
|
+ options = pcre2_str.substr(pattern_end + 1, std::string::npos);
|
|
+ new_opts = "";
|
|
+
|
|
+ for (char c : options )
|
|
+ {
|
|
+ std::string sticky_buffer = std::string(); // empty string
|
|
+
|
|
+ switch (c)
|
|
+ {
|
|
+ case 'B': sticky_buffer = "raw_data"; break;
|
|
+ case 'U': sticky_buffer = "http_uri"; break;
|
|
+ case 'P': sticky_buffer = "pcre_P_option_body"; break;
|
|
+ case 'H': sticky_buffer = "pcre_H_option_header"; break;
|
|
+ case 'M': sticky_buffer = "http_method"; break;
|
|
+ case 'C': sticky_buffer = "http_cookie"; break;
|
|
+ case 'I': sticky_buffer = "http_raw_uri"; break;
|
|
+ case 'D': sticky_buffer = "http_raw_header"; break;
|
|
+ case 'K': sticky_buffer = "http_raw_cookie"; break;
|
|
+ case 'S': sticky_buffer = "http_stat_code"; break;
|
|
+ case 'Y': sticky_buffer = "http_stat_msg"; break;
|
|
+ case 'i':
|
|
+ case 's':
|
|
+ case 'm':
|
|
+ case 'x':
|
|
+ case 'A':
|
|
+ case 'E':
|
|
+ case 'G':
|
|
+ case 'O':
|
|
+ case 'R':
|
|
+ case '"': // end of reg_ex
|
|
+ new_opts += c;
|
|
+ break;
|
|
+ default:
|
|
+ {
|
|
+ std::string dlt_opt = "unknown option - '";
|
|
+ dlt_opt.append(1, c);
|
|
+ dlt_opt += "'";
|
|
+ rule_api.bad_rule(data_stream, dlt_opt);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!sticky_buffer.empty())
|
|
+ {
|
|
+ buffer = sticky_buffer;
|
|
+
|
|
+ if (sticky_buffer_set)
|
|
+ rule_api.bad_rule(data_stream,
|
|
+ "Two sticky buffers set for this regular expression!");
|
|
+ else
|
|
+ sticky_buffer_set = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ rule_api.add_option("pcre", pattern + new_opts);
|
|
+
|
|
+ rule_api.set_curr_options_buffer(buffer);
|
|
+
|
|
+ return set_next_rule_state(data_stream);
|
|
+}
|
|
+
|
|
+/**************************
|
|
+ ******* A P I ***********
|
|
+ **************************/
|
|
+
|
|
+static ConversionState* ctor(Converter& c)
|
|
+{ return new Pcre2(c); }
|
|
+
|
|
+static const ConvertMap pcre2_api =
|
|
+{
|
|
+ "pcre2",
|
|
+ ctor,
|
|
+};
|
|
+
|
|
+const ConvertMap* pcre2_map = &pcre2_api;
|
|
+} // namespace rules
|
|
+
|
|
--- a/tools/snort2lua/rule_states/rule_sd_pattern.cc
|
|
+++ b/tools/snort2lua/rule_states/rule_sd_pattern.cc
|
|
@@ -41,7 +41,7 @@ private:
|
|
|
|
std::string SDPattern::convert_pattern(const std::string& pattern)
|
|
{
|
|
- const std::string unused_pcre_tokens("()[].+*^$|");
|
|
+ const std::string unused_pcre2_tokens("()[].+*^$|");
|
|
|
|
std::string s3_pattern;
|
|
|
|
@@ -100,7 +100,7 @@ std::string SDPattern::convert_pattern(c
|
|
break;
|
|
|
|
default:
|
|
- if (unused_pcre_tokens.find(sym) != std::string::npos)
|
|
+ if (unused_pcre2_tokens.find(sym) != std::string::npos)
|
|
s3_pattern.push_back('\\');
|
|
s3_pattern.push_back(sym);
|
|
break;
|