========================================================================
CVE-2020-RCPTL -- Integer overflow in receive_add_recipient()
========================================================================

By default, Exim does not limit the number of recipients (the number of
valid RCPT TO commands) for a mail. But after 52428800 (50M) recipients,
the multiplication at line 492 overflows, and the size that is passed to
store_get() becomes negative (2*50M * 40B = -96MB):

 484 void
 485 receive_add_recipient(uschar *recipient, int pno)
 486 {
 487 if (recipients_count >= recipients_list_max)
 488   {
 489   recipient_item *oldlist = recipients_list;
 490   int oldmax = recipients_list_max;
 491   recipients_list_max = recipients_list_max ? 2*recipients_list_max : 50;
 492   recipients_list = store_get(recipients_list_max * sizeof(recipient_item));
 493   if (oldlist != NULL)
 494     memcpy(recipients_list, oldlist, oldmax * sizeof(recipient_item));
 495   }

- at line 492, store_get() back-jumps the current block of memory
  (Digression 1b), by -96MB;

- at line 494, memcpy() forward-overflows the current block of memory
  (Digression 1a), by nearly 2GB (50M * 40B = 2000MB).

Initially, we thought that CVE-2020-RCPTL would be the perfect
vulnerability:

- it affects all versions of Exim (since at least the beginning of its
  Git history in 2004);

- it is certainly exploitable (an unauthenticated RCE as the "exim"
  user): the forward-overflow can be absorbed to avoid a crash, and the
  back-jump can be directed onto Exim's configuration (Digression 2);

- a back-of-the-envelope calculation suggested that an exploit would
  require "only" 6GB of memory: 2*2GB for all the recipients_lists, and
  2GB of recipient addresses to absorb the forward-overflow.

Eventually, we abandoned the exploitation of CVE-2020-RCPTL:

- On Exim 4.89 (Debian oldstable), the ACLs (Access Control Lists) for
  the RCPT TO command consume approximately 512 bytes per recipient: an
  exploit would require more than 50M * 512B = 25GB of memory. Instead,
  we decided to exploit another vulnerability, CVE-2020-HSIZE, which
  requires only 3GB of memory.

- On Exim 4.92 (Debian stable), the ACLs for RCPT TO consume at least
  4KB per recipient. Indeed, this version's string_sprintf() allocates a
  whole new 32KB memory block but uses only one page (4KB): an exploit
  would require more than 50M * 4KB = 200GB of memory.

- On Exim 4.94 (Debian testing), the problem with string_sprintf() was
  solved, and an exploit would therefore require "only" 25GB of memory.
  However, the "tainted" checks create another problem: each RCPT TO
  allocates T blocks of tainted memory, and makes U is_tainted() checks
  on untainted memory, but each check traverses the complete linked list
  of tainted memory blocks. For n recipients, this has an O(n^2) time
  complexity (roughly U*T*(n^2)/2): it would take months to reach 50M
  recipients.

CVE-2020-RCPTL is also exploitable locally (through -bS and
smtp_setup_batch_msg(), which does not have ACLs), and would allow an
unprivileged local attacker to obtain the privileges of the "exim" user.
But better vulnerabilities exist: CVE-2020-NLEND and CVE-2020-CLOSE are
locally exploitable and yield full root privileges.

(sleep 10; echo 'EHLO test'; sleep 3; echo 'MAIL FROM:<>'; sleep 3; for ((i=0; i<64000000; i++)); do [ "$((i%1000000))" -eq 0 ] && echo "`date` $i" >&2; echo 'RCPT TO:lp@localhost'; done) | /usr/sbin/exim4 -bS | wc
Program received signal SIGSEGV, Segmentation fault.

