Package: release.debian.org Severity: normal User: release.debian....@packages.debian.org Usertags: unblock
Hi RMs, I would like to ask for unblocking fetchmail, fixing a security issue. [ Reason ] When logging long messages, fetchmail might segfault or leak information to logs. [ Impact ] Normal logging in all cases. [ Tests ] Local tests. [ Risks ] None. [ Checklist ] [x] all changes are documented in the d/changelog [x] I reviewed all changes and I approve them [x] attach debdiff against the package in testing unblock fetchmail/6.4.16-4 Thanks for considering, Laszlo/GCS
diff -Nru fetchmail-6.4.16/debian/changelog fetchmail-6.4.16/debian/changelog --- fetchmail-6.4.16/debian/changelog 2021-06-26 23:53:00.000000000 +0200 +++ fetchmail-6.4.16/debian/changelog 2021-07-29 00:18:56.000000000 +0200 @@ -1,3 +1,10 @@ +fetchmail (6.4.16-4) unstable; urgency=high + + * Backport upstream security fix for CVE-2021-36386: denial of service or + information disclosure when logging long messages. + + -- Laszlo Boszormenyi (GCS) <g...@debian.org> Thu, 29 Jul 2021 00:18:56 +0200 + fetchmail (6.4.16-3) unstable; urgency=medium * Fix operation autopkgtest. diff -Nru fetchmail-6.4.16/debian/patches/11_fix_CVE-2021-38386.patch fetchmail-6.4.16/debian/patches/11_fix_CVE-2021-38386.patch --- fetchmail-6.4.16/debian/patches/11_fix_CVE-2021-38386.patch 1970-01-01 01:00:00.000000000 +0100 +++ fetchmail-6.4.16/debian/patches/11_fix_CVE-2021-38386.patch 2021-07-29 00:18:56.000000000 +0200 @@ -0,0 +1,258 @@ +From c546c8299243a10a7b85c638e0e61396ecd5d8b5 Mon Sep 17 00:00:00 2001 +From: Matthias Andree <matthias.and...@gmx.de> +Date: Wed, 7 Jul 2021 16:22:57 +0200 +Subject: [PATCH] Fix SIGSEGV when resizing report*() buffer. + +Reported (with a different patch suggestion) by +Christian Herdtweck <christian.herdtw...@intra2net.com>. + +Note that vsnprintf() calls va_arg(), and depending on operating system, +compiler, configuration, this will invalidate the va_list argument +pointer, so that va_start has to be called again before a subsequent +vsnprintf(). However, it is better to do away with the loop and the +trial-and-error, and leverage the return value of vsnprintf instead for +a direct one-off resizing, whilst taking into account that on SUSv2 +systems, the return value can be useless if the size argument to +vsnprintf is 0. +--- + NEWS | 18 ++++++++ + report.c | 138 +++++++++++++++++++++++++++++++------------------------ + 2 files changed, 95 insertions(+), 61 deletions(-) + +diff --git a/NEWS b/NEWS +index 04239b16..67dc1f9e 100644 +--- a/NEWS ++++ b/NEWS +@@ -64,6 +64,24 @@ removed from a 6.5.0 or newer release.) + for end-of-life OpenSSL versions may be removed even from patchlevel releases. + + -------------------------------------------------------------------------------- ++fetchmail-6.4.20 (not yet released): ++ ++# SECURITY FIX: ++* When a log message exceeds c. 2 kByte in size, for instance, with very long ++ header contents, and depending on verbosity option, fetchmail can crash or ++ misreport each first log message that requires a buffer reallocation. ++ fetchmail then reallocates memory and re-runs vsnprintf() without another ++ call to va_start(), so it reads garbage. The exact impact depends on ++ many factors around the compiler and operating system configurations used and ++ the implementation details of the stdarg.h interfaces of the two functions ++ mentioned before. To fix CVE-2021-38386. ++ ++ Reported by Christian Herdtweck of Intra2net AG, Tübingen, Germany. ++ ++ He also offered a patch, which I could not take for fetchmail 6.4 because ++ it required a C99 system and I'd promised earlier that 6.4 would remain ++ compatible with C89 systems. ++-------------------------------------------------------------------------------- + fetchmail-6.4.16 (released 2021-02-08, 27707 LoC): + + # BUG FIXES +diff --git a/report.c b/report.c +index 1466802a..aea6b3ea 100644 +--- a/report.c ++++ b/report.c +@@ -44,6 +44,8 @@ static unsigned int partial_message_size = 0; + static unsigned int partial_message_size_used = 0; + static char *partial_message; + static int partial_suppress_tag = 0; ++/* default size for the allocation of the report buffer */ ++const size_t defaultsize = 4096; + + static unsigned unbuffered; + static unsigned int use_syslog; +@@ -177,6 +179,27 @@ void report_init(int mode /** 0: regular output, 1: unbuffered output, -1: syslo + } + } + ++static void rep_ensuresize(size_t increment) { ++ if (partial_message_size == 0) ++ { ++ /* initialization */ ++ partial_message_size_used = 0; ++ /* avoid too many small allocations initially */ ++ if (increment < defaultsize) increment = defaultsize; ++ partial_message_size = increment; ++ partial_message = (char *)MALLOC (partial_message_size); ++ } ++ else /* already have buffer -> resize if too little room */ ++ { ++ if (increment < defaultsize) increment = defaultsize; ++ if (partial_message_size - partial_message_size_used < increment) ++ { ++ partial_message_size += increment; ++ partial_message = (char *)REALLOC (partial_message, partial_message_size); ++ } ++ } ++} ++ + /* Build an report message by appending MESSAGE, which is a printf-style + format string with optional args, to the existing report message (which may + be empty.) The completed report message is finally printed (and reset to +@@ -185,52 +208,37 @@ void report_init(int mode /** 0: regular output, 1: unbuffered output, -1: syslo + message exists, then, in an attempt to keep the messages in their proper + sequence, the partial message will be printed as-is (with a trailing + newline) before report() prints its message. */ ++ ++ + /* VARARGS */ ++#ifdef HAVE_STDARG_H ++static int report_vgetsize(const char *message, va_list args) ++{ ++ char tmp[1]; + +-static void rep_ensuresize(void) { +- /* Make an initial guess for the size of any single message fragment. */ +- if (partial_message_size == 0) +- { +- partial_message_size_used = 0; +- partial_message_size = 2048; +- partial_message = (char *)MALLOC (partial_message_size); +- } +- else +- if (partial_message_size - partial_message_size_used < 1024) +- { +- partial_message_size += 2048; +- partial_message = (char *)REALLOC (partial_message, partial_message_size); +- } ++ return vsnprintf(tmp, 1, message, args); + } + +-#ifdef HAVE_STDARG_H +-static void report_vbuild(const char *message, va_list args) ++/* note that report_vbuild assumes that the buffer was already allocated. */ ++/* VARARGS */ ++static int report_vbuild(const char *message, va_list args) + { + int n; + +- for ( ; ; ) +- { +- /* +- * args has to be initialized before every call of vsnprintf(), +- * because vsnprintf() invokes va_arg macro and thus args is +- * undefined after the call. +- */ +- n = vsnprintf (partial_message + partial_message_size_used, partial_message_size - partial_message_size_used, +- message, args); +- +- /* output error, f. i. EILSEQ */ +- if (n < 0) break; +- +- if (n >= 0 +- && (unsigned)n < partial_message_size - partial_message_size_used) +- { +- partial_message_size_used += n; +- break; +- } ++ n = vsnprintf (partial_message + partial_message_size_used, ++ partial_message_size - partial_message_size_used, ++ message, args); ++ ++ /* output error, f. i. EILSEQ */ ++ if (n < 0) ++ return -1; + +- partial_message_size += 2048; +- partial_message = (char *)REALLOC (partial_message, partial_message_size); ++ if (n > 0) ++ { ++ partial_message_size_used += n; + } ++ ++ return n; + } + #endif + +@@ -243,40 +251,45 @@ report_build (FILE *errfp, message, va_alist) + va_dcl + #endif + { ++ int n; + #ifdef VA_START + va_list args; +-#else +- int n; + #endif + +- rep_ensuresize(); ++/* the logic is to first calculate the size, ++ * then reallocate, then fill the buffer ++ */ + + #if defined(VA_START) + VA_START(args, message); +- report_vbuild(message, args); ++ n = report_vgetsize(message, args); + va_end(args); +-#else +- for ( ; ; ) +- { +- n = snprintf (partial_message + partial_message_size_used, +- partial_message_size - partial_message_size_used, +- message, a1, a2, a3, a4, a5, a6, a7, a8); + +- /* output error, f. i. EILSEQ */ +- if (n < 0) break; ++ rep_ensuresize(n + 1); + +- if (n >= 0 +- && (unsigned)n < partial_message_size - partial_message_size_used) +- { +- partial_message_size_used += n; +- break; +- } ++ VA_START(args, message); ++ n = report_vbuild(message, args); ++ va_end(args); ++#else ++ { ++ char tmp[1]; ++ /* note that SUSv2 specifies that with the 2nd argument zero, an ++ * unspecified value less than 1 were to be returned. This is not ++ * useful, so pass 1. */ ++ n = snprintf (tmp, 1, ++ message, a1, a2, a3, a4, a5, a6, a7, a8); + +- partial_message_size += 2048; +- partial_message = REALLOC (partial_message, partial_message_size); ++ if (n > 0) ++ rep_ensuresize(n + 1); + } ++ ++ n = snprintf (partial_message + partial_message_size_used, ++ partial_message_size - partial_message_size_used, ++ message, a1, a2, a3, a4, a5, a6, a7, a8); + #endif + ++ if (n > 0) partial_message_size_used += n; ++ + if (unbuffered && partial_message_size_used != 0) + { + partial_message_size_used = 0; +@@ -308,15 +321,18 @@ report_complete (FILE *errfp, message, va_alist) + va_dcl + #endif + { ++ int n; + #ifdef VA_START + va_list args; +-#endif + +- rep_ensuresize(); ++ VA_START(args, message); ++ n = report_vgetsize(message, args); ++ va_end(args); ++ ++ rep_ensuresize(n + 1); + +-#if defined(VA_START) + VA_START(args, message); +- report_vbuild(message, args); ++ n = report_vbuild(message, args); + va_end(args); + #else + report_build(errfp, message, a1, a2, a3, a4, a5, a6, a7, a8); +-- +GitLab + diff -Nru fetchmail-6.4.16/debian/patches/series fetchmail-6.4.16/debian/patches/series --- fetchmail-6.4.16/debian/patches/series 2021-06-24 19:00:48.000000000 +0200 +++ fetchmail-6.4.16/debian/patches/series 2021-07-29 00:18:56.000000000 +0200 @@ -4,3 +4,4 @@ 08_remove_forced_OpenSSL_check.patch 09_fix_memory_leak_in_timeout_situation.patch 10_update_manpage.patch +11_fix_CVE-2021-38386.patch