Axel Beckert wrote: > A local test on my /var/log/syslog immediately ran into a segfault, > though, so I guess, that's one of the plugins you couldn't test.
I tested it but I guess results depend on the contents of the log; apparently my log didn't trigger this code. > Culprit is this line, actually the first line in my current > /var/log/syslog: > > Dec 3 06:38:28 c6 syslog-ng[26651]: Configuration reload request > received, reloading configuration; Many thanks for the reproducer. Attached is patch that fixes it for me. I suspect there are other issues like these; in fact my pathethic patch introduces a few memory leaks (I should have told you that in advance). The problem is that ccze code manipulates strings obtained with pcre_get_substring, and assumes it can always use "free" to free them. That assumption is fine in the case with the old pcre, because the definition of pcre_free_substring is just a wrapper around free (src:pcre3: pcre_get.c:655): void pcre_free_substring(const char *pointer) { (PUBL(free))((void *)pointer); } So ccze code always uses "free". However, in pcre2, the equivalent function is different (src:pcre2: src/pcre2_substring.c:240): void pcre2_substring_free(PCRE2_UCHAR *string) { if (string != NULL) { pcre2_memctl *memctl = (pcre2_memctl *)((char *)string - sizeof(pcre2_memctl)); memctl->free(memctl, memctl->memory_data); } } Attempting to use "free" to free a string obtained with pcre2_subtring_get_by* results in SIGABRT with invalid pointer, while using pcre2_substring_free on a string obtained with strdup or some other standard (glibc) string manipulation functions results in SIGSEGV. Attached are two equivalent minimalistic programs that demonstrate this: foo.c uses pcre2 and if you exchange the free functions at the end for date and dup, you will observe exactly what I wrote above. The other program, bar.c, uses the old pcre and it doesn't make any difference if you swap them or use only "free" as ccze does. I guess I need to revisit my patch and find some way to fix this. It's up to you whether to upload the memleaky patch now or wait for me to find a solution. Sorry about this.
diff --git a/debian/patches/pcre2.patch b/debian/patches/pcre2.patch index 6b60dc8..2723ff8 100644 --- a/debian/patches/pcre2.patch +++ b/debian/patches/pcre2.patch @@ -2455,26 +2455,32 @@ Last-Update: 2023-12-03 } if (process) -@@ -87,12 +87,13 @@ +@@ -60,7 +60,7 @@ + + pid = strndup (&t[1], (size_t)(t2 - t - 1)); + tmp = strndup (process, (size_t)(t - process)); +- free (process); ++ pcre2_substring_free (process); + process = tmp; + } + } +@@ -87,11 +87,11 @@ else toret = strdup (send); - free (date); - free (host); - free (send); -- free (process); -- free (msg); + pcre2_substring_free (date); + pcre2_substring_free (host); + pcre2_substring_free (send); -+ pcre2_substring_free (process); + pcre2_substring_free (msg); + free (process); +- free (msg); free (pid); -+ free (tmp); return toret; - } -@@ -100,33 +101,34 @@ +@@ -100,33 +100,34 @@ static void ccze_syslog_setup (void) {
#define PCRE2_CODE_UNIT_WIDTH 8 #include <pcre2.h> #include <stdio.h> #include <string.h> int main (void) { pcre2_code *pcre; pcre2_match_data *md; int error; size_t errptr, l; char *date = NULL, *dup; const char *str = "Dec 3 06:38:28 c6 syslog-ng[26651]: Configuration " "reload request received, reloading configuration;"; pcre = pcre2_compile ("^(\\S*\\s{1,2}\\d{1,2}\\s\\d\\d:\\d\\d:\\d\\d)" "\\s(\\S+)\\s+((\\S+:?)\\s(.*))$", PCRE2_ZERO_TERMINATED, 0, &error, &errptr, NULL); md = pcre2_match_data_create (99, NULL); pcre2_match (pcre, str, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL); pcre2_substring_get_bynumber (md, 1, (unsigned char **)&date, &l); if (date) { printf ("%s\n", date); dup = strdup (date); } pcre2_substring_free (date); free (dup); return 0; }
#include <pcre.h> #include <stdio.h> #include <string.h> int main (void) { pcre *pcre; int md[99]; const char *error; int errptr, match; char *date = NULL, *dup; const char *str = "Dec 3 06:38:28 c6 syslog-ng[26651]: Configuration " "reload request received, reloading configuration;"; pcre = pcre_compile ("^(\\S*\\s{1,2}\\d{1,2}\\s\\d\\d:\\d\\d:\\d\\d)" "\\s(\\S+)\\s+((\\S+:?)\\s(.*))$", 0, &error, &errptr, NULL); match = pcre_exec (pcre, NULL, str, strlen (str), 0, 0, md, 99); pcre_get_substring (str, md, match, 1, (const char **)&date); if (date) { printf ("%s\n", date); dup = strdup (date); } pcre_free_substring (date); free (dup); return 0; }