[On-line version will be at http://www.postfix.org/CVE-2011-1720.html]
Summary
=======
The Postfix SMTP server has a memory corruption error when the Cyrus
SASL library is used with authentication mechanisms other than PLAIN
and LOGIN (the ANONYMOUS mechanism is unaffected but should not be
enabled for different reasons). See below for instructions to
determine what systems are affected.
Examples of affected Cyrus SASL authentication methods are CRAM-MD5,
DIGEST-MD5, EXTERNAL, GSSAPI, KERBEROS_V4, NTLM, OTP, PASSDSS-3DES-1,
and SRP.
The error was introduced with the Postfix SASL patch, and is present
in all Postfix versions where the command "postconf mail_release_date"
reports a value of 20000314 (March 14, 2000) or greater.
This problem was discovered by Thomas Jarosch of Intra2net AG.
The memory corruption is known to result in a program crash (SIGSEV).
Remote code execution cannot be excluded. Such code would execute
as the unprivileged "postfix" user. This user has no control over
processes that run with non-postfix privileges including Postfix
processes running as root; the impact may be reduced with configurations
that enable the Postfix chroot feature or that use platform-dependent
privilege-reducing features.
The problem is fixed in Postfix stable releases 2.5.13, 2.6.10,
2.7.4, 2.8.3; in the Postfix 2.9 development release as of May 1,
2011; patches exist for Postfix version 1.1 and later. All this is
available from Postfix mirrors at http://www.postfix.org/download.html.
What systems are affected
=========================
The Postfix SMTP client is not affected.
Affected are Postfix SMTP server configurations that have SASL
authentication turned on, and that use Cyrus SASL authentication
mechanisms other than ANONYMOUS, PLAIN and LOGIN. Here,
* the command "postconf smtpd_sasl_auth_enable" produces as output
"smtpd_sasl_auth_enable = yes";
* and the command "postconf smtpd_sasl_type" produces as output
"smtpd_sasl_type = cyrus" (or "smtpd_sasl_type: unknown
parameter");
* and the Postfix SMTP server's reply to the EHLO command shows
AUTH methods other than ANONYMOUS, PLAIN and LOGIN. Examples
of other methods are CRAM-MD5 or DIGEST-MD5.
Example for the "port 25" service:
$ telnet server.example.com 25
Connected to server.example.com.
Escape character is '^]'.
220 server.example.com ESMTP Postfix
ehlo client.example.com
250-server.example.com
250-PIPELINING
250-SIZE 10240000
250-STARTTLS
250-AUTH DIGEST-MD5 LOGIN PLAIN CRAM-MD5
250-AUTH=DIGEST-MD5 LOGIN PLAIN CRAM-MD5
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
quit
221 2.0.0 Bye
Connection closed by foreign host.
Example for the "port 587" (submission) service. This service
is not enabled by default.
$ openssl s_client -quiet -starttls smtp -connect server.example.com:587
[TLS handshake information deleted]
250 DSN
ehlo client.example.com
250-server.example.com
250-PIPELINING
250-SIZE 10240000
250-AUTH DIGEST-MD5 LOGIN PLAIN CRAM-MD5
250-AUTH=DIGEST-MD5 LOGIN PLAIN CRAM-MD5
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
quit
221 2.0.0 Bye
Although it is not affected, the ANONYMOUS authentication mechanism
should not be enabled as it can make an SMTP server an open relay.
What systems are not affected
=============================
The Postfix SMTP client is not affected.
Not affected are Postfix SMTP server configurations that have SASL
authentication turned off, including configurations without SASL
support compiled in. Here, the command "postconf smtpd_sasl_auth_enable"
produces as output "smtpd_sasl_auth_enable = no".
Not affected are Postfix SMTP server configurations that use Dovecot
SASL instead of Cyrus SASL. Here, the command "postconf smtpd_sasl_type"
produces as output "smtpd_sasl_type = dovecot".
Not affected are Postfix SMTP server configurations that enable
Cyrus SASL support with only the PLAIN or LOGIN methods, or both.
Here,
* the command "postconf smtpd_sasl_auth_enable" produces as output
"smtpd_sasl_auth_enable = yes";
* and the command "postconf smtpd_sasl_type" produces as output
"smtpd_sasl_type = cyrus" (or "smtpd_sasl_type: unknown
parameter");
* and the Postfix SMTP server's reply to the EHLO command shows
only AUTH mechanisms of PLAIN, LOGIN, or both.
Example for the "port 25" service:
$ telnet server.example.com 25
Connected to server.example.com.
Escape character is '^]'.
220 server.example.com ESMTP Postfix
ehlo client.example.com
250-server.example.com
250-PIPELINING
250-SIZE 10240000
250-STARTTLS
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN PLAIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
quit
221 2.0.0 Bye
Connection closed by foreign host.
Example for the "port 587" (submission) service. This service
is not enabled by default.
$ openssl s_client -quiet -starttls smtp -connect server.example.com:587
[TLS handshake information deleted]
250 DSN
ehlo client.example.com
250-server.example.com
250-PIPELINING
250-SIZE 10240000
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN PLAIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
quit
221 2.0.0 Bye
Not affected is the ANONYMOUS authentication mechanism, but this
should not be enabled as it can make an SMTP server an open relay.
Workarounds
===========
Disable Cyrus SASL authentication mechanisms for the Postfix SMTP
server other than PLAIN and LOGIN. The mechanisms are specified in
a Cyrus SASL smtpd.conf configuration file. This file may be found
in /etc/postfix/sasl/, /var/lib/ sasl2/, /etc/sasl2/, /usr/lib/sasl2/
or /usr/local/lib/sasl2/.
In this file, update the "mech_list:" entry and remove any methods
other than PLAIN and LOGIN. For example, this configuration is not
affected:
mech_list: PLAIN LOGIN
Execute the command "postfix reload" to make the change effective,
then verify that the "port 25" and "port 587" services no longer
announce other SASL mechanisms, as shown in the previous section.
Technical details
=================
The Postfix SMTP server creates a SASL handle for each SMTP session,
when SASL authentication is enabled. The Postfix SMTP server will
use this SASL handle until it closes the SMTP connection (the Postfix
SMTP server may create a new server SASL handle when the client and
server agree to switch from a plaintext session to a TLS-encrypted
session, but this does not eliminate the memory corruption problem).
According to a comment in a Cyrus SASL include source file, a server
must not reuse a Cyrus SASL server handle after client authentication
failure. Instead, a server must create a new Cyrus SASL server
handle including mechanism list, before processing another client
authentication request.
The Postfix SMTP server fails to create a new Cyrus SASL server
handle after authentication failure. This causes memory corruption
when, for example, a client requests CRAM-MD5 authentication, fails
to authenticate, and then invokes some other authentication mechanism
except PLAIN (or ANONYMOUS if available). The likely outcome is
that the Postfix SMTP server process crashes with a segmentation
violation error (SIGSEGV, a.k.a. signal 11).
In the following example, S: indicates server output and C: indicates
client input. Line numbers are prepended for reference in the
background discussion in the next section.
1 S: 220 server.example.com ESMTP
2 C: EHLO client.example.com
3 S: 250-server.example.com
4 S: ...other server output skipped...
5 S: 250-AUTH DIGEST-MD5 LOGIN PLAIN CRAM-MD5
6 S: 250-AUTH=DIGEST-MD5 LOGIN PLAIN CRAM-MD5
7 S: ...other server output skipped...
8 C: AUTH CRAM-MD5
9 S: 334 PDg5ODE0OTI3MS4xMDQyMTg1OUBzZXJ2ZXIuZXhhbXBsZS5jb20+Cg==
10 C: *
11 S: 501 5.7.0 Authentication aborted
12 C: AUTH DIGEST-MD5
13 Connection closed by foreign host.
In the mail logfile, Postfix will log a warning similar to:
postfix/master[2213]: warning: process /usr/libexec/postfix/smtpd
pid 22585 killed by signal 11
Background
==========
Each Cyrus SASL authentication mechanism is implemented with a) one
statically-allocated shared data structure containing data and
pointers to functions that implement the mechanism, and b)
dynamically-allocated session context data structures with
authentication state.
When the Postfix SMTP server receives "AUTH CRAM-MD5" (line 8 above),
the Cyrus SASL CRAM-MD5 method initializes one CRAM-MD5 session
context data structure, and generates the "step 1" initial client
challenge which the Postfix SMTP server sends in line 9 above.
When the SMTP client sends "*" to abort the CRAM-MD5 authentication
request (line 10 above), the CRAM-MD5 session context data structure
remains attached to the Cyrus SASL server handle. Postfix fails to
create a new Cyrus SASL server handle when the client sends the
subsequent "AUTH DIGEST-MD5" request (line 12 above); the DIGEST-MD5
method will therefore use the "wrong" session context data structure
(which was created after the "AUTH CRAM-MD5" request on line 8),
and will skip its "step 1" challenge.
Each Cyrus SASL authentication method has a different context data
structure layout. Because of these differences, the bits from the
CRAM-MD5 method's context data structure will not work as intended
with the DIGEST-MD5 method. As shown in the stack trace below, the
Postfix SMTP server process crashes in "step 2" of the DIGEST-MD5
authentication protocol. This happens while attempting to read from
a pointer that contains an invalid address.
In this particular example, the Postfix SMTP server crashes while
running under control of the GDB debugger (see the Postfix master(5)
manpage discussion of the -D option), while processing the SMTP
commands shown in the example above.
(gdb) where
#0 0x884bbedf in clear_reauth_entry (reauth=0x206e6f69, type=SERVER,
utils=0x88534400) at digestmd5.c:1579
#1 0x884be648 in digestmd5_server_mech_step2 (stext=0x88518150,
sparams=0x8850c840, clientin=0x0, clientinlen=0, serverout=0xbfbfe140,
serveroutlen=0xbfbfe144, oparams=0x8855e860) at digestmd5.c:2588
#2 0x884be9c5 in digestmd5_server_mech_step (conn_context=0x88518150,
sparams=0x8850c840, clientin=0x0, clientinlen=0, serverout=0xbfbfe140,
serveroutlen=0xbfbfe144, oparams=0x8855e860) at digestmd5.c:2689
#3 0x882a51e9 in sasl_server_step (conn=0x8855e000, clientin=0x0,
clientinlen=0, serverout=0xbfbfe140, serveroutlen=0xbfbfe144)
at server.c:1430
#4 0x882a5002 in sasl_server_start (conn=0x8855e000, mech=0x8854dc08
"DIGEST-MD5", clientin=0x0, clientinlen=0, serverout=0xbfbfe140,
serveroutlen=0xbfbfe144) at server.c:1362
#5 0x08066bf7 in xsasl_cyrus_server_first (xp=0x8851af18,
sasl_method=0x8854dc08 "DIGEST-MD5", init_response=0x0,
reply=0x8851aee8) at xsasl_cyrus_server.c:529
[Remainder of stack trace omitted for brevity]
This stack trace was obtained after informing the GDB debugger of
SASL authentication methods that are linked in at runtime (example:
"add-symbol-file /usr/local/lib/sasl2/libdigestmd5.so.2 0x884b8e50").
Without that information, GDB reports a corrupted stack, because
it does not know that the program is executing legitimate code.
Impact analysis
===============
What context data structure bits does the DIGEST-MD5 method inherit
from the aborted CRAM-MD5 authentication request? As mentioned
earlier, different Cyrus SASL authentication methods have different
per-session context data structures. In particular, the CRAM-MD5
method uses a small structure while DIGEST-MD5 uses a larger one.
The DIGEST-MD5 method will therefore access memory outside the block
that was allocated during the aborted CRAM-MD5 request. That is,
it accesses random memory on the heap. The contents of that memory
will depend on the malloc implementation and on the program execution
history.
Version 2.1.23 of the Cyrus SASL library implements 12 authentication
methods. Of these, 9 methods maintain server session context data
structures that contain some mix of data and data pointers. When
these are read from random heap memory, or from a structure that
was allocated for a different SASL mechanism, all kinds of things
could happen. This is why remote code execution cannot be excluded.
Why the Cyrus SASL PLAIN and LOGIN methods are not affected
===========================================================
There is no memory corruption problem with the "AUTH PLAIN" method,
because this does not use or create a dynamically-allocated session
context data structure. In particular, sending "AUTH LOGIN" after
aborting or failing an "AUTH PLAIN" request does not result in
memory corruption, because the PLAIN authentication method does not
allocate a session context data structure. Also, sending "AUTH
PLAIN" after aborting or failing an "AUTH LOGIN" request does not
result in memory corruption, because the PLAIN authentication method
ignores the per-session context data structure that is created by
the LOGIN authentication method. Finally, there is no memory
corruption when the LOGIN authentication method inherits a session
context data structure from an aborted or failed "AUTH LOGIN"
request.
It is for these reasons that Postfix SMTP servers with Cyrus SASL
support for only PLAIN and LOGIN are not affected. Fortunately,
PLAIN + LOGIN is the most commonly-used configuration, usually
combined with TLS encryption to protect passwords on the wire. There
will be a minor memory leak, but the Postfix SMTP server limits the
number of failed requests and thereby limits the leak.
There is no memory corruption problem with the "AUTH ANONYMOUS"
method, because just like "AUTH PLAIN" this does not create or use
a dynamically-allocated session context data structure. However,
"AUTH ANONYMOUS" support should not be enabled as it can make an
SMTP server an open relay.
Timeline
========
* April 8, 2011: Thomas Jarosch (Intra2net AG) reported the
problem.
* April 18, 2011: After completing a detailed analysis of what
configurations are affected, and after testing solutions for
Postfix 1.1 .. 2.9, Wietse asked CERT/CC to notify vendors.
Thank you, CERT/CC.
* April 20, 2011: Pre-release versions available for Postfix 2.5
.. 2.8 and patches for Postfix 1.1 .. 2.9.
* Most vendors honored Wietse's request to avoid non-public
information in plaintext email headers or content. The exceptions
were SUSE and Red Hat. Shame on you, SUSE and Red Hat.
* May 9, 2011: Announcement and public release of fixes.