]> git.kaiwu.me - nginx.git/commitdiff
HTTP: uniform checks in ngx_http_alloc_large_header_buffer().
authorVladimir Khomutov <vl@wbsrv.ru>
Wed, 29 Nov 2023 08:13:05 +0000 (11:13 +0300)
committerVladimir Khomutov <vl@wbsrv.ru>
Wed, 29 Nov 2023 08:13:05 +0000 (11:13 +0300)
If URI is not fully parsed yet, some pointers are not set.  As a result,
the calculation of "new + (ptr - old)" expression is flawed.

According to C11, 6.5.6 Additive operators, p.9:

: When two pointers are subtracted, both shall point to elements
: of the same array object, or one past the last element of the
: array object

Since "ptr" is not set, subtraction leads to undefined behaviour, because
"ptr" and "old" are not in the same buffer (i.e. array objects).

Prodded by GCC undefined behaviour sanitizer.

src/http/ngx_http_request.c

index 058d502866760e3cd7f876a21bbd41e80393114f..21738ff4c58dbc8ea4753122d629edff2c657d8a 100644 (file)
@@ -1718,14 +1718,23 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r,
             r->request_end = new + (r->request_end - old);
         }
 
-        r->method_end = new + (r->method_end - old);
+        if (r->method_end) {
+            r->method_end = new + (r->method_end - old);
+        }
+
+        if (r->uri_start) {
+            r->uri_start = new + (r->uri_start - old);
+        }
 
-        r->uri_start = new + (r->uri_start - old);
-        r->uri_end = new + (r->uri_end - old);
+        if (r->uri_end) {
+            r->uri_end = new + (r->uri_end - old);
+        }
 
         if (r->schema_start) {
             r->schema_start = new + (r->schema_start - old);
-            r->schema_end = new + (r->schema_end - old);
+            if (r->schema_end) {
+                r->schema_end = new + (r->schema_end - old);
+            }
         }
 
         if (r->host_start) {
@@ -1749,9 +1758,18 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r,
 
     } else {
         r->header_name_start = new;
-        r->header_name_end = new + (r->header_name_end - old);
-        r->header_start = new + (r->header_start - old);
-        r->header_end = new + (r->header_end - old);
+
+        if (r->header_name_end) {
+            r->header_name_end = new + (r->header_name_end - old);
+        }
+
+        if (r->header_start) {
+            r->header_start = new + (r->header_start - old);
+        }
+
+        if (r->header_end) {
+            r->header_end = new + (r->header_end - old);
+        }
     }
 
     r->header_in = b;