Skip to content

Support PCRE2 #2719

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
v3.x.y - YYYY-MMM-DD (to be released)
-------------------------------------

- Support PCRE2
[Issue #2668 - @martinhsv]
- Support SecRequestBodyNoFilesLimit
[Issue #2670 - @airween, @martinhsv]
- Fix misuses of LMDB API
Expand Down
183 changes: 183 additions & 0 deletions build/pcre2.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
dnl Check for PCRE2 Libraries
dnl CHECK_PCRE2(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])

AC_DEFUN([PROG_PCRE2], [

# Possible names for the pcre2 library/package (pkg-config)
PCRE2_POSSIBLE_LIB_NAMES="pcre2 pcre2-8"

# Possible extensions for the library
PCRE2_POSSIBLE_EXTENSIONS="so so0 la sl dll dylib so.0.0.0"

# Possible paths (if pkg-config was not found, proceed with the file lookup)
PCRE2_POSSIBLE_PATHS="/usr/lib /usr/local/lib /usr/local/libpcre2-8 /usr/local/pcre2 /usr/local /opt/libpcre2-8 /opt/pcre2 /opt /usr /usr/lib64 /opt/local"

# Variables to be set by this very own script.
PCRE2_VERSION=""
PCRE2_CFLAGS=""
PCRE2_CPPFLAGS=""
PCRE2_LDADD=""
PCRE2_LDFLAGS=""

AC_ARG_WITH(
pcre2,
AC_HELP_STRING(
[--with-pcre2=PATH],
[Path to pcre2 prefix or config script]
)
)

if test "x${with_pcre2}" == "xno"; then
AC_DEFINE(HAVE_PCRE2, 0, [Support for PCRE2 was disabled by the utilization of --without-pcre2 or --with-pcre2=no])
AC_MSG_NOTICE([Support for PCRE2 was disabled by the utilization of --without-pcre2 or --with-pcre2=no])
PCRE2_DISABLED=yes
else
if test "x${with_pcre2}" == "xyes"; then
PCRE2_MANDATORY=yes
AC_MSG_NOTICE([PCRE2 support was marked as mandatory by the utilization of --with-pcre2=yes])
fi
# for x in ${PCRE2_POSSIBLE_LIB_NAMES}; do
# CHECK_FOR_PCRE2_AT(${x})
# if test -n "${PCRE2_VERSION}"; then
# break
# fi
# done

# if test "x${with_pcre2}" != "xyes" or test "x${with_pcre2}" == "xyes"; then
if test "x${with_pcre2}" == "x" || test "x${with_pcre2}" == "xyes"; then
# Nothing about PCRE2 was informed, using the pkg-config to figure things out.
if test -n "${PKG_CONFIG}"; then
PCRE2_PKG_NAME=""
for x in ${PCRE2_POSSIBLE_LIB_NAMES}; do
if ${PKG_CONFIG} --exists ${x}; then
PCRE2_PKG_NAME="$x"
break
fi
done
fi
AC_MSG_NOTICE([Nothing about PCRE2 was informed during the configure phase. Trying to detect it on the platform...])
if test -n "${PCRE2_PKG_NAME}"; then
# Package was found using the pkg-config scripts
PCRE2_VERSION="`${PKG_CONFIG} ${PCRE2_PKG_NAME} --modversion`"
PCRE2_CFLAGS="`${PKG_CONFIG} ${PCRE2_PKG_NAME} --cflags`"
PCRE2_LDADD="`${PKG_CONFIG} ${PCRE2_PKG_NAME} --libs-only-l`"
PCRE2_LDFLAGS="`${PKG_CONFIG} ${PCRE2_PKG_NAME} --libs-only-L --libs-only-other`"
PCRE2_DISPLAY="${PCRE2_LDADD}, ${PCRE2_CFLAGS}"
else
# If pkg-config did not find anything useful, go over file lookup.
for x in ${PCRE2_POSSIBLE_PATHS}; do
CHECK_FOR_PCRE2_AT(${x})
if test -n "${PCRE2_VERSION}"; then
break
fi
done
fi
fi
if test "x${with_pcre2}" != "x"; then
# An specific path was informed, lets check.
PCRE2_MANDATORY=yes
CHECK_FOR_PCRE2_AT(${with_pcre2})
fi
# fi
fi

if test -z "${PCRE2_LDADD}"; then
if test -z "${PCRE2_MANDATORY}"; then
if test -z "${PCRE2_DISABLED}"; then
AC_MSG_NOTICE([PCRE2 library was not found])
PCRE2_FOUND=0
else
PCRE2_FOUND=2
fi
else
AC_MSG_ERROR([PCRE2 was explicitly referenced but it was not found])
PCRE2_FOUND=-1
fi
else
if test -z "${PCRE2_MANDATORY}"; then
PCRE2_FOUND=2
AC_MSG_NOTICE([PCRE2 is disabled by default.])
else
PCRE2_FOUND=1
AC_MSG_NOTICE([using PCRE2 v${PCRE2_VERSION}])
PCRE2_CFLAGS="-DWITH_PCRE2 ${PCRE2_CFLAGS}"
PCRE2_DISPLAY="${PCRE2_LDADD}, ${PCRE2_CFLAGS}"
AC_SUBST(PCRE2_VERSION)
AC_SUBST(PCRE2_LDADD)
AC_SUBST(PCRE2_LIBS)
AC_SUBST(PCRE2_LDFLAGS)
AC_SUBST(PCRE2_CFLAGS)
AC_SUBST(PCRE2_DISPLAY)
fi
fi


AC_SUBST(PCRE2_FOUND)

]) # AC_DEFUN [PROG_PCRE2]


AC_DEFUN([CHECK_FOR_PCRE2_AT], [
path=$1
echo "*** LOOKING AT PATH: " ${path}
for y in ${PCRE2_POSSIBLE_EXTENSIONS}; do
for z in ${PCRE2_POSSIBLE_LIB_NAMES}; do
if test -e "${path}/${z}.${y}"; then
pcre2_lib_path="${path}/"
pcre2_lib_name="${z}"
pcre2_lib_file="${pcre2_lib_path}/${z}.${y}"
break
fi
if test -e "${path}/lib${z}.${y}"; then
pcre2_lib_path="${path}/"
pcre2_lib_name="${z}"
pcre2_lib_file="${pcre2_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/lib${z}.${y}"; then
pcre2_lib_path="${path}/lib/"
pcre2_lib_name="${z}"
pcre2_lib_file="${pcre2_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/x86_64-linux-gnu/lib${z}.${y}"; then
pcre2_lib_path="${path}/lib/x86_64-linux-gnu/"
pcre2_lib_name="${z}"
pcre2_lib_file="${pcre2_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/i386-linux-gnu/lib${z}.${y}"; then
pcre2_lib_path="${path}/lib/i386-linux-gnu/"
pcre2_lib_name="${z}"
pcre2_lib_file="${pcre2_lib_path}/lib${z}.${y}"
break
fi
done
if test -n "$pcre2_lib_path"; then
break
fi
done
if test -e "${path}/include/pcre2.h"; then
pcre2_inc_path="${path}/include"
elif test -e "${path}/pcre2.h"; then
pcre2_inc_path="${path}"
elif test -e "${path}/include/pcre2/pcre2.h"; then
pcre2_inc_path="${path}/include"
fi

if test -n "${pcre2_lib_path}"; then
AC_MSG_NOTICE([PCRE2 library found at: ${pcre2_lib_file}])
fi

if test -n "${pcre2_inc_path}"; then
AC_MSG_NOTICE([PCRE2 headers found at: ${pcre2_inc_path}])
fi

if test -n "${pcre2_lib_path}" -a -n "${pcre2_inc_path}"; then
# TODO: Compile a piece of code to check the version.
PCRE2_CFLAGS="-I${pcre2_inc_path}"
PCRE2_LDADD="-l${pcre2_lib_name}"
PCRE2_LDFLAGS="-L${pcre2_lib_path}"
PCRE2_DISPLAY="${pcre2_lib_file}, ${pcre2_inc_path}"
fi
]) # AC_DEFUN [CHECK_FOR_PCRE2_AT]
24 changes: 24 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@ CHECK_LIBXML2
CHECK_PCRE


#
# Check for pcre2
#
PROG_PCRE2
AM_CONDITIONAL([PCRE2_CFLAGS], [test "PCRE2_CFLAGS" != ""])


# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([string])
Expand Down Expand Up @@ -555,6 +562,23 @@ if test "x$LUA_FOUND" = "x2"; then
fi


## PCRE2
if test "x$PCRE2_FOUND" = "x0"; then
echo " + PCRE2 ....not found"
fi
if test "x$PCRE2_FOUND" = "x1"; then
echo -n " + PCRE2 ....found "
if ! test "x$PCRE2_VERSION" = "x"; then
echo "v${PCRE2_VERSION}"
else
echo ""
fi
echo " ${PCRE2_DISPLAY}"
fi
if test "x$PCRE2_FOUND" = "x2"; then
echo " + PCRE2 ....disabled"
fi

echo " "
echo " Other Options"
if test $buildTestUtilities = true; then
Expand Down
3 changes: 3 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ libmodsecurity_la_CPPFLAGS = \
$(YAJL_CFLAGS) \
$(LMDB_CFLAGS) \
$(PCRE_CFLAGS) \
$(PCRE2_CFLAGS) \
$(SSDEEP_CFLAGS) \
$(MAXMIND_CFLAGS) \
$(LUA_CFLAGS) \
Expand All @@ -339,6 +340,7 @@ libmodsecurity_la_LDFLAGS = \
$(LMDB_LDFLAGS) \
$(LUA_LDFLAGS) \
$(PCRE_LDFLAGS) \
$(PCRE2_LDFLAGS) \
$(SSDEEP_LDFLAGS) \
$(MAXMIND_LDFLAGS) \
$(YAJL_LDFLAGS) \
Expand All @@ -355,6 +357,7 @@ libmodsecurity_la_LIBADD = \
../others/libinjection.la \
../others/libmbedtls.la \
$(PCRE_LDADD) \
$(PCRE2_LDADD) \
$(MAXMIND_LDADD) \
$(SSDEEP_LDADD) \
$(YAJL_LDADD)
Expand Down
43 changes: 40 additions & 3 deletions src/operators/verify_cc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,28 @@

#include "src/operators/verify_cc.h"

#include <pcre.h>
#include <iostream>
#include <cstring>
#include <vector>

#include "src/operators/operator.h"

#ifndef WITH_PCRE2
#if PCRE_HAVE_JIT
#define pcre_study_opt PCRE_STUDY_JIT_COMPILE
#else
#define pcre_study_opt 0
#endif
#endif


namespace modsecurity {
namespace operators {

VerifyCC::~VerifyCC() {
#if WITH_PCRE2
pcre2_code_free(m_pc);
#else
if (m_pc != NULL) {
pcre_free(m_pc);
m_pc = NULL;
Expand All @@ -45,6 +49,7 @@ VerifyCC::~VerifyCC() {
#endif
m_pce = NULL;
}
#endif
}

/**
Expand Down Expand Up @@ -90,6 +95,22 @@ int VerifyCC::luhnVerify(const char *ccnumber, int len) {


bool VerifyCC::init(const std::string &param2, std::string *error) {
#ifdef WITH_PCRE2
PCRE2_SPTR pcre2_pattern = reinterpret_cast<PCRE2_SPTR>(m_param.c_str());
uint32_t pcre2_options = (PCRE2_DOTALL|PCRE2_MULTILINE);
int errornumber = 0;
PCRE2_SIZE erroroffset = 0;
m_pc = pcre2_compile(pcre2_pattern, PCRE2_ZERO_TERMINATED,
pcre2_options, &errornumber, &erroroffset, NULL);
if (m_pc == NULL) {
return false;
} else {
m_match_data = pcre2_match_data_create_from_pattern(m_pc, NULL);
if (m_match_data == NULL) {
return false;
}
}
#else
const char *errptr = NULL;
int erroffset = 0;

Expand All @@ -112,18 +133,33 @@ bool VerifyCC::init(const std::string &param2, std::string *error) {
error->assign(errptr);
return false;
}
#endif

return true;
}


bool VerifyCC::evaluate(Transaction *t, RuleWithActions *rule,
const std::string& i, std::shared_ptr<RuleMessage> ruleMessage) {
#ifdef WITH_PCRE2
PCRE2_SIZE offset = 0;
size_t target_length = i.length();
PCRE2_SPTR pcre2_i = reinterpret_cast<PCRE2_SPTR>(i.c_str());

for (offset = 0; offset < target_length; offset++) {
int ret = pcre2_match(m_pc, pcre2_i, target_length, offset, 0, m_match_data, NULL);

/* If there was no match, then we are done. */
if (ret < 0) {
break;
}
PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(m_match_data);

#else
int offset = 0;
int target_length = i.length();

for (offset = 0; offset < target_length; offset++) {
std::string match;
int ovector[33];
memset(ovector, 0, sizeof(ovector));
int ret = pcre_exec(m_pc, m_pce, i.c_str(), i.size(), offset,
Expand All @@ -136,8 +172,9 @@ bool VerifyCC::evaluate(Transaction *t, RuleWithActions *rule,
if (ret < 0) {
return false;
}
#endif
if (ret > 0) {
match = std::string(i, ovector[0], ovector[1] - ovector[0]);
std::string match = std::string(i, ovector[0], ovector[1] - ovector[0]);
int is_cc = luhnVerify(match.c_str(), match.size());
if (is_cc) {
if (t) {
Expand Down
Loading