]> git.kaiwu.me - nginx.git/commitdiff
Script: avoid garbage at the end of the result string
authorRoman Arutyunyan <arut@nginx.com>
Fri, 3 Jul 2026 11:11:09 +0000 (15:11 +0400)
committerRoman Arutyunyan <arutyunyan.roman@gmail.com>
Wed, 15 Jul 2026 15:51:22 +0000 (19:51 +0400)
If the script result turned out to be shorter than its predicted
length, the result string contained uninitialized bytes at the end.
The fix is to cut the result string by its actual size.

The following locations returned trailing garbage to the client with
URI "/1234abcd".

    map $uri $foo {
        ~^/(?<bar>[0-9]).*$ $bar;
    }

    location ~(?<bar>[0-9]*)[a-z]*$ {
        return 200 $1:$foo;
    }

    location ~(?<bar>[0-9]*)[a-z]*$ {
        set $qux $1:$foo;
        return 200 $qux;
    }

src/http/modules/ngx_http_rewrite_module.c
src/http/ngx_http_script.c
src/http/ngx_http_script.h
src/stream/ngx_stream_script.c

index ff3b68716d485ebd3614850a4b36b2eec7f4a718..eefe4c8c8933ccfd876407bc14dc0110170c7ea1 100644 (file)
@@ -966,10 +966,11 @@ static char *
 ngx_http_rewrite_value(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
     ngx_str_t *value)
 {
-    ngx_int_t                              n;
-    ngx_http_script_compile_t              sc;
-    ngx_http_script_value_code_t          *val;
-    ngx_http_script_complex_value_code_t  *complex;
+    ngx_int_t                                  n;
+    ngx_http_script_compile_t                  sc;
+    ngx_http_script_value_code_t              *val;
+    ngx_http_script_complex_value_code_t      *complex;
+    ngx_http_script_complex_value_end_code_t  *complex_end;
 
     n = ngx_http_script_variables_count(value);
 
@@ -1016,5 +1017,14 @@ ngx_http_rewrite_value(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
         return NGX_CONF_ERROR;
     }
 
+    complex_end = ngx_http_script_add_code(lcf->codes,
+                              sizeof(ngx_http_script_complex_value_end_code_t),
+                              &complex);
+    if (complex_end == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    complex_end->code = ngx_http_script_complex_value_end_code;
+
     return NGX_CONF_OK;
 }
index c7e28b23171199ae21cf6ad0999ea0f0491dcb64..4d0a6708432a999101212c4082eaaae7a852b4af 100644 (file)
@@ -103,7 +103,8 @@ ngx_http_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val,
         return NGX_ERROR;
     }
 
-    *value = e.buf;
+    value->data = e.buf.data;
+    value->len = e.pos - e.buf.data;
 
     return NGX_OK;
 }
@@ -622,6 +623,7 @@ u_char *
 ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value,
     void *code_lengths, size_t len, void *code_values)
 {
+    size_t                        n;
     ngx_uint_t                    i;
     ngx_http_script_code_pt       code;
     ngx_http_script_len_code_pt   lcode;
@@ -643,21 +645,23 @@ ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value,
     e.request = r;
     e.flushed = 1;
 
+    n = len;
+
     while (*(uintptr_t *) e.ip) {
         lcode = *(ngx_http_script_len_code_pt *) e.ip;
-        len += lcode(&e);
+        n += lcode(&e);
     }
 
 
-    value->len = len;
-    value->data = ngx_pnalloc(r->pool, len);
+    value->len = n;
+    value->data = ngx_pnalloc(r->pool, n);
     if (value->data == NULL) {
         return NULL;
     }
 
     e.ip = code_values;
     e.pos = value->data;
-    e.end = value->data + len;
+    e.end = value->data + n;
 
     while (*(uintptr_t *) e.ip) {
         code = *(ngx_http_script_code_pt *) e.ip;
@@ -668,6 +672,8 @@ ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value,
         return NULL;
     }
 
+    value->len = e.pos + len - value->data;
+
     return e.pos;
 }
 
@@ -1551,6 +1557,8 @@ ngx_http_script_full_name_code(ngx_http_script_engine_t *e)
     }
 
     e->buf = value;
+    e->pos = value.data + value.len;
+    e->end = e->pos;
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
                    "http script fullname: \"%V\"", &value);
@@ -1859,8 +1867,18 @@ ngx_http_script_complex_value_code(ngx_http_script_engine_t *e)
 
     e->pos = e->buf.data;
     e->end = e->buf.data + len;
+}
+
+
+void
+ngx_http_script_complex_value_end_code(ngx_http_script_engine_t *e)
+{
+    e->ip += sizeof(ngx_http_script_complex_value_end_code_t);
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http script complex value end");
 
-    e->sp->len = e->buf.len;
+    e->sp->len = e->pos - e->buf.data;
     e->sp->data = e->buf.data;
     e->sp++;
 }
index b086b266f38f67e398bfc6173be71a397ce61a80..4f2fbd16e846e5742b985b13260de2426f8e96b9 100644 (file)
@@ -200,6 +200,11 @@ typedef struct {
 } ngx_http_script_complex_value_code_t;
 
 
+typedef struct {
+    ngx_http_script_code_pt     code;
+} ngx_http_script_complex_value_end_code_t;
+
+
 typedef struct {
     ngx_http_script_code_pt     code;
     uintptr_t                   value;
@@ -263,6 +268,7 @@ void ngx_http_script_equal_code(ngx_http_script_engine_t *e);
 void ngx_http_script_not_equal_code(ngx_http_script_engine_t *e);
 void ngx_http_script_file_code(ngx_http_script_engine_t *e);
 void ngx_http_script_complex_value_code(ngx_http_script_engine_t *e);
+void ngx_http_script_complex_value_end_code(ngx_http_script_engine_t *e);
 void ngx_http_script_value_code(ngx_http_script_engine_t *e);
 void ngx_http_script_set_var_code(ngx_http_script_engine_t *e);
 void ngx_http_script_var_set_handler_code(ngx_http_script_engine_t *e);
index 431364b49ef9ea67b8ea57067deb52a05833938c..54e5dd55918c9c63d3529e8dfba7d00f7511a030 100644 (file)
@@ -104,7 +104,8 @@ ngx_stream_complex_value(ngx_stream_session_t *s,
         return NGX_ERROR;
     }
 
-    *value = e.buf;
+    value->data = e.buf.data;
+    value->len = e.pos - e.buf.data;
 
     return NGX_OK;
 }
@@ -498,6 +499,7 @@ u_char *
 ngx_stream_script_run(ngx_stream_session_t *s, ngx_str_t *value,
     void *code_lengths, size_t len, void *code_values)
 {
+    size_t                          n;
     ngx_uint_t                      i;
     ngx_stream_script_code_pt       code;
     ngx_stream_script_engine_t      e;
@@ -519,21 +521,23 @@ ngx_stream_script_run(ngx_stream_session_t *s, ngx_str_t *value,
     e.session = s;
     e.flushed = 1;
 
+    n = len;
+
     while (*(uintptr_t *) e.ip) {
         lcode = *(ngx_stream_script_len_code_pt *) e.ip;
-        len += lcode(&e);
+        n += lcode(&e);
     }
 
 
-    value->len = len;
-    value->data = ngx_pnalloc(s->connection->pool, len);
+    value->len = n;
+    value->data = ngx_pnalloc(s->connection->pool, n);
     if (value->data == NULL) {
         return NULL;
     }
 
     e.ip = code_values;
     e.pos = value->data;
-    e.end = value->data + len;
+    e.end = value->data + n;
 
     while (*(uintptr_t *) e.ip) {
         code = *(ngx_stream_script_code_pt *) e.ip;
@@ -544,6 +548,8 @@ ngx_stream_script_run(ngx_stream_session_t *s, ngx_str_t *value,
         return NULL;
     }
 
+    value->len = e.pos + len - value->data;
+
     return e.pos;
 }
 
@@ -1064,6 +1070,8 @@ ngx_stream_script_full_name_code(ngx_stream_script_engine_t *e)
     }
 
     e->buf = value;
+    e->pos = value.data + value.len;
+    e->end = e->pos;
 
     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0,
                    "stream script fullname: \"%V\"", &value);