Crash in mail module during SMTP setup
Maxim Dounin
mdounin at mdounin.ru
Tue Jul 30 15:32:43 UTC 2019
Hello!
On Tue, Jul 30, 2019 at 10:39:56PM +1000, Rob N ★ wrote:
> On Tue, 30 Jul 2019, at 4:26 AM, Maxim Dounin wrote:
> > Looking at "p *c" and "p *s" might be also interesting.
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x00000000005562f2 in ngx_mail_smtp_resolve_name_handler (ctx=0x7bcaa40)
> at src/mail/ngx_mail_smtp_handler.c:215
> 215 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
>
> (gdb) p *c
> $14 = {data = 0x30, read = 0x111, write = 0xc2cfff0, fd = 263201712,
> recv = 0xfb023c0, send = 0x0, recv_chain = 0xb0, send_chain = 0x350cf90,
> listening = 0x0, sent = 55627856, log = 0x0, pool = 0x350cff0,
> type = -1242759166, sockaddr = 0x0, socklen = 7, addr_text = {len = 0,
> data = 0x2c4e8fc ""}, proxy_protocol_addr = {len = 0,
> data = 0x54eb79 <ngx_mail_log_error> "UH\211\345H\203\354 at H\211}\330H\211u\320H\211U\310H\213E\330H\213@@H\205\300tCH\213E\330H\213P at H\213u\310H\213E\320H\211\321\272\234\064z"}, proxy_protocol_port = 53344,
> ssl = 0x484cb1 <ngx_syslog_writer>, udp = 0x2018d20,
> local_sockaddr = 0x7a414a, local_socklen = 0, buffer = 0x33312e32322e3438,
> queue = {prev = 0x3031312e36, next = 0x0}, number = 204275712,
> requests = 139872032560632, buffered = 0, log_error = 0, timedout = 0,
> error = 0, destroyed = 0, idle = 0, reusable = 0, close = 1, shared = 0,
> sendfile = 1, sndlowat = 1, tcp_nodelay = 2, tcp_nopush = 0,
> need_last_buf = 0}
It looks like "c" points to garbage.
>
> (gdb) p *s
> $15 = {signature = 155588656, connection = 0x350cf80, out = {len = 35,
Signature should be 0x4C49414D ("MAIL") == 1279869261, so this
looks like garbage too. And this explains why "c" points to
garbage.
> data = 0x20ae3e0 "220 smtp.fastmail.com ESMTP ready\r\n250 smtp.fastmail.com\r\n250-smtp.fastmail.com\r\n250-PIPELINING\r\n250-SIZE 71000000\r\n250-ENHANCEDSTATUSCODES\r\n250-8BITMIME\r\n250-AUTH PLAIN LOGIN\r\n250 AUTH=PLAIN LOGIN\r\n2"...}, buffer = 0x0, ctx = 0xfb02470, main_conf = 0x2015218,
Except there are some seemingly valid fields - it looks like
s->out is set to sscf->greeting. So it looks like this might be
an already closed and partially overwritten session.
Given that "s->out = sscf->greeting;" is expected to happen after
client address resolution, likely this is a duplicate handler call
from the resolver.
I think I see the problem - when using SMTP with SSL and resolver,
read events might be enabled during address resolving, leading to
duplicate ngx_mail_ssl_handshake_handler() calls if something
arrives from the client, and duplicate session initialization -
including starting another resolving.
The following patch should resolve this:
# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1564500680 -10800
# Tue Jul 30 18:31:20 2019 +0300
# Node ID 63604bfd60a09c7c91ce62c89df468a6e54d2f1c
# Parent e7181cfe9212de7f67df805bb746519c059b490b
Mail: fixed duplicate resolving.
When using SMTP with SSL and resolver, read events might be enabled
during address resolving, leading to duplicate ngx_mail_ssl_handshake_handler()
calls if something arrives from the client, and duplicate session
initialization - including starting another resolving. This can lead
to a segmentation fault if the session is closed after first resolving
finished. Fix is to block read events while resolving.
Reported by Robert Norris,
http://mailman.nginx.org/pipermail/nginx/2019-July/058204.html.
diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c
--- a/src/mail/ngx_mail_smtp_handler.c
+++ b/src/mail/ngx_mail_smtp_handler.c
@@ -15,6 +15,7 @@
static void ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx);
static void ngx_mail_smtp_resolve_name(ngx_event_t *rev);
static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx);
+static void ngx_mail_smtp_block_reading(ngx_event_t *rev);
static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c);
static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev);
static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s,
@@ -91,6 +92,9 @@ ngx_mail_smtp_init_session(ngx_mail_sess
if (ngx_resolve_addr(ctx) != NGX_OK) {
ngx_mail_close_connection(c);
}
+
+ s->resolver_ctx = ctx;
+ c->read->handler = ngx_mail_smtp_block_reading;
}
@@ -172,6 +176,9 @@ ngx_mail_smtp_resolve_name(ngx_event_t *
if (ngx_resolve_name(ctx) != NGX_OK) {
ngx_mail_close_connection(c);
}
+
+ s->resolver_ctx = ctx;
+ c->read->handler = ngx_mail_smtp_block_reading;
}
@@ -239,6 +246,38 @@ found:
static void
+ngx_mail_smtp_block_reading(ngx_event_t *rev)
+{
+ ngx_connection_t *c;
+ ngx_mail_session_t *s;
+ ngx_resolver_ctx_t *ctx;
+
+ c = rev->data;
+ s = c->data;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0,
+ "smtp reading blocked");
+
+ if (ngx_handle_read_event(rev, 0) != NGX_OK) {
+ if (s->resolver_ctx) {
+ ctx = s->resolver_ctx;
+
+ if (ctx->handler == ngx_mail_smtp_resolve_addr_handler) {
+ ngx_resolve_addr_done(ctx);
+
+ } else if (ctx->handler == ngx_mail_smtp_resolve_name_handler) {
+ ngx_resolve_name_done(ctx);
+ }
+
+ s->resolver_ctx = NULL;
+ }
+
+ ngx_mail_close_connection(c);
+ }
+}
+
+
+static void
ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c)
{
ngx_msec_t timeout;
@@ -258,6 +297,10 @@ ngx_mail_smtp_greeting(ngx_mail_session_
ngx_mail_close_connection(c);
}
+ if (c->read->ready) {
+ ngx_post_event(c->read, &ngx_posted_events);
+ }
+
if (sscf->greeting_delay) {
c->read->handler = ngx_mail_smtp_invalid_pipelining;
return;
--
Maxim Dounin
http://mdounin.ru/
More information about the nginx
mailing list