Merge branch 'debian'
[hcoop/debian/exim4.git] / debian / patches / 84_21-Security-Avoid-modification-of-constant-data-in-dkim.patch
diff --git a/debian/patches/84_21-Security-Avoid-modification-of-constant-data-in-dkim.patch b/debian/patches/84_21-Security-Avoid-modification-of-constant-data-in-dkim.patch
new file mode 100644 (file)
index 0000000..b723d0f
--- /dev/null
@@ -0,0 +1,89 @@
+From a4e1b7755ebbdee2689d40683ba69f09e38a8d7f Mon Sep 17 00:00:00 2001
+From: Qualys Security Advisory <qsa@qualys.com>
+Date: Sun, 21 Feb 2021 22:30:03 -0800
+Subject: [PATCH 21/29] Security: Avoid modification of constant data in dkim
+ handling
+
+Based on Heiko Schlittermann's commits f880c7f3 and c118c7f4. This
+fixes:
+
+6/ In src/pdkim/pdkim.c, pdkim_update_ctx_bodyhash() is sometimes called
+with a global orig_data and hence canon_data, and the following line can
+therefore modify data that should be constant:
+
+ 773   canon_data->len = b->bodylength - b->signed_body_bytes;
+
+For example, the following proof of concept sets lineending.len to 0
+(this should not be possible):
+
+(sleep 10; echo 'EHLO test'; sleep 3; echo 'MAIL FROM:<>'; sleep 3; echo 'RCPT TO:postmaster'; sleep 3; echo 'DATA'; date >&2; sleep 30; printf 'DKIM-Signature:a=rsa-sha1;c=simple/simple;l=0\r\n\r\n\r\nXXX\r\n.\r\n'; sleep 30) | nc -n -v 192.168.56.102 25
+
+(gdb) print lineending
+$1 = {data = 0x55e18035b2ad "\r\n", len = 2}
+(gdb) print &lineending.len
+$3 = (size_t *) 0x55e180385948 <lineending+8>
+(gdb) watch *(size_t *) 0x55e180385948
+
+Hardware watchpoint 1: *(size_t *) 0x55e180385948
+Old value = 2
+New value = 0
+(gdb) print lineending
+$5 = {data = 0x55e18035b2ad "\r\n", len = 0}
+---
+ src/pdkim/pdkim.c | 21 ++++++++++++---------
+ 1 file changed, 12 insertions(+), 9 deletions(-)
+
+diff --git a/src/pdkim/pdkim.c b/src/pdkim/pdkim.c
+index e3233e9f0..512a3e352 100644
+--- a/src/pdkim/pdkim.c
++++ b/src/pdkim/pdkim.c
+@@ -107,7 +107,7 @@ pdkim_combined_canon_entry pdkim_combined_canons[] = {
+ };
+-static blob lineending = {.data = US"\r\n", .len = 2};
++static const blob lineending = {.data = US"\r\n", .len = 2};
+ /* -------------------------------------------------------------------------- */
+ uschar *
+@@ -719,9 +719,11 @@ return NULL;
+ If we have to relax the data for this sig, return our copy of it. */
+ static blob *
+-pdkim_update_ctx_bodyhash(pdkim_bodyhash * b, blob * orig_data, blob * relaxed_data)
++pdkim_update_ctx_bodyhash(pdkim_bodyhash * b, const blob * orig_data, blob * relaxed_data)
+ {
+-blob * canon_data = orig_data;
++const blob * canon_data = orig_data;
++size_t left;
++
+ /* Defaults to simple canon (no further treatment necessary) */
+ if (b->canon_method == PDKIM_CANON_RELAXED)
+@@ -767,16 +769,17 @@ if (b->canon_method == PDKIM_CANON_RELAXED)
+   }
+ /* Make sure we don't exceed the to-be-signed body length */
++left = canon_data->len;
+ if (  b->bodylength >= 0
+-   && b->signed_body_bytes + (unsigned long)canon_data->len > b->bodylength
++   && left > (unsigned long)b->bodylength - b->signed_body_bytes
+    )
+-  canon_data->len = b->bodylength - b->signed_body_bytes;
++  left = (unsigned long)b->bodylength - b->signed_body_bytes;
+-if (canon_data->len > 0)
++if (left > 0)
+   {
+-  exim_sha_update(&b->body_hash_ctx, CUS canon_data->data, canon_data->len);
+-  b->signed_body_bytes += canon_data->len;
+-  DEBUG(D_acl) pdkim_quoteprint(canon_data->data, canon_data->len);
++  exim_sha_update(&b->body_hash_ctx, CUS canon_data->data, left);
++  b->signed_body_bytes += left;
++  DEBUG(D_acl) pdkim_quoteprint(canon_data->data, left);
+   }
+ return relaxed_data;
+-- 
+2.30.2
+