Hi On 2021-07-17 19:49:05 +0200, Sebastian Ramacher wrote: > Control: tags -1 confirmed moreinfo > > On 2021-07-14 21:48:50, Oxan van Leeuwen wrote: > > Package: release.debian.org > > Severity: normal > > User: release.debian.org@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 > > If this is a pre-approval request, please go ahead and remove the > moreinfo tag once the new version is available in unstable. Ping. The window for getting this upload into the initial release of bullseye is closing. Cheers > > Cheers > > > > 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 <oxan@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?= <timo@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%error@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 test@domain1.com\nget test@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 test@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 > > > -- > Sebastian Ramacher > -- Sebastian Ramacher
Attachment:
signature.asc
Description: PGP signature