Patch for CVE-2011-1951: syslog-ng-3.1.4-pcre-dos.patch (#709088)
Enabled the test suite
This commit is contained in:
parent
8108ce0d9d
commit
8629f464db
|
@ -0,0 +1,19 @@
|
||||||
|
diff -ruN syslog-ng-3.1.4/tests/functional/func_test.py syslog-ng-3.1.4-modified/tests/functional/func_test.py
|
||||||
|
--- syslog-ng-3.1.4/tests/functional/func_test.py 2009-11-21 15:48:09.000000000 +0000
|
||||||
|
+++ syslog-ng-3.1.4-modified/tests/functional/func_test.py 2011-06-17 03:44:18.057873606 +0100
|
||||||
|
@@ -60,11 +60,12 @@
|
||||||
|
# import test modules
|
||||||
|
import test_file_source
|
||||||
|
import test_filters
|
||||||
|
-import test_input_drivers
|
||||||
|
+#import test_input_drivers
|
||||||
|
import test_performance
|
||||||
|
-import test_sql
|
||||||
|
+#import test_sql
|
||||||
|
|
||||||
|
-tests = (test_input_drivers, test_sql, test_file_source, test_filters, test_performance)
|
||||||
|
+#tests = (test_input_drivers, test_sql, test_file_source, test_filters, test_performance)
|
||||||
|
+tests = (test_file_source, test_filters, test_performance)
|
||||||
|
|
||||||
|
init_env()
|
||||||
|
seed_rnd()
|
|
@ -0,0 +1,271 @@
|
||||||
|
commit 35de55e53dd653c50c8da5daf41a99ab22e7e8aa
|
||||||
|
Author: Balazs Scheidler <bazsi@balabit.hu>
|
||||||
|
Date: Tue May 3 20:54:53 2011 +0200
|
||||||
|
|
||||||
|
pcre: fixed a potential resource hogging infinite loop when an error occurs
|
||||||
|
|
||||||
|
Any kind of PCRE error case would cause an infinite loop, when the
|
||||||
|
"global" flag is present and pcre returns an error code.
|
||||||
|
|
||||||
|
The reported problem is that with PCRE 8.12 we indeed get such an error
|
||||||
|
while doing a global replace.
|
||||||
|
|
||||||
|
This patch also reworks the way PCRE based replacements are made, that code
|
||||||
|
was hairy, and I just hope this one is one bit less so. One performance
|
||||||
|
related change also made it that improves the speed pcre replacements,
|
||||||
|
which previously zeroed out a 3k array unconditionally in every invocation.
|
||||||
|
|
||||||
|
Also added some additional testcases to be sure I didn't break anything.
|
||||||
|
|
||||||
|
Reported-By: Micah Anderson <micah@riseup.net>
|
||||||
|
Signed-off-by: Balazs Scheidler <bazsi@balabit.hu>
|
||||||
|
|
||||||
|
diff --git a/src/logmatcher.c b/src/logmatcher.c
|
||||||
|
index 67b6c1b..6b70f13 100644
|
||||||
|
--- a/src/logmatcher.c
|
||||||
|
+++ b/src/logmatcher.c
|
||||||
|
@@ -504,7 +504,6 @@ typedef struct _LogMatcherPcreRe
|
||||||
|
pcre *pattern;
|
||||||
|
pcre_extra *extra;
|
||||||
|
gint match_options;
|
||||||
|
- int start_offset;
|
||||||
|
} LogMatcherPcreRe;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
@@ -623,29 +622,37 @@ static gboolean
|
||||||
|
log_matcher_pcre_re_match(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len)
|
||||||
|
{
|
||||||
|
LogMatcherPcreRe *self = (LogMatcherPcreRe *) s;
|
||||||
|
- int matches[RE_MAX_MATCHES * 3];
|
||||||
|
+ gint *matches;
|
||||||
|
+ gsize matches_size;
|
||||||
|
+ gint num_matches;
|
||||||
|
gint rc;
|
||||||
|
|
||||||
|
- if(value_len == -1)
|
||||||
|
+ if (value_len == -1)
|
||||||
|
value_len = strlen(value);
|
||||||
|
|
||||||
|
- self->start_offset = 0;
|
||||||
|
- rc = pcre_exec(self->pattern, self->extra, value, value_len, self->start_offset, self->match_options, matches, (RE_MAX_MATCHES * 3));
|
||||||
|
+ if (pcre_fullinfo(self->pattern, self->extra, PCRE_INFO_CAPTURECOUNT, &num_matches) < 0)
|
||||||
|
+ g_assert_not_reached();
|
||||||
|
+ if (num_matches > RE_MAX_MATCHES)
|
||||||
|
+ num_matches = RE_MAX_MATCHES;
|
||||||
|
+
|
||||||
|
+ matches_size = 3 * (num_matches + 1);
|
||||||
|
+ matches = g_alloca(matches_size * sizeof(gint));
|
||||||
|
+
|
||||||
|
+ rc = pcre_exec(self->pattern, self->extra,
|
||||||
|
+ value, value_len, 0, self->match_options, matches, matches_size);
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
switch (rc)
|
||||||
|
{
|
||||||
|
- case PCRE_ERROR_NOMATCH:
|
||||||
|
- /*
|
||||||
|
- msg_debug("No match", NULL);
|
||||||
|
- */
|
||||||
|
+ case PCRE_ERROR_NOMATCH:
|
||||||
|
break;
|
||||||
|
+
|
||||||
|
+ default:
|
||||||
|
/* Handle other special cases */
|
||||||
|
- default:
|
||||||
|
- msg_error("Error while matching regexp",
|
||||||
|
- evt_tag_int("error_code",rc),
|
||||||
|
- NULL);
|
||||||
|
- break;
|
||||||
|
+ msg_error("Error while matching regexp",
|
||||||
|
+ evt_tag_int("error_code", rc),
|
||||||
|
+ NULL);
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
@@ -668,78 +675,120 @@ static gchar *
|
||||||
|
log_matcher_pcre_re_replace(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len, LogTemplate *replacement, gssize *new_length)
|
||||||
|
{
|
||||||
|
LogMatcherPcreRe *self = (LogMatcherPcreRe *) s;
|
||||||
|
- int matches[RE_MAX_MATCHES * 3];
|
||||||
|
- gint rc;
|
||||||
|
- gboolean first_round = TRUE;
|
||||||
|
GString *new_value = NULL;
|
||||||
|
- gssize last_offset = 0;
|
||||||
|
- gint options = 0;
|
||||||
|
+ gint *matches;
|
||||||
|
+ gsize matches_size;
|
||||||
|
+ gint num_matches;
|
||||||
|
+ gint rc;
|
||||||
|
+ gint start_offset, last_offset;
|
||||||
|
+ gint options;
|
||||||
|
+ gboolean last_match_was_empty;
|
||||||
|
+
|
||||||
|
+ if (pcre_fullinfo(self->pattern, self->extra, PCRE_INFO_CAPTURECOUNT, &num_matches) < 0)
|
||||||
|
+ g_assert_not_reached();
|
||||||
|
+ if (num_matches > RE_MAX_MATCHES)
|
||||||
|
+ num_matches = RE_MAX_MATCHES;
|
||||||
|
+
|
||||||
|
+ matches_size = 3 * (num_matches + 1);
|
||||||
|
+ matches = g_alloca(matches_size * sizeof(gint));
|
||||||
|
+
|
||||||
|
+ /* we need zero initialized offsets for the last match as the
|
||||||
|
+ * algorithm tries uses that as the base position */
|
||||||
|
|
||||||
|
- memset(matches, 0, sizeof(matches));
|
||||||
|
+ matches[0] = matches[1] = matches[2] = 0;
|
||||||
|
|
||||||
|
if (value_len == -1)
|
||||||
|
value_len = strlen(value);
|
||||||
|
|
||||||
|
+ last_offset = start_offset = 0;
|
||||||
|
+ last_match_was_empty = FALSE;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
- options = 0;
|
||||||
|
- self->start_offset = matches[1]; /* Start at end of previous match 0 on the first iteration*/
|
||||||
|
-
|
||||||
|
- /* If the previous match was for an empty string, we are finished if we are
|
||||||
|
- at the end of the subject. Otherwise, arrange to run another match at the
|
||||||
|
- same point to see if a non-empty match can be found.
|
||||||
|
+ /* loop over the string, replacing one occurence at a time. */
|
||||||
|
+
|
||||||
|
+ /* NOTE: zero length matches need special care, as we could spin
|
||||||
|
+ * forever otherwise (since the current position wouldn't be
|
||||||
|
+ * advanced).
|
||||||
|
+ *
|
||||||
|
+ * A zero-length match can be as simple as "a*" which will be
|
||||||
|
+ * returned unless PCRE_NOTEMPTY is specified.
|
||||||
|
+ *
|
||||||
|
+ * By supporting zero-length matches, we basically make it
|
||||||
|
+ * possible to insert replacement between each incoming
|
||||||
|
+ * character.
|
||||||
|
+ *
|
||||||
|
+ * For example:
|
||||||
|
+ * pattern: a*
|
||||||
|
+ * replacement: #
|
||||||
|
+ * input: message
|
||||||
|
+ * result: #m#e#s#s#a#g#e#
|
||||||
|
+ *
|
||||||
|
+ * This mimics Perl behaviour.
|
||||||
|
*/
|
||||||
|
|
||||||
|
- if (matches[0] == matches[1] && !first_round)
|
||||||
|
+ if (last_match_was_empty)
|
||||||
|
{
|
||||||
|
- if (matches[0] == value_len)
|
||||||
|
- break;
|
||||||
|
+ /* Otherwise, arrange to run another match at the same point
|
||||||
|
+ * to see if a non-empty match can be found.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
options = PCRE_NOTEMPTY | PCRE_ANCHORED;
|
||||||
|
}
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ options = 0;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- rc = pcre_exec(self->pattern, self->extra, value, value_len, self->start_offset/*start offset*/, (self->match_options | options) , matches, (RE_MAX_MATCHES * 3) );
|
||||||
|
- if (rc < 0)
|
||||||
|
+ rc = pcre_exec(self->pattern, self->extra,
|
||||||
|
+ value, value_len,
|
||||||
|
+ start_offset, (self->match_options | options), matches, matches_size);
|
||||||
|
+ if (rc < 0 && rc != PCRE_ERROR_NOMATCH)
|
||||||
|
{
|
||||||
|
- if(rc == PCRE_ERROR_NOMATCH)
|
||||||
|
- {
|
||||||
|
- /* msg_debug("No match", NULL); */
|
||||||
|
- if(!first_round)
|
||||||
|
- {
|
||||||
|
- if (options == 0)
|
||||||
|
- break;
|
||||||
|
- else
|
||||||
|
- matches[1] = self->start_offset + 1;
|
||||||
|
- continue; /* Go round the loop again */
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- {
|
||||||
|
- /* Handle other special cases */
|
||||||
|
- msg_error("Error while matching regexp",
|
||||||
|
- evt_tag_int("error_code",rc),
|
||||||
|
- NULL);
|
||||||
|
- }
|
||||||
|
+ msg_error("Error while matching regexp",
|
||||||
|
+ evt_tag_int("error_code", rc),
|
||||||
|
+ NULL);
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
- else if (rc == 0)
|
||||||
|
+ else if (rc < 0)
|
||||||
|
{
|
||||||
|
- msg_error("Error while storing matching substrings", NULL);
|
||||||
|
+ if ((options & PCRE_NOTEMPTY) == 0)
|
||||||
|
+ {
|
||||||
|
+ /* we didn't match, even when we permitted to match the
|
||||||
|
+ * empty string. Nothing to find here, bail out */
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* we didn't match, quite possibly because the empty match
|
||||||
|
+ * was not permitted. Skip one character in order to avoid
|
||||||
|
+ * infinite loop over the same zero-length match. */
|
||||||
|
+
|
||||||
|
+ start_offset = start_offset + 1;
|
||||||
|
+ /* FIXME: handle complex sequences like utf8 and newline characters */
|
||||||
|
+ last_match_was_empty = FALSE;
|
||||||
|
+ continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
+ /* if the output array was too small, truncate the number of
|
||||||
|
+ captures to RE_MAX_MATCHES */
|
||||||
|
+
|
||||||
|
+ if (rc == 0)
|
||||||
|
+ rc = matches_size / 3;
|
||||||
|
+
|
||||||
|
log_matcher_pcre_re_feed_backrefs(s, msg, value_handle, matches, rc, value);
|
||||||
|
log_matcher_pcre_re_feed_named_substrings(s, msg, matches, value);
|
||||||
|
|
||||||
|
if (!new_value)
|
||||||
|
new_value = g_string_sized_new(value_len);
|
||||||
|
- /* literal */
|
||||||
|
+ /* append non-matching portion */
|
||||||
|
g_string_append_len(new_value, &value[last_offset], matches[0] - last_offset);
|
||||||
|
/* replacement */
|
||||||
|
log_template_append_format(replacement, msg, 0, TS_FMT_BSD, NULL, 0, 0, new_value);
|
||||||
|
- last_offset = matches[1];
|
||||||
|
+ last_match_was_empty = (matches[0] == matches[1]);
|
||||||
|
+ start_offset = last_offset = matches[1];
|
||||||
|
}
|
||||||
|
- first_round = FALSE;
|
||||||
|
}
|
||||||
|
- while (TRUE && (self->super.flags & LMF_GLOBAL));
|
||||||
|
+ while (self->super.flags & LMF_GLOBAL && start_offset < value_len);
|
||||||
|
|
||||||
|
if (new_value)
|
||||||
|
{
|
||||||
|
diff --git a/tests/unit/test_matcher.c b/tests/unit/test_matcher.c
|
||||||
|
index 3df98e5..95866b3 100644
|
||||||
|
--- a/tests/unit/test_matcher.c
|
||||||
|
+++ b/tests/unit/test_matcher.c
|
||||||
|
@@ -144,9 +144,18 @@ main()
|
||||||
|
/* empty match with global flag*/
|
||||||
|
testcase_replace("<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: aa bb", 0, "c*", "#", "#a#a# #b#b#", LMF_GLOBAL, log_matcher_pcre_re_new());
|
||||||
|
testcase_replace("<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: aa bb", 0, "a*", "?", "?? ?b?b?", LMF_GLOBAL, log_matcher_pcre_re_new());
|
||||||
|
+ testcase_replace("<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: aa", 0, "aa|b*", "@", "@@", LMF_GLOBAL, log_matcher_pcre_re_new());
|
||||||
|
+ testcase_replace("<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: aa", 0, "aa|b*", "@", "@", 0, log_matcher_pcre_re_new());
|
||||||
|
+ testcase_replace("<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: aa", 0, "b*|aa", "@", "@@@", LMF_GLOBAL, log_matcher_pcre_re_new());
|
||||||
|
+ testcase_replace("<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: aa", 0, "b*|aa", "@", "@aa", 0, log_matcher_pcre_re_new());
|
||||||
|
|
||||||
|
testcase_replace("<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: wikiwiki", 0, "wi", "", "kiki", LMF_GLOBAL, log_matcher_pcre_re_new());
|
||||||
|
testcase_replace("<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: wikiwiki", 0, "wi", "kuku", "kukukikukuki", LMF_GLOBAL, log_matcher_pcre_re_new());
|
||||||
|
+
|
||||||
|
+ /* this tests a pcre 8.12 incompatibility */
|
||||||
|
+
|
||||||
|
+ testcase_replace("<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: wikiwiki", 0, "([[:digit:]]{1,3}\\.){3}[[:digit:]]{1,3}", "foo", "wikiwiki", LMF_GLOBAL, log_matcher_pcre_re_new());
|
||||||
|
+
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
Name: syslog-ng
|
Name: syslog-ng
|
||||||
Version: 3.1.4
|
Version: 3.1.4
|
||||||
Release: 3%{?dist}
|
Release: 4%{?dist}
|
||||||
Summary: Next-generation syslog server
|
Summary: Next-generation syslog server
|
||||||
|
|
||||||
Group: System Environment/Daemons
|
Group: System Environment/Daemons
|
||||||
|
@ -16,6 +16,9 @@ Source2: syslog-ng.init.d
|
||||||
Source3: syslog-ng.sysconfig
|
Source3: syslog-ng.sysconfig
|
||||||
Source4: syslog-ng.logrotate
|
Source4: syslog-ng.logrotate
|
||||||
|
|
||||||
|
Patch0: syslog-ng-3.1.4-disable-sql-and-ssl-tests.patch
|
||||||
|
Patch1: syslog-ng-3.1.4-pcre-dos.patch
|
||||||
|
|
||||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||||
|
|
||||||
BuildRequires: pkgconfig
|
BuildRequires: pkgconfig
|
||||||
|
@ -49,6 +52,8 @@ ideal for firewalled environments.
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
%setup -q
|
%setup -q
|
||||||
|
%patch0 -p1
|
||||||
|
%patch1 -p1
|
||||||
|
|
||||||
# fix perl path
|
# fix perl path
|
||||||
%{__sed} -i 's|^#!/usr/local/bin/perl|#!%{__perl}|' contrib/relogger.pl
|
%{__sed} -i 's|^#!/usr/local/bin/perl|#!%{__perl}|' contrib/relogger.pl
|
||||||
|
@ -109,6 +114,10 @@ for vimver in 70 71 72 73 ; do
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
|
%check
|
||||||
|
make check
|
||||||
|
|
||||||
|
|
||||||
%clean
|
%clean
|
||||||
rm -rf %{buildroot}
|
rm -rf %{buildroot}
|
||||||
|
|
||||||
|
@ -179,6 +188,10 @@ fi
|
||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Fri Jun 17 2011 Jose Pedro Oliveira <jpo at di.uminho.pt> - 3.1.4-4
|
||||||
|
- Patch for CVE-2011-1951: syslog-ng-3.1.4-pcre-dos.patch (#709088)
|
||||||
|
- Enabled the test suite
|
||||||
|
|
||||||
* Mon May 9 2011 Jose Pedro Oliveira <jpo at di.uminho.pt> - 3.1.4-3
|
* Mon May 9 2011 Jose Pedro Oliveira <jpo at di.uminho.pt> - 3.1.4-3
|
||||||
- Bumped the eventlog version to match the latest upstream version (0.2.12)
|
- Bumped the eventlog version to match the latest upstream version (0.2.12)
|
||||||
- Overrided the default _localstatedir value (configure --localstatedir)
|
- Overrided the default _localstatedir value (configure --localstatedir)
|
||||||
|
|
Loading…
Reference in New Issue