Refactor regex code

This commit fixes quite a few odd things in regex code:
 * Lack of encapsulation.
 * Non-method functions for matching without retrieving all groups.
 * Regex class being copyable without proper copy-constructor (potential UAF
   and double free due to pointer members m_pc and m_pce).
 * Redundant SMatch::m_length, which always equals to match.size() anyway.
 * Weird SMatch::size_ member which is initialized only by one of the three matching
   functions, and equals to the return value of that function anyways.
 * Several places in code having std::string value instead of reference.
This commit is contained in:
WGH
2019-01-17 01:55:17 +03:00
committed by Felipe Zimmerle
parent e0a0fa05cc
commit ad28de4f14
10 changed files with 68 additions and 67 deletions

View File

@@ -39,15 +39,11 @@ namespace Utils {
Regex::Regex(const std::string& pattern_)
: pattern(pattern_),
m_ovector {0} {
: pattern(pattern_.empty() ? ".*" : pattern_)
{
const char *errptr = NULL;
int erroffset;
if (pattern.empty() == true) {
pattern.assign(".*");
}
m_pc = pcre_compile(pattern.c_str(), PCRE_DOTALL|PCRE_MULTILINE,
&errptr, &erroffset, NULL);
@@ -71,7 +67,7 @@ Regex::~Regex() {
}
std::list<SMatch> Regex::searchAll(const std::string& s) {
std::list<SMatch> Regex::searchAll(const std::string& s) const {
const char *subject = s.c_str();
const std::string tmpString = std::string(s.c_str(), s.size());
int ovector[OVECCOUNT];
@@ -83,7 +79,6 @@ std::list<SMatch> Regex::searchAll(const std::string& s) {
s.size(), offset, 0, ovector, OVECCOUNT);
for (i = 0; i < rc; i++) {
SMatch match;
size_t start = ovector[2*i];
size_t end = ovector[2*i+1];
size_t len = end - start;
@@ -91,11 +86,9 @@ std::list<SMatch> Regex::searchAll(const std::string& s) {
rc = 0;
break;
}
match.match = std::string(tmpString, start, len);
match.m_offset = start;
match.m_length = len;
std::string match = std::string(tmpString, start, len);
offset = start + len;
retList.push_front(match);
retList.push_front(SMatch(match, start));
if (len == 0) {
rc = 0;
@@ -107,24 +100,24 @@ std::list<SMatch> Regex::searchAll(const std::string& s) {
return retList;
}
int regex_search(const std::string& s, SMatch *match,
const Regex& regex) {
int Regex::search(const std::string& s, SMatch *match) const {
int ovector[OVECCOUNT];
int ret = pcre_exec(regex.m_pc, regex.m_pce, s.c_str(),
int ret = pcre_exec(m_pc, m_pce, s.c_str(),
s.size(), 0, 0, ovector, OVECCOUNT) > 0;
if (ret > 0) {
match->match = std::string(s, ovector[ret-1],
ovector[ret] - ovector[ret-1]);
match->size_ = ret;
*match = SMatch(
std::string(s, ovector[ret-1], ovector[ret] - ovector[ret-1]),
0
);
}
return ret;
}
int regex_search(const std::string& s, const Regex& regex) {
int Regex::search(const std::string& s) const {
int ovector[OVECCOUNT];
return pcre_exec(regex.m_pc, regex.m_pce, s.c_str(),
return pcre_exec(m_pc, m_pce, s.c_str(),
s.size(), 0, 0, ovector, OVECCOUNT) > 0;
}

View File

@@ -31,39 +31,48 @@ namespace Utils {
class SMatch {
public:
SMatch() : size_(0),
m_offset(0),
m_length(0),
match("") { }
size_t size() const { return size_; }
std::string str() const { return match; }
SMatch()
: m_match(), m_offset(0)
{}
int size_;
int m_offset;
int m_length;
std::string match;
SMatch(const std::string &match, size_t offset)
: m_match(match), m_offset(offset)
{}
const std::string& str() const { return m_match; }
size_t offset() const { return m_offset; }
private:
std::string m_match;
size_t m_offset;
};
class Regex {
public:
explicit Regex(const std::string& pattern_);
~Regex();
std::string pattern;
// m_pc and m_pce can't be easily copied
Regex(const Regex&) = delete;
Regex& operator=(const Regex&) = delete;
std::list<SMatch> searchAll(const std::string& s) const;
int search(const std::string &s, SMatch *m) const;
int search(const std::string &s) const;
const std::string pattern;
private:
pcre *m_pc = NULL;
pcre_extra *m_pce = NULL;
int m_ovector[OVECCOUNT];
std::list<SMatch> searchAll(const std::string& s);
};
static inline int regex_search(const std::string& s, SMatch *match, const Regex& regex) {
return regex.search(s, match);
}
int regex_search(const std::string& s, SMatch *m,
const Regex& regex);
int regex_search(const std::string& s, const Regex& r);
static inline int regex_search(const std::string& s, const Regex& regex) {
return regex.search(s);
}
} // namespace Utils
} // namespace modsecurity