Package: release.debian.org Severity: normal User: release.debian....@packages.debian.org Usertags: unblock
Please unblock package postsrsd [ Reason ] Security fix for CVE-2021-35525. [ Impact ] Package is vulnerable to a potential DoS attack. [ Tests ] Tests from upstream backported, testsuite from upstream passes, manually tested functionality. [ Risks ] Fix is a one-to-one backport from upstream, modulus formatting changes. [ 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 [ Other info ] N/A unblock postsrsd/1.10-2
diff -Nru postsrsd-1.10/debian/changelog postsrsd-1.10/debian/changelog --- postsrsd-1.10/debian/changelog 2020-12-02 22:36:36.000000000 +0100 +++ postsrsd-1.10/debian/changelog 2021-07-14 21:21:11.000000000 +0200 @@ -1,4 +1,12 @@ -postsrsd (1.10-1) UNRELEASED; urgency=medium +postsrsd (1.10-2) UNRELEASED; urgency=medium + + * Fix CVE-2021-35525: potential DoS when Postfix sends certain long data + fields such as multiple concatenated email addresses. Fix backported from + upstream commit 077be98d8c8. (Closes: #990439) + + -- Oxan van Leeuwen <o...@oxanvanleeuwen.nl> Wed, 14 Jul 2021 21:21:11 +0200 + +postsrsd (1.10-1) unstable; urgency=medium * New upstream release (Closes: #975633) * Drop patches integrated upstream diff -Nru postsrsd-1.10/debian/patches/0002-SECURITY-Fix-DoS-on-overly-long-input-from-Postfix.patch postsrsd-1.10/debian/patches/0002-SECURITY-Fix-DoS-on-overly-long-input-from-Postfix.patch --- postsrsd-1.10/debian/patches/0002-SECURITY-Fix-DoS-on-overly-long-input-from-Postfix.patch 1970-01-01 01:00:00.000000000 +0100 +++ postsrsd-1.10/debian/patches/0002-SECURITY-Fix-DoS-on-overly-long-input-from-Postfix.patch 2021-07-14 21:21:11.000000000 +0200 @@ -0,0 +1,211 @@ +From: =?utf-8?q?Timo_R=C3=B6hling?= <t...@gaussglocke.de> +Date: Sun, 21 Mar 2021 15:27:55 +0100 +Subject: SECURITY: Fix DoS on overly long input from Postfix +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 8bit + +Thanks to Mateusz Jończyk who reported this issue and gave valuable +feedback for its resolution. + +PostSRSd would hang on an overly long GET request, because the +fread()/fwrite() logic in the subprocess would get confused by the +remaining input line in its buffer. + +Theoretically, this error should never occur, as Postfix is supposed to +send valid email addresses only, which are shorter than the buffer, even +assuming every single character is percent-encoded. However, Postfix +sometimes does seem to send malformed request with multiple concatenated +email addresses. I'm not sure if there's a reliable way to trigger this +condition by an external attacker, but it is a security bug in PostSRSd +nevertheless. + +Fixes CVE-2021-35525. + +Origin: https://github.com/roehling/postsrsd/commit/077be98d8c8a9847e4ae0c7dc09e7474cbe27db2 +Forwarded: not-needed +Last-Update: 2021-07-14 +--- + postsrsd.c | 52 ++++++++++++++++++++++++++++++------------------- + run_postsrsd_tests.bats | 40 +++++++++++++++++++++++++++++++++---- + 2 files changed, 68 insertions(+), 24 deletions(-) + +diff --git a/postsrsd.c b/postsrsd.c +index c009d8f..5ebf7f6 100644 +--- a/postsrsd.c ++++ b/postsrsd.c +@@ -518,9 +518,9 @@ int main (int argc, char **argv) + fds[sc].events = POLLIN; + } + while(TRUE) { + int conn; +- FILE *fp; ++ FILE *fp_read, *fp_write; + char linebuf[1024], *line; + char keybuf[1024], *key; + + if (poll(fds, socket_count, 1000) < 0) { +@@ -540,41 +540,53 @@ int main (int argc, char **argv) + int i; + // close listen sockets so that we don't stop the main daemon process from restarting + for (i = 0; i < socket_count; ++i) close (sockets[i]); + +- fp = fdopen(conn, "r+"); +- if (fp == NULL) exit(EXIT_FAILURE); +- fds[0].fd = conn; +- fds[0].events = POLLIN; +- if (poll(fds, 1, timeout * 1000) <= 0) return EXIT_FAILURE; +- line = fgets(linebuf, sizeof(linebuf), fp); +- while (line) { +- fseek (fp, 0, SEEK_CUR); /* Workaround for Solaris */ ++ /* create separate input/output streams */ ++ fp_read = fdopen(conn, "r"); ++ if (fp_read == NULL) ++ return EXIT_FAILURE; ++ fp_write = fdopen(dup(conn), "w"); ++ if (fp_write == NULL) return EXIT_FAILURE; ++ errno = 0; ++ alarm(timeout); ++ if (errno != 0) ++ return EXIT_FAILURE; ++ while ((line = fgets(linebuf, sizeof(linebuf), fp_read))) { + char* token; ++ alarm(0); ++ if (strlen(line) >= sizeof(linebuf) - 1) { ++ fprintf(fp_write, "500 Invalid request\n"); ++ fflush(fp_write); ++ return EXIT_FAILURE; ++ } + token = strtok(line, " \r\n"); + if (token == NULL || strcmp(token, "get") != 0) { +- fprintf (fp, "500 Invalid request\n"); +- fflush (fp); ++ fprintf (fp_write, "500 Invalid request\n"); ++ fflush (fp_write); + return EXIT_FAILURE; + } + token = strtok(NULL, "\r\n"); + if (!token) { +- fprintf (fp, "500 Invalid request\n"); +- fflush (fp); ++ fprintf (fp_write, "500 Invalid request\n"); ++ fflush (fp_write); + return EXIT_FAILURE; + } + key = url_decode(keybuf, sizeof(keybuf), token); + if (!key) { +- fprintf (fp, "500 Invalid request\n"); +- fflush(fp); ++ fprintf (fp_write, "500 Invalid request\n"); ++ fflush(fp_write); + return EXIT_FAILURE; + } +- handler[sc](srs, fp, key, domain, excludes); +- fflush (fp); +- if (poll(fds, 1, timeout * 1000) <= 0) break; +- line = fgets(linebuf, sizeof(linebuf), fp); ++ handler[sc](srs, fp_write, key, domain, excludes); ++ fflush (fp_write); ++ errno = 0; ++ alarm(timeout); ++ if (errno != 0) ++ return EXIT_FAILURE; + } +- fclose (fp); ++ fclose (fp_write); ++ fclose (fp_read); + return EXIT_SUCCESS; + } + close (conn); + } +diff --git a/run_postsrsd_tests.bats b/run_postsrsd_tests.bats +index f4b04bb..3d52a50 100755 +--- a/run_postsrsd_tests.bats ++++ b/run_postsrsd_tests.bats +@@ -2,9 +2,9 @@ + # vim: filetype=bash: + + if [ ! -x "$POSTSRSD" ] + then +- for builddir in . build* obj* ++ for builddir in . build* obj* _build* + do + if [ -x "${builddir}/postsrsd" ] + then + POSTSRSD="${builddir}/postsrsd" +@@ -14,9 +14,9 @@ then + fi + if [ ! -x "$POSTSRSD" ] + then + cat>&2 <<- EOF +- cannot find postsrsd executable (looked in ., build*, obj*) ++ cannot find postsrsd executable (looked in ., build*, obj*, _build*) + please build the executable first, or set the POSTSRSD + environment variable if it is in a different location. + + EOF +@@ -25,14 +25,21 @@ fi + + LANG=C.UTF-8 + + ++fillchar() ++{ ++ local count="$1" ++ local char="$2" ++ eval 'printf "'"$char"'%.0s" {1..'"$count"'}' ++} ++ + start_postsrsd_at() + { + echo 'tops3cr3t' > "$BATS_TMPDIR/postsrsd.secret" + local faketime="$1" + shift +- faketime "${faketime}" ${POSTSRSD} -D -f 10001 -r 10002 -p "$BATS_TMPDIR/postsrsd.pid" -s "$BATS_TMPDIR/postsrsd.secret" -d example.com "$@" ++ faketime "${faketime}" ${POSTSRSD} -D -t1 -f 10001 -r 10002 -p "$BATS_TMPDIR/postsrsd.pid" -s "$BATS_TMPDIR/postsrsd.secret" -d example.com "$@" + } + + stop_postsrsd() + { +@@ -158,9 +165,9 @@ teardown() + read<&9 line + [[ "$line" =~ ^"500 Domain excluded" ]] + } + +-@test "SRS invalid requests" { ++@test "Malformed or invalid requests" { + start_postsrsd_at "2020-01-01 00:01:00 UTC" + exec 9<>/dev/tcp/127.0.0.1/10001 + echo>&9 "get" + read<&9 line +@@ -172,5 +179,30 @@ teardown() + exec 9<>/dev/tcp/127.0.0.1/10001 + echo>&9 "get encoding%er...@otherdomain.com" + read<&9 line + [[ "$line" =~ ^500 ]] ++ exec 9<>/dev/tcp/127.0.0.1/10001 ++ # Try to overflow the input buffer ++ echo>&9 "get too_long@`fillchar 1024 a`.com" ++ read<&9 line ++ [[ "$line" =~ ^500 ]] ++} ++ ++@test "Pipelining multiple requests" { ++ start_postsrsd_at "2020-01-01 00:01:00 UTC" ++ exec 9<>/dev/tcp/127.0.0.1/10001 ++ # Send two requests at once and see if PostSRSd answers both ++ echo>&9 -e "get t...@domain1.com\nget t...@domain2.com" ++ read<&9 line ++ [[ "$line" =~ ^200 ]] ++ read<&9 line ++ [[ "$line" =~ ^200 ]] ++} ++ ++@test "Session timeout" { ++ start_postsrsd_at "2020-01-01 00:01:00 UTC" ++ exec 9<>/dev/tcp/127.0.0.1/10001 ++ # Wait until PostSRSd disconnects due to inactivity ++ sleep 2 ++ echo >&9 "get t...@example.com" ++ ! read <&9 line + } diff -Nru postsrsd-1.10/debian/patches/series postsrsd-1.10/debian/patches/series --- postsrsd-1.10/debian/patches/series 2020-12-02 22:36:36.000000000 +0100 +++ postsrsd-1.10/debian/patches/series 2021-07-14 21:21:11.000000000 +0200 @@ -1 +1,2 @@ 0001-Run-as-postsrsd-user-by-default.patch +0002-SECURITY-Fix-DoS-on-overly-long-input-from-Postfix.patch