[nginx] Upstream: blocked read events till sending request.

Maxim Dounin mdounin at mdounin.ru
Tue Feb 10 11:17:23 UTC 2026


details:   http://freenginx.org/hg/nginx/rev/36c9c3fae57f
branches:  
changeset: 9465:36c9c3fae57f
user:      Maxim Dounin <mdounin at mdounin.ru>
date:      Tue Feb 10 05:50:14 2026 +0300
description:
Upstream: blocked read events till sending request.

Previously, SSL initialization only happened on write events, which are
reported once a TCP connection is established.  However, if some data
are received before the write event is reported, the read event might be
reported first, potentially resulting in a plain text response being
accepted when it shouldn't (CVE-2026-1642).

Similarly, if a response was received before the write event was reported
(and hence before the request was sent to the upstream server), switching
to the next upstream server failed to do proper reinitialization, which
used to check the u->request_sent flag.  This resulted in various issues,
most notably previously parsed headers were not cleared.

Normally SSL servers do not send anything before ClientHello from the
client, though formally they are allowed to (for example, HelloRequest
messages may be sent at any time).  Further, returning an immediate error
response might also be seen as valid, for example, in HTTP.  As such,
the fix is to block read events until the write event is reported, ensuring
correct and identical behaviour regardless of the order of events being
reported.

diffstat:

 src/http/ngx_http_upstream.c |  31 +++++++++++++++++++++++++------
 1 files changed, 25 insertions(+), 6 deletions(-)

diffs (69 lines):

diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -52,6 +52,8 @@ static ngx_int_t ngx_http_upstream_send_
 static void ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
     ngx_http_upstream_t *u);
 static void ngx_http_upstream_read_request_handler(ngx_http_request_t *r);
+static void ngx_http_upstream_block_reading(ngx_http_request_t *r,
+    ngx_http_upstream_t *u);
 static void ngx_http_upstream_process_header(ngx_http_request_t *r,
     ngx_http_upstream_t *u);
 static ngx_int_t ngx_http_upstream_test_next(ngx_http_request_t *r,
@@ -1595,7 +1597,7 @@ ngx_http_upstream_connect(ngx_http_reque
     c->read->handler = ngx_http_upstream_handler;
 
     u->write_event_handler = ngx_http_upstream_send_request_handler;
-    u->read_event_handler = ngx_http_upstream_process_header;
+    u->read_event_handler = ngx_http_upstream_block_reading;
 
     c->sendfile &= r->connection->sendfile;
     u->output.sendfile = c->sendfile;
@@ -2138,6 +2140,10 @@ ngx_http_upstream_send_request(ngx_http_
         return;
     }
 
+    if (!u->request_sent) {
+        u->read_event_handler = ngx_http_upstream_process_header;
+    }
+
     sent = c->sent;
 
     if (!u->request_sent) {
@@ -2419,6 +2425,24 @@ ngx_http_upstream_read_request_handler(n
 
 
 static void
+ngx_http_upstream_block_reading(ngx_http_request_t *r, ngx_http_upstream_t *u)
+{
+    ngx_connection_t  *c;
+
+    c = u->peer.connection;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http upstream block reading");
+
+    if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+}
+
+
+static void
 ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
 {
     ssize_t            n;
@@ -2437,11 +2461,6 @@ ngx_http_upstream_process_header(ngx_htt
         return;
     }
 
-    if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) {
-        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
-        return;
-    }
-
     if (u->buffer.start == NULL) {
         u->buffer.start = ngx_palloc(r->pool, u->conf->buffer_size);
         if (u->buffer.start == NULL) {


More information about the nginx-devel mailing list