mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-11-16 01:22:18 +03:00
Implement RE2 fallback to libpcre
RE2 doesn't support certain features, like negative lookaround, so when a regular expression cannot be compiled with RE2, it's compiled with libpcre instead. This has some runtime cost, as this fallback is implemented with an extra heap object and virtual function calls. When RE2 is not enabled, however, everything works as it did before.
This commit is contained in:
44
src/regex/backend/backend.h
Normal file
44
src/regex/backend/backend.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* ModSecurity, http://www.modsecurity.org/
|
||||
* Copyright (c) 2019
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*
|
||||
*/
|
||||
#ifndef SRC_REGEX_BACKEND_BACKEND_H_
|
||||
#define SRC_REGEX_BACKEND_BACKEND_H_
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "src/regex/regex_match.h"
|
||||
|
||||
namespace modsecurity {
|
||||
namespace regex {
|
||||
namespace backend {
|
||||
|
||||
class Backend {
|
||||
public:
|
||||
virtual ~Backend() {}
|
||||
|
||||
virtual bool ok() const = 0;
|
||||
|
||||
virtual std::list<RegexMatch> searchAll(const std::string& s) const = 0;
|
||||
virtual int search(const std::string &s, RegexMatch *m) const = 0;
|
||||
virtual int search(const std::string &s) const = 0;
|
||||
|
||||
virtual const std::string& getPattern() const = 0;
|
||||
};
|
||||
|
||||
} // namespace backend
|
||||
} // namespace regex
|
||||
} // namespace modsecurity
|
||||
|
||||
#endif // SRC_REGEX_BACKEND_BACKEND_H_
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include "src/regex/backend/backend.h"
|
||||
#include "src/regex/regex_match.h"
|
||||
|
||||
#ifndef SRC_REGEX_BACKEND_PCRE_H_
|
||||
@@ -36,7 +37,7 @@ namespace backend {
|
||||
#define OVECCOUNT 30
|
||||
|
||||
|
||||
class Pcre {
|
||||
class Pcre : public Backend {
|
||||
public:
|
||||
explicit Pcre(const std::string& pattern_);
|
||||
~Pcre();
|
||||
@@ -45,12 +46,20 @@ class Pcre {
|
||||
Pcre(const Pcre&) = delete;
|
||||
Pcre& operator=(const Pcre&) = delete;
|
||||
|
||||
std::list<RegexMatch> searchAll(const std::string& s) const;
|
||||
int search(const std::string &s, RegexMatch *m) const;
|
||||
int search(const std::string &s) const;
|
||||
virtual bool ok() const override {
|
||||
return m_pc != NULL;
|
||||
}
|
||||
|
||||
const std::string pattern;
|
||||
std::list<RegexMatch> searchAll(const std::string& s) const override;
|
||||
int search(const std::string &s, RegexMatch *m) const override;
|
||||
int search(const std::string &s) const override;
|
||||
|
||||
virtual const std::string& getPattern() const override {
|
||||
return pattern;
|
||||
};
|
||||
private:
|
||||
const std::string pattern;
|
||||
|
||||
pcre *m_pc = NULL;
|
||||
pcre_extra *m_pce = NULL;
|
||||
};
|
||||
|
||||
@@ -29,15 +29,18 @@ namespace backend {
|
||||
static RE2::Options get_re2_options() {
|
||||
RE2::Options res;
|
||||
|
||||
// Re2 is usually used with fallback to libpcre,
|
||||
// so disable unnecessary stderr noise
|
||||
res.set_log_errors(false);
|
||||
|
||||
res.set_dot_nl(true);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Re2::Re2(const std::string& pattern_)
|
||||
: pattern(pattern_.empty() ? ".*" : pattern_),
|
||||
re(pattern, get_re2_options())
|
||||
Re2::Re2(const std::string& pattern)
|
||||
: re(pattern.empty() ? ".*" : pattern, get_re2_options())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include "src/regex/backend/backend.h"
|
||||
#include "src/regex/regex_match.h"
|
||||
|
||||
#ifndef SRC_REGEX_BACKEND_RE2_H_
|
||||
@@ -31,7 +32,7 @@ namespace backend {
|
||||
|
||||
#ifdef WITH_RE2
|
||||
|
||||
class Re2 {
|
||||
class Re2 : public Backend {
|
||||
public:
|
||||
explicit Re2(const std::string& pattern_);
|
||||
|
||||
@@ -39,11 +40,17 @@ class Re2 {
|
||||
Re2(const Re2&) = delete;
|
||||
Re2& operator=(const Re2&) = delete;
|
||||
|
||||
std::list<RegexMatch> searchAll(const std::string& s) const;
|
||||
int search(const std::string &s, RegexMatch *m) const;
|
||||
int search(const std::string &s) const;
|
||||
virtual bool ok() const override {
|
||||
return re.ok();
|
||||
}
|
||||
|
||||
const std::string pattern;
|
||||
std::list<RegexMatch> searchAll(const std::string& s) const override;
|
||||
int search(const std::string &s, RegexMatch *m) const override;
|
||||
int search(const std::string &s) const override;
|
||||
|
||||
virtual const std::string& getPattern() const override {
|
||||
return re.pattern();
|
||||
};
|
||||
private:
|
||||
const RE2 re;
|
||||
};
|
||||
|
||||
72
src/regex/backend_fallback.h
Normal file
72
src/regex/backend_fallback.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* ModSecurity, http://www.modsecurity.org/
|
||||
* Copyright (c) 2019
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*
|
||||
*/
|
||||
#ifndef SRC_REGEX_BACKEND_FALLBACK_H_
|
||||
#define SRC_REGEX_BACKEND_FALLBACK_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "src/regex/backend/backend.h"
|
||||
|
||||
namespace modsecurity {
|
||||
namespace regex {
|
||||
|
||||
template<typename T>
|
||||
static backend::Backend* compile_regex_fallback(const std::string& pattern) {
|
||||
return new T(pattern);
|
||||
}
|
||||
|
||||
template<typename T, typename T2, typename... Args>
|
||||
static backend::Backend* compile_regex_fallback(const std::string& pattern) {
|
||||
T *regex = new T{pattern};
|
||||
if (regex->ok()) {
|
||||
return regex;
|
||||
} else {
|
||||
delete regex;
|
||||
return compile_regex_fallback<T2, Args...>(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
class BackendFallback : public backend::Backend {
|
||||
public:
|
||||
BackendFallback(const std::string& pattern)
|
||||
: backend(compile_regex_fallback<Args...>(pattern))
|
||||
{}
|
||||
|
||||
virtual bool ok() const override {
|
||||
return backend->ok();
|
||||
}
|
||||
|
||||
std::list<RegexMatch> searchAll(const std::string& s) const override {
|
||||
return backend->searchAll(s);
|
||||
}
|
||||
int search(const std::string &s, RegexMatch *m) const override {
|
||||
return backend->search(s, m);
|
||||
}
|
||||
int search(const std::string &s) const override {
|
||||
return backend->search(s);
|
||||
}
|
||||
|
||||
const std::string& getPattern() const override {
|
||||
return backend->getPattern();
|
||||
}
|
||||
private:
|
||||
std::unique_ptr<backend::Backend> backend;
|
||||
};
|
||||
|
||||
} // namespace regex
|
||||
} // namespace modsecurity
|
||||
|
||||
#endif // SRC_REGEX_BACKEND_FALLBACK_H_
|
||||
@@ -20,9 +20,11 @@
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include "src/regex/backend/backend.h"
|
||||
#include "src/regex/backend/pcre.h"
|
||||
#include "src/regex/backend/re2.h"
|
||||
#include "src/regex/regex_match.h"
|
||||
#include "src/regex/backend_fallback.h"
|
||||
|
||||
#ifndef SRC_REGEX_REGEX_H_
|
||||
#define SRC_REGEX_REGEX_H_
|
||||
@@ -32,15 +34,17 @@ namespace modsecurity {
|
||||
namespace regex {
|
||||
|
||||
#ifdef WITH_PCRE
|
||||
using selectedBackend = backend::Pcre;
|
||||
#elif WITH_RE2
|
||||
using selectedBackend = backend::Re2;
|
||||
# ifdef WITH_RE2
|
||||
using selectedBackend = BackendFallback<
|
||||
backend::Re2, backend::Pcre
|
||||
>;
|
||||
# else
|
||||
using selectedBackend = backend::Pcre;
|
||||
# endif
|
||||
#else
|
||||
#error "no regex backend selected"
|
||||
# error "PCRE is not available"
|
||||
#endif
|
||||
|
||||
using selectedBackend = backend::Pcre;
|
||||
|
||||
class Regex : public selectedBackend {
|
||||
public:
|
||||
explicit Regex(const std::string& pattern) :
|
||||
|
||||
@@ -115,7 +115,7 @@ class KeyExclusion {
|
||||
class KeyExclusionRegex : public KeyExclusion {
|
||||
public:
|
||||
explicit KeyExclusionRegex(regex::Regex re)
|
||||
: m_re(re.pattern) { }
|
||||
: m_re(re.getPattern()) { }
|
||||
explicit KeyExclusionRegex(std::string re)
|
||||
: m_re(re) { }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user