]> 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 17:20:38 +0000 (21:20 +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 d3af4408d834c25a4f79e8e777e42f1219b3e494..9c97a5b085112e1f673a6638ecd23ba5cd83d127 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;
 }
@@ -620,6 +621,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;
@@ -641,21 +643,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;
@@ -666,6 +670,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;
 }
 
@@ -1548,6 +1554,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);
@@ -1855,8 +1863,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 2e31102df8432dec6b7712c366d127bdf318868f..559b8b9fb2b03d57f215a1d9799cae7f5068688b 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;
 }
@@ -496,6 +497,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;
@@ -517,21 +519,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;
@@ -542,6 +546,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;
 }
 
@@ -1062,6 +1068,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);