[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