Update Information from Qualys
[exim-website.git] / templates / static / doc / security / CVE-2020-qualys / minor-issues.txt
diff --git a/templates/static/doc/security/CVE-2020-qualys/minor-issues.txt b/templates/static/doc/security/CVE-2020-qualys/minor-issues.txt
new file mode 100644 (file)
index 0000000..5413e20
--- /dev/null
@@ -0,0 +1,253 @@
+Date: Thu, 29 Oct 2020 18:45:45 +0000
+From: Qualys Security Advisory via Security <security@exim.org>
+To: "security@exim.org" <security@exim.org>
+Subject: Re: [Exim-Security] Audit
+Sender: Security <security-bounces+hs=nodmarc.schlittermann.de@exim.org>
+Return-Path: <security-bounces+hs=nodmarc.schlittermann.de@exim.org>
+Authentication-Results: mx10.schlittermann.de; spf=pass
+ smtp.mailfrom=exim.org; dkim=pass header.d=exim.org header.s=d202008
+ header.a=rsa-sha256; dmarc=none header.from=exim.org
+Authentication-Results: exim.org; iprev=pass (mx0a-001ca501.pphosted.com)
+ smtp.remote-ip=148.163.156.198; spf=pass smtp.mailfrom=qualys.com; dkim=pass
+ header.d=qualys.com header.s=qualyscom header.a=rsa-sha256; dkim=pass
+ header.d=qualys.onmicrosoft.com header.s=selector2-qualys-onmicrosoft-com
+ header.a=rsa-sha256;  dmarc=pass header.from=qualys.com; arc=pass (i=1)
+ header.s=arcselector9901 arc.oldest-pass=1 smtp.remote-ip=148.163.156.198
+Authentication-Results: ppops.net; spf=pass smtp.mailfrom=qsa@qualys.com
+authentication-results: exim.org; dkim=none (message not signed)
+ header.d=none;exim.org; dmarc=none action=none header.from=qualys.com;
+X-Spam-Score: 0.0 (/) 
+Reply-To: Qualys Security Advisory <qsa@qualys.com>
+
+Hi all,
+
+Below are various non-security bugs that we found during our audit.
+First, a few bugs that almost have security consequences.
+
+========================================================================
+
+1/ In src/transports/smtp.c:
+
+2281       int n = sizeof(sx->buffer);
+2282       uschar * rsp = sx->buffer;
+2283
+2284       if (sx->esmtp_sent && (n = Ustrlen(sx->buffer)) < sizeof(sx->buffer)/2)
+2285         { rsp = sx->buffer + n + 1; n = sizeof(sx->buffer) - n; }
+
+This should probably be either:
+
+rsp = sx->buffer + n + 1; n = sizeof(sx->buffer) - n - 1;
+
+or:
+
+rsp = sx->buffer + n; n = sizeof(sx->buffer) - n;
+
+(not sure which) to avoid an off-by-one.
+
+========================================================================
+
+2/ In src/spool_in.c:
+
+ 462   while (  (len = Ustrlen(big_buffer)) == big_buffer_size-1
+ 463         && big_buffer[len-1] != '\n'
+ 464         )
+ 465     {   /* buffer not big enough for line; certs make this possible */
+ 466     uschar * buf;
+ 467     if (big_buffer_size >= BIG_BUFFER_SIZE*4) goto SPOOL_READ_ERROR;
+ 468     buf = store_get_perm(big_buffer_size *= 2, FALSE);
+ 469     memcpy(buf, big_buffer, --len);
+
+The --len in memcpy() chops off a useful byte (we know for sure that
+big_buffer[len-1] is not a '\n' because we entered the while loop).
+
+========================================================================
+
+3/ In src/deliver.c:
+
+ 333 static int
+ 334 open_msglog_file(uschar *filename, int mode, uschar **error)
+ 335 {
+ 336 if (Ustrstr(filename, US"/../"))
+ 337   log_write(0, LOG_MAIN|LOG_PANIC,
+ 338     "Attempt to open msglog file path with upward-traversal: '%s'\n", filename);
+
+Should this be LOG_PANIC_DIE instead of LOG_PANIC? Right now it will log
+the /../ attempt but will open the file anyway.
+
+========================================================================
+
+4/ In src/smtp_in.c:
+
+4966     case RCPT_CMD:
+4967       HAD(SCH_RCPT);
+4968       rcpt_count++;
+....
+5123       if (rcpt_count > recipients_max && recipients_max > 0)
+
+In theory this recipients_max check can be bypassed, because the int
+rcpt_count can overflow (become negative). In practice this would either
+consume too much memory or generate too much network traffic, but maybe
+it should be fixed anyway.
+
+========================================================================
+
+5/ receive_msg() calls dkim_exim_verify_finish(), which sets
+dkim_collect_input to 0 and calls pdkim_feed_finish(), which calls
+pdkim_header_complete(), which decreases dkim_collect_input to UINT_MAX,
+which reactivates the DKIM code.
+
+As a result, pdkim_feed() is called again (through receive_getc at the
+end of receive_msg()), but functions like pdkim_finish_bodyhash() and
+exim_sha_finish() have already been called (in pdkim_feed_finish()).
+This suggests a use-after-free.
+
+But it seems that a use-after-free would happen only with
+EVP_DigestFinal() (in exim_sha_finish()), which does not seem to be
+reachable via DKIM (no SHA3). But we checked OpenSSL only, not GnuTLS.
+
+Here is a proof of concept that triggers the bug (which came very close
+to a security vulnerability):
+
+(sleep 10; echo 'EHLO test'; sleep 3; echo 'MAIL FROM:<>'; sleep 3; echo 'RCPT TO:postmaster'; sleep 3; echo 'BDAT 42 LAST'; date >&2; sleep 30; printf 'not a valid header line\r\nDKIM-Signature:\r\nXXX'; sleep 30) | nc -n -v 192.168.56.102 25
+
+(gdb) print &dkim_collect_input
+$2 = (unsigned int *) 0x55e180386d90 <dkim_collect_input>
+(gdb) watch *(unsigned int *) 0x55e180386d90
+
+Hardware watchpoint 1: *(unsigned int *) 0x55e180386d90
+Old value = 0
+New value = 4294967295
+#0  0x000055e18031f805 in pdkim_header_complete (ctx=ctx@entry=0x55e181b9e8e0) at pdkim.c:1006
+#1  0x000055e18032106c in pdkim_feed_finish (ctx=0x55e181b9e8e0, return_signatures=0x55e180386d78 <dkim_signatures>, err=err@entry=0x7ffe443e1d00) at pdkim.c:1490
+#2  0x000055e1802a3280 in dkim_exim_verify_finish () at dkim.c:328
+#3  0x000055e1802c9d1d in receive_msg (extract_recip=extract_recip@entry=0) at receive.c:3409
+
+========================================================================
+
+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}
+
+========================================================================
+
+7/ In src/smtp_out.c, read_response_line(), inblock->ptr is not updated
+when -1 is returned. This does not seem to have bad consequences, but is
+maybe not the intended behavior.
+
+========================================================================
+
+8/ When gstring_grow() calls store_extend(), oldsize is g->size, and
+store_extend() therefore applies its rounding to g->size. But initially,
+the rounding was not applied to g->size but to sizeof(gstring) + g->size
+(in string_get()). This luckily does not have bad consequences on 64-bit
+(because sizeof(gstring) is rounded -- a multiple of alignment), but on
+32-bit it may have unintended consequences. We were not able to exploit
+this, however.
+
+========================================================================
+
+9/ In several cases a fixed gstring is built manually, but is then used
+with string functions that may grow/extend the gstring and have
+unintended consequences. For example, in src/exim.c:
+
+ 180 void
+ 181 set_process_info(const char *format, ...)
+ 182 {
+ 183 gstring gs = { .size = PROCESS_INFO_SIZE - 2, .ptr = 0, .s = process_info };
+ 184 gstring * g;
+ 185 int len;
+ 186 va_list ap;
+ 187
+ 188 g = string_fmt_append(&gs, "%5d ", (int)getpid());
+ 189 len = g->ptr;
+ 190 va_start(ap, format);
+ 191 if (!string_vformat(g, 0, format, ap))
+ 192   {
+ 193   gs.ptr = len;
+ 194   g = string_cat(&gs, US"**** string overflowed buffer ****");
+ 195   }
+ 196 g = string_catn(g, US"\n", 1);
+
+string_fmt_append() uses the SVFMT_EXTEND flag, and string_cat() and
+string_catn() call gstring_grow(). We were not able to exploit this,
+however.
+
+========================================================================
+
+10/ string_vformat_trc() should always call die_tainted() if the format
+string is tainted. Otherwise an attacker can exploit %n or overflow the
+newformat[] stack buffer.
+
+One note about untainted memory vs. memory corruption: the ideal
+long-term solution would be to make all untainted memory read-only
+(through mprotect()). Not sure if this would be possible or portable,
+but we wanted to at least mention it.
+
+========================================================================
+
+Finally, a few minor bugs/questions.
+
+========================================================================
+
+11/ In src/pdkim/pdkim.c, pdkim_parse_sig_header(), there might be a
+missing break at the end of the case 'a'.
+
+========================================================================
+
+12/ Same function, the call to pdkim_strtrim() seems to be useless
+because whitespace is already skipped by:
+
+ 531     if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
+ 532       goto NEXT_CHAR;
+
+But we have not fully analyzed this, so we might be missing something.
+
+========================================================================
+
+13/ Same file, HEADER_BUFFER_FRAG_SIZE seems to be unused?
+
+========================================================================
+
+14/ In src/smtp_in.c, bdat_getc(), dkim_exim_verify_feed() is called but
+does nothing because dkim_collect_input is always set to 0 at the
+beginning of bdat_getc().
+
+========================================================================
+
+We are at your disposal for questions, comments, and further
+discussions. Thank you very much!
+
+With best regards,
+
+--
+the Qualys Security Advisory team
+
+
+[https://d1dejaj6dcqv24.cloudfront.net/asset/image/email-banner-384-2x.png]<https://www.qualys.com/email-banner>
+
+
+
+This message may contain confidential and privileged information. If it has been sent to you in error, please reply to advise the sender of the error and then immediately delete it. If you are not the intended recipient, do not read, copy, disclose or otherwise use this message. The sender disclaims any liability for such unauthorized use. NOTE that all incoming emails sent to Qualys email accounts will be archived and may be scanned by us and/or by external service providers to detect and prevent threats to our systems, investigate illegal or inappropriate behavior, and/or eliminate unsolicited promotional emails (“spam”). If you have any concerns about this process, please contact us.
+_______________________________________________
+Security mailing list
+Security@exim.org
+https://lists.exim.org/mailman/listinfo/security