[syslog-ng/f14] Patch for CVE-2011-1951: syslog-ng-3.1.4-pcre-dos.patch (#709088) Enabled the test suite
Jose Pedro Oliveira
jpo at fedoraproject.org
Fri Jun 17 03:03:23 UTC 2011
commit 8629f464db1e3ddd5c31ec7731a3ec71f94c6fdd
Author: Jose Pedro Oliveira <jpo at di.uminho.pt>
Date: Fri Jun 17 04:02:53 2011 +0100
Patch for CVE-2011-1951: syslog-ng-3.1.4-pcre-dos.patch (#709088)
Enabled the test suite
syslog-ng-3.1.4-disable-sql-and-ssl-tests.patch | 19 ++
syslog-ng-3.1.4-pcre-dos.patch | 271 +++++++++++++++++++++++
syslog-ng.spec | 15 ++-
3 files changed, 304 insertions(+), 1 deletions(-)
---
diff --git a/syslog-ng-3.1.4-disable-sql-and-ssl-tests.patch b/syslog-ng-3.1.4-disable-sql-and-ssl-tests.patch
new file mode 100644
index 0000000..11e3a76
--- /dev/null
+++ b/syslog-ng-3.1.4-disable-sql-and-ssl-tests.patch
@@ -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()
diff --git a/syslog-ng-3.1.4-pcre-dos.patch b/syslog-ng-3.1.4-pcre-dos.patch
new file mode 100644
index 0000000..08a12f9
--- /dev/null
+++ b/syslog-ng-3.1.4-pcre-dos.patch
@@ -0,0 +1,271 @@
+commit 35de55e53dd653c50c8da5daf41a99ab22e7e8aa
+Author: Balazs Scheidler <bazsi at 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 at riseup.net>
+ Signed-off-by: Balazs Scheidler <bazsi at 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;
diff --git a/syslog-ng.spec b/syslog-ng.spec
index 29e977a..2458354 100644
--- a/syslog-ng.spec
+++ b/syslog-ng.spec
@@ -4,7 +4,7 @@
Name: syslog-ng
Version: 3.1.4
-Release: 3%{?dist}
+Release: 4%{?dist}
Summary: Next-generation syslog server
Group: System Environment/Daemons
@@ -16,6 +16,9 @@ Source2: syslog-ng.init.d
Source3: syslog-ng.sysconfig
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)
BuildRequires: pkgconfig
@@ -49,6 +52,8 @@ ideal for firewalled environments.
%prep
%setup -q
+%patch0 -p1
+%patch1 -p1
# fix perl path
%{__sed} -i 's|^#!/usr/local/bin/perl|#!%{__perl}|' contrib/relogger.pl
@@ -109,6 +114,10 @@ for vimver in 70 71 72 73 ; do
done
+%check
+make check
+
+
%clean
rm -rf %{buildroot}
@@ -179,6 +188,10 @@ fi
%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
- Bumped the eventlog version to match the latest upstream version (0.2.12)
- Overrided the default _localstatedir value (configure --localstatedir)
More information about the scm-commits
mailing list