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.
Maxim Dounin
2 years ago
14 | 14 | static void ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx); |
15 | 15 | static void ngx_mail_smtp_resolve_name(ngx_event_t *rev); |
16 | 16 | static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx); |
17 | static void ngx_mail_smtp_block_reading(ngx_event_t *rev); | |
17 | 18 | static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c); |
18 | 19 | static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev); |
19 | 20 | static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s, |
87 | 88 | ctx->data = s; |
88 | 89 | ctx->timeout = cscf->resolver_timeout; |
89 | 90 | |
91 | s->resolver_ctx = ctx; | |
92 | c->read->handler = ngx_mail_smtp_block_reading; | |
93 | ||
90 | 94 | if (ngx_resolve_addr(ctx) != NGX_OK) { |
91 | 95 | ngx_mail_close_connection(c); |
92 | 96 | } |
167 | 171 | ctx->handler = ngx_mail_smtp_resolve_name_handler; |
168 | 172 | ctx->data = s; |
169 | 173 | ctx->timeout = cscf->resolver_timeout; |
174 | ||
175 | s->resolver_ctx = ctx; | |
176 | c->read->handler = ngx_mail_smtp_block_reading; | |
170 | 177 | |
171 | 178 | if (ngx_resolve_name(ctx) != NGX_OK) { |
172 | 179 | ngx_mail_close_connection(c); |
238 | 245 | |
239 | 246 | |
240 | 247 | static void |
248 | ngx_mail_smtp_block_reading(ngx_event_t *rev) | |
249 | { | |
250 | ngx_connection_t *c; | |
251 | ngx_mail_session_t *s; | |
252 | ngx_resolver_ctx_t *ctx; | |
253 | ||
254 | c = rev->data; | |
255 | s = c->data; | |
256 | ||
257 | ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp reading blocked"); | |
258 | ||
259 | if (ngx_handle_read_event(rev, 0) != NGX_OK) { | |
260 | ||
261 | if (s->resolver_ctx) { | |
262 | ctx = s->resolver_ctx; | |
263 | ||
264 | if (ctx->handler == ngx_mail_smtp_resolve_addr_handler) { | |
265 | ngx_resolve_addr_done(ctx); | |
266 | ||
267 | } else if (ctx->handler == ngx_mail_smtp_resolve_name_handler) { | |
268 | ngx_resolve_name_done(ctx); | |
269 | } | |
270 | ||
271 | s->resolver_ctx = NULL; | |
272 | } | |
273 | ||
274 | ngx_mail_close_connection(c); | |
275 | } | |
276 | } | |
277 | ||
278 | ||
279 | static void | |
241 | 280 | ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c) |
242 | 281 | { |
243 | 282 | ngx_msec_t timeout; |
255 | 294 | |
256 | 295 | if (ngx_handle_read_event(c->read, 0) != NGX_OK) { |
257 | 296 | ngx_mail_close_connection(c); |
297 | } | |
298 | ||
299 | if (c->read->ready) { | |
300 | ngx_post_event(c->read, &ngx_posted_events); | |
258 | 301 | } |
259 | 302 | |
260 | 303 | if (sscf->greeting_delay) { |