[PATCH] Mail: updated ngx_mail_send() to set handlers on s->quit
Maxim Dounin
mdounin at mdounin.ru
Wed Jun 10 10:36:36 UTC 2026
# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1781087610 -10800
# Wed Jun 10 13:33:30 2026 +0300
# Node ID e6ef0412a95a5e9e2bd7243978750475f07f0377
# Parent 67059a7429f113a0af1e0b7d21ff8bf7ef4ac9f7
Mail: updated ngx_mail_send() to set handlers on s->quit.
Most notably, this fixes potential issues when a fatal error message is
sent with ngx_mail_send() with s->quit set, but the read handler is not
updated. Despite s->quit, ngx_mail_send() might not be able to send the
error message immediately, and the read handler might be called on read
events. In particular, in ngx_mail_auth_http_block_read() and in
ngx_mail_proxy_block_read() this could potentially cause accesses to
freed memory or already closed connections in ngx_handle_read_event()
error handling code paths.
Reported by Evan Hellman,
https://github.com/freenginx/nginx/issues/23
https://github.com/freenginx/nginx/issues/24
diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c
--- a/src/mail/ngx_mail_handler.c
+++ b/src/mail/ngx_mail_handler.c
@@ -25,6 +25,7 @@ static ngx_int_t ngx_mail_verify_cert(ng
static void ngx_mail_lingering_close(ngx_connection_t *c);
static void ngx_mail_lingering_close_handler(ngx_event_t *rev);
static void ngx_mail_empty_handler(ngx_event_t *wev);
+static void ngx_mail_block_read(ngx_event_t *rev);
void
@@ -419,8 +420,6 @@ ngx_mail_verify_cert(ngx_mail_session_t
s->out = cscf->protocol->cert_error;
s->quit = 1;
- c->write->handler = ngx_mail_send;
-
ngx_mail_send(s->connection->write);
return NGX_ERROR;
}
@@ -440,8 +439,6 @@ ngx_mail_verify_cert(ngx_mail_session_t
s->out = cscf->protocol->no_cert;
s->quit = 1;
- c->write->handler = ngx_mail_send;
-
ngx_mail_send(s->connection->write);
return NGX_ERROR;
}
@@ -1088,6 +1085,11 @@ ngx_mail_send(ngx_event_t *wev)
delay = (ngx_msec_t) (excess * 1000 / cscf->limit_rate + 1);
ngx_add_timer(wev, delay);
+ if (s->quit) {
+ c->read->handler = ngx_mail_block_read;
+ c->write->handler = ngx_mail_send;
+ }
+
if (ngx_handle_write_event(wev, 0) != NGX_OK) {
ngx_mail_close_connection(c);
}
@@ -1141,6 +1143,11 @@ again:
ngx_add_timer(wev, cscf->timeout);
}
+ if (s->quit) {
+ c->read->handler = ngx_mail_block_read;
+ c->write->handler = ngx_mail_send;
+ }
+
if (ngx_handle_write_event(wev, 0) != NGX_OK) {
ngx_mail_close_connection(c);
return;
@@ -1422,6 +1429,17 @@ ngx_mail_empty_handler(ngx_event_t *wev)
}
+static void
+ngx_mail_block_read(ngx_event_t *rev)
+{
+ ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail block read");
+
+ if (ngx_handle_read_event(rev, 0) != NGX_OK) {
+ ngx_mail_close_connection(rev->data);
+ }
+}
+
+
void
ngx_mail_close_connection(ngx_connection_t *c)
{
More information about the nginx-devel
mailing list