comparison src/mail/ngx_mail_smtp_handler.c @ 7546:fcd92ad76b7b

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.
author Maxim Dounin <mdounin@mdounin.ru>
date Thu, 01 Aug 2019 13:50:07 +0300
parents b2915d99ee8d
children ab6257dac2a8
comparison
equal deleted inserted replaced
7545:0ef2bc0ec9c9 7546:fcd92ad76b7b
13 13
14 14
15 static void ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx); 15 static void ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx);
16 static void ngx_mail_smtp_resolve_name(ngx_event_t *rev); 16 static void ngx_mail_smtp_resolve_name(ngx_event_t *rev);
17 static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx); 17 static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx);
18 static void ngx_mail_smtp_block_reading(ngx_event_t *rev);
18 static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c); 19 static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c);
19 static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev); 20 static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev);
20 static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s, 21 static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s,
21 ngx_connection_t *c); 22 ngx_connection_t *c);
22 23
86 ctx->addr.socklen = c->socklen; 87 ctx->addr.socklen = c->socklen;
87 ctx->handler = ngx_mail_smtp_resolve_addr_handler; 88 ctx->handler = ngx_mail_smtp_resolve_addr_handler;
88 ctx->data = s; 89 ctx->data = s;
89 ctx->timeout = cscf->resolver_timeout; 90 ctx->timeout = cscf->resolver_timeout;
90 91
92 s->resolver_ctx = ctx;
93 c->read->handler = ngx_mail_smtp_block_reading;
94
91 if (ngx_resolve_addr(ctx) != NGX_OK) { 95 if (ngx_resolve_addr(ctx) != NGX_OK) {
92 ngx_mail_close_connection(c); 96 ngx_mail_close_connection(c);
93 } 97 }
94 } 98 }
95 99
166 170
167 ctx->name = s->host; 171 ctx->name = s->host;
168 ctx->handler = ngx_mail_smtp_resolve_name_handler; 172 ctx->handler = ngx_mail_smtp_resolve_name_handler;
169 ctx->data = s; 173 ctx->data = s;
170 ctx->timeout = cscf->resolver_timeout; 174 ctx->timeout = cscf->resolver_timeout;
175
176 s->resolver_ctx = ctx;
177 c->read->handler = ngx_mail_smtp_block_reading;
171 178
172 if (ngx_resolve_name(ctx) != NGX_OK) { 179 if (ngx_resolve_name(ctx) != NGX_OK) {
173 ngx_mail_close_connection(c); 180 ngx_mail_close_connection(c);
174 } 181 }
175 } 182 }
237 ngx_mail_smtp_greeting(s, c); 244 ngx_mail_smtp_greeting(s, c);
238 } 245 }
239 246
240 247
241 static void 248 static void
249 ngx_mail_smtp_block_reading(ngx_event_t *rev)
250 {
251 ngx_connection_t *c;
252 ngx_mail_session_t *s;
253 ngx_resolver_ctx_t *ctx;
254
255 c = rev->data;
256 s = c->data;
257
258 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp reading blocked");
259
260 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
261
262 if (s->resolver_ctx) {
263 ctx = s->resolver_ctx;
264
265 if (ctx->handler == ngx_mail_smtp_resolve_addr_handler) {
266 ngx_resolve_addr_done(ctx);
267
268 } else if (ctx->handler == ngx_mail_smtp_resolve_name_handler) {
269 ngx_resolve_name_done(ctx);
270 }
271
272 s->resolver_ctx = NULL;
273 }
274
275 ngx_mail_close_connection(c);
276 }
277 }
278
279
280 static void
242 ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c) 281 ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c)
243 { 282 {
244 ngx_msec_t timeout; 283 ngx_msec_t timeout;
245 ngx_mail_core_srv_conf_t *cscf; 284 ngx_mail_core_srv_conf_t *cscf;
246 ngx_mail_smtp_srv_conf_t *sscf; 285 ngx_mail_smtp_srv_conf_t *sscf;
254 timeout = sscf->greeting_delay ? sscf->greeting_delay : cscf->timeout; 293 timeout = sscf->greeting_delay ? sscf->greeting_delay : cscf->timeout;
255 ngx_add_timer(c->read, timeout); 294 ngx_add_timer(c->read, timeout);
256 295
257 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { 296 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
258 ngx_mail_close_connection(c); 297 ngx_mail_close_connection(c);
298 }
299
300 if (c->read->ready) {
301 ngx_post_event(c->read, &ngx_posted_events);
259 } 302 }
260 303
261 if (sscf->greeting_delay) { 304 if (sscf->greeting_delay) {
262 c->read->handler = ngx_mail_smtp_invalid_pipelining; 305 c->read->handler = ngx_mail_smtp_invalid_pipelining;
263 return; 306 return;