]> git.kaiwu.me - nginx.git/commitdiff
HTTP/3: kept the skipped frame length separate from data length
authorVadim Zhestikov <v.zhestikov@f5.com>
Thu, 23 Jul 2026 00:48:55 +0000 (17:48 -0700)
committerSergey Kandaurov <pluknet@nginx.com>
Thu, 1 Oct 2026 17:19:27 +0000 (21:19 +0400)
ngx_http_v3_parse_data() stored the remaining length of a skipped
(unknown) frame in st->length -- the same field the request body
filter uses for the number of DATA payload bytes to pass on as
request body.  When an unknown frame was split across parser
invocations, the skip was interrupted with st->length holding the
skip remainder; on the next buffer the body filter, which calls
the parser only while st->length == 0, treated that remainder as
request body.

When proxying, this could result in sending unframed bytes, potentially
allowing for bypass of client_max_body_size, which is enforced only on
the DATA path, or an injection.

The fix is to keep unknown frame payload in a separate st->skip counter.

Reported by Hansol Lee of GOTROOT.

src/http/v3/ngx_http_v3_parse.c
src/http/v3/ngx_http_v3_parse.h

index 1ba08c7910574364aac5ece222757899d7f7ef14..573a832ef22ec60ff55f64c389f9192d4a1906ca 100644 (file)
@@ -1861,6 +1861,8 @@ ngx_http_v3_parse_data(ngx_connection_t *c, ngx_http_v3_parse_data_t *st,
                            st->type, st->length);
 
             if (st->type != NGX_HTTP_V3_FRAME_DATA && st->length > 0) {
+                st->skip = st->length;
+                st->length = 0;
                 st->state = sw_skip;
                 break;
             }
@@ -1870,7 +1872,7 @@ ngx_http_v3_parse_data(ngx_connection_t *c, ngx_http_v3_parse_data_t *st,
 
         case sw_skip:
 
-            rc = ngx_http_v3_parse_skip(b, &st->length);
+            rc = ngx_http_v3_parse_skip(b, &st->skip);
             if (rc != NGX_DONE) {
                 return rc;
             }
index c7e1e1ebb9aa12a3081dc66de84564d07b111b75..3db1418dad9084c696b8b472a58b79e381474743 100644 (file)
@@ -122,6 +122,7 @@ typedef struct {
     ngx_uint_t                      state;
     ngx_uint_t                      type;
     ngx_uint_t                      length;
+    ngx_uint_t                      skip;
     ngx_http_v3_parse_varlen_int_t  vlint;
 } ngx_http_v3_parse_data_t;