[PATCH] Access log: buffer overrun protection

Maxim Dounin mdounin at mdounin.ru
Sun Jun 14 20:59:12 UTC 2026


# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1781464439 -10800
#      Sun Jun 14 22:13:59 2026 +0300
# Node ID ec34a87ad20c74ac8ed95ddff647fb03aaf48beb
# Parent  fe5ef747dc2e471967f816f36360013c5a7aa215
Access log: buffer overrun protection.

Similarly to generic script operations, access log script copy operations
now check if there is enough room in the buffer.

diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -17,7 +17,7 @@
 typedef struct ngx_http_log_op_s  ngx_http_log_op_t;
 
 typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf,
-    ngx_http_log_op_t *op);
+    u_char *end, ngx_http_log_op_t *op);
 
 typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r,
     uintptr_t data);
@@ -112,39 +112,42 @@ static void ngx_http_log_flush(ngx_open_
 static void ngx_http_log_flush_handler(ngx_event_t *ev);
 
 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
-    ngx_http_log_op_t *op);
+    u_char *end, ngx_http_log_op_t *op);
 static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
-    ngx_http_log_op_t *op);
+    u_char *end, ngx_http_log_op_t *op);
 static u_char *ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf,
-    ngx_http_log_op_t *op);
+    u_char *end, ngx_http_log_op_t *op);
 static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf,
-    ngx_http_log_op_t *op);
+    u_char *end, ngx_http_log_op_t *op);
 static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
-    ngx_http_log_op_t *op);
+    u_char *end, ngx_http_log_op_t *op);
 static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf,
-    ngx_http_log_op_t *op);
+    u_char *end, ngx_http_log_op_t *op);
 static u_char *ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
-    ngx_http_log_op_t *op);
-static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r,
-    u_char *buf, ngx_http_log_op_t *op);
+    u_char *end, ngx_http_log_op_t *op);
+static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf,
+    u_char *end, ngx_http_log_op_t *op);
 static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
-    ngx_http_log_op_t *op);
+    u_char *end, ngx_http_log_op_t *op);
 
 static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
     ngx_http_log_op_t *op, ngx_str_t *value, ngx_uint_t escape);
 static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r,
     uintptr_t data);
 static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf,
-    ngx_http_log_op_t *op);
+    u_char *end, ngx_http_log_op_t *op);
 static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size);
 static size_t ngx_http_log_json_variable_getlen(ngx_http_request_t *r,
     uintptr_t data);
 static u_char *ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf,
-    ngx_http_log_op_t *op);
+    u_char *end, ngx_http_log_op_t *op);
 static size_t ngx_http_log_unescaped_variable_getlen(ngx_http_request_t *r,
     uintptr_t data);
 static u_char *ngx_http_log_unescaped_variable(ngx_http_request_t *r,
-    u_char *buf, ngx_http_log_op_t *op);
+    u_char *buf, u_char *end, ngx_http_log_op_t *op);
+
+static ngx_int_t ngx_http_log_check_length(ngx_http_request_t *r,
+    u_char *buf, u_char *end, size_t len);
 
 
 static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
@@ -253,7 +256,7 @@ static ngx_http_log_var_t  ngx_http_log_
 static ngx_int_t
 ngx_http_log_handler(ngx_http_request_t *r)
 {
-    u_char                   *line, *p;
+    u_char                   *line, *p, *end;
     size_t                    len;
     ngx_str_t                 val;
     ngx_uint_t                i, l;
@@ -308,6 +311,8 @@ ngx_http_log_handler(ngx_http_request_t 
             }
         }
 
+        len += NGX_LINEFEED_SIZE;
+
         if (log[l].syslog_peer) {
 
             /* length of syslog's PRI and HEADER message parts */
@@ -318,8 +323,6 @@ ngx_http_log_handler(ngx_http_request_t 
             goto alloc_line;
         }
 
-        len += NGX_LINEFEED_SIZE;
-
         buffer = log[l].file ? log[l].file->data : NULL;
 
         if (buffer) {
@@ -335,13 +338,18 @@ ngx_http_log_handler(ngx_http_request_t 
             if (len <= (size_t) (buffer->last - buffer->pos)) {
 
                 p = buffer->pos;
+                end = p + len - NGX_LINEFEED_SIZE;
 
                 if (buffer->event && p == buffer->start) {
                     ngx_add_timer(buffer->event, buffer->flush);
                 }
 
-                for (i = 0; i < log[l].format->ops->nelts; i++) {
-                    p = op[i].run(r, p, &op[i]);
+                for (i = 0; i < log[l].format->ops->nelts && p; i++) {
+                    p = op[i].run(r, p, end, &op[i]);
+                }
+
+                if (p == NULL) {
+                    return NGX_ERROR;
                 }
 
                 ngx_linefeed(p);
@@ -364,13 +372,18 @@ ngx_http_log_handler(ngx_http_request_t 
         }
 
         p = line;
+        end = line + len - NGX_LINEFEED_SIZE;
 
         if (log[l].syslog_peer) {
             p = ngx_syslog_add_header(log[l].syslog_peer, line);
         }
 
-        for (i = 0; i < log[l].format->ops->nelts; i++) {
-            p = op[i].run(r, p, &op[i]);
+        for (i = 0; i < log[l].format->ops->nelts && p; i++) {
+            p = op[i].run(r, p, end, &op[i]);
+        }
+
+        if (p == NULL) {
+            return NGX_ERROR;
         }
 
         if (log[l].syslog_peer) {
@@ -757,7 +770,7 @@ ngx_http_log_flush_handler(ngx_event_t *
 
 
 static u_char *
-ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
+ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf, u_char *end,
     ngx_http_log_op_t *op)
 {
     size_t     len;
@@ -766,6 +779,10 @@ ngx_http_log_copy_short(ngx_http_request
     len = op->len;
     data = op->data;
 
+    if (ngx_http_log_check_length(r, buf, end, len) != NGX_OK) {
+        return NULL;
+    }
+
     while (len--) {
         *buf++ = (u_char) (data & 0xff);
         data >>= 8;
@@ -776,16 +793,25 @@ ngx_http_log_copy_short(ngx_http_request
 
 
 static u_char *
-ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf,
+ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf, u_char *end,
     ngx_http_log_op_t *op)
 {
+    if (ngx_http_log_check_length(r, buf, end, op->len) != NGX_OK) {
+        return NULL;
+    }
+
     return ngx_cpymem(buf, (u_char *) op->data, op->len);
 }
 
 
 static u_char *
-ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
+ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, u_char *end,
+    ngx_http_log_op_t *op)
 {
+    if (ngx_http_log_check_length(r, buf, end, 1) != NGX_OK) {
+        return NULL;
+    }
+
     if (r->pipeline) {
         *buf = 'p';
     } else {
@@ -797,24 +823,43 @@ ngx_http_log_pipe(ngx_http_request_t *r,
 
 
 static u_char *
-ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
+ngx_http_log_time(ngx_http_request_t *r, u_char *buf, u_char *end,
+    ngx_http_log_op_t *op)
 {
+    if (ngx_http_log_check_length(r, buf, end, ngx_cached_http_log_time.len)
+        != NGX_OK)
+    {
+        return NULL;
+    }
+
     return ngx_cpymem(buf, ngx_cached_http_log_time.data,
                       ngx_cached_http_log_time.len);
 }
 
 static u_char *
-ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
+ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf, u_char *end,
+    ngx_http_log_op_t *op)
 {
+    if (ngx_http_log_check_length(r, buf, end, ngx_cached_http_log_iso8601.len)
+        != NGX_OK)
+    {
+        return NULL;
+    }
+
     return ngx_cpymem(buf, ngx_cached_http_log_iso8601.data,
                       ngx_cached_http_log_iso8601.len);
 }
 
 static u_char *
-ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
+ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, u_char *end,
+    ngx_http_log_op_t *op)
 {
     ngx_time_t  *tp;
 
+    if (ngx_http_log_check_length(r, buf, end, NGX_TIME_T_LEN + 4) != NGX_OK) {
+        return NULL;
+    }
+
     tp = ngx_timeofday();
 
     return ngx_sprintf(buf, "%T.%03M", tp->sec, tp->msec);
@@ -822,11 +867,15 @@ ngx_http_log_msec(ngx_http_request_t *r,
 
 
 static u_char *
-ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
+ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf, u_char *end,
     ngx_http_log_op_t *op)
 {
     ngx_msec_int_t  ms;
 
+    if (ngx_http_log_check_length(r, buf, end, NGX_TIME_T_LEN + 4) != NGX_OK) {
+        return NULL;
+    }
+
     ms = (ngx_msec_int_t) (ngx_current_msec - r->start_time);
     ms = ngx_max(ms, 0);
 
@@ -835,10 +884,15 @@ ngx_http_log_request_time(ngx_http_reque
 
 
 static u_char *
-ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
+ngx_http_log_status(ngx_http_request_t *r, u_char *buf, u_char *end,
+    ngx_http_log_op_t *op)
 {
     ngx_uint_t  status;
 
+    if (ngx_http_log_check_length(r, buf, end, NGX_INT_T_LEN) != NGX_OK) {
+        return NULL;
+    }
+
     if (r->err_status) {
         status = r->err_status;
 
@@ -857,9 +911,13 @@ ngx_http_log_status(ngx_http_request_t *
 
 
 static u_char *
-ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
+ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf, u_char *end,
     ngx_http_log_op_t *op)
 {
+    if (ngx_http_log_check_length(r, buf, end, NGX_OFF_T_LEN) != NGX_OK) {
+        return NULL;
+    }
+
     return ngx_sprintf(buf, "%O", r->connection->sent);
 }
 
@@ -870,11 +928,15 @@ ngx_http_log_bytes_sent(ngx_http_request
  */
 
 static u_char *
-ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf,
+ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf, u_char *end,
     ngx_http_log_op_t *op)
 {
     off_t  length;
 
+    if (ngx_http_log_check_length(r, buf, end, NGX_OFF_T_LEN) != NGX_OK) {
+        return NULL;
+    }
+
     length = r->connection->sent - r->header_size;
 
     if (length > 0) {
@@ -888,9 +950,13 @@ ngx_http_log_body_bytes_sent(ngx_http_re
 
 
 static u_char *
-ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
+ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, u_char *end,
     ngx_http_log_op_t *op)
 {
+    if (ngx_http_log_check_length(r, buf, end, NGX_OFF_T_LEN) != NGX_OK) {
+        return NULL;
+    }
+
     return ngx_sprintf(buf, "%O", r->request_length);
 }
 
@@ -951,21 +1017,39 @@ ngx_http_log_variable_getlen(ngx_http_re
 
 
 static u_char *
-ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
+ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, u_char *end,
+    ngx_http_log_op_t *op)
 {
+    uintptr_t                   len;
     ngx_http_variable_value_t  *value;
 
     value = ngx_http_get_indexed_variable(r, op->data);
 
     if (value == NULL || value->not_found) {
+        if (ngx_http_log_check_length(r, buf, end, 1) != NGX_OK) {
+            return NULL;
+        }
+
         *buf = '-';
         return buf + 1;
     }
 
     if (value->escape == 0) {
+        if (ngx_http_log_check_length(r, buf, end, value->len) != NGX_OK) {
+            return NULL;
+        }
+
         return ngx_cpymem(buf, value->data, value->len);
 
     } else {
+        len = ngx_http_log_escape(NULL, value->data, value->len);
+
+        if (ngx_http_log_check_length(r, buf, end, value->len + len * 3)
+            != NGX_OK)
+        {
+            return NULL;
+        }
+
         return (u_char *) ngx_http_log_escape(buf, value->data, value->len);
     }
 }
@@ -1052,9 +1136,10 @@ ngx_http_log_json_variable_getlen(ngx_ht
 
 
 static u_char *
-ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf,
+ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf, u_char *end,
     ngx_http_log_op_t *op)
 {
+    uintptr_t                   len;
     ngx_http_variable_value_t  *value;
 
     value = ngx_http_get_indexed_variable(r, op->data);
@@ -1064,9 +1149,21 @@ ngx_http_log_json_variable(ngx_http_requ
     }
 
     if (value->escape == 0) {
+        if (ngx_http_log_check_length(r, buf, end, value->len) != NGX_OK) {
+            return NULL;
+        }
+
         return ngx_cpymem(buf, value->data, value->len);
 
     } else {
+        len = ngx_escape_json(NULL, value->data, value->len);
+
+        if (ngx_http_log_check_length(r, buf, end, value->len + len)
+            != NGX_OK)
+        {
+            return NULL;
+        }
+
         return (u_char *) ngx_escape_json(buf, value->data, value->len);
     }
 }
@@ -1091,7 +1188,7 @@ ngx_http_log_unescaped_variable_getlen(n
 
 static u_char *
 ngx_http_log_unescaped_variable(ngx_http_request_t *r, u_char *buf,
-    ngx_http_log_op_t *op)
+    u_char *end, ngx_http_log_op_t *op)
 {
     ngx_http_variable_value_t  *value;
 
@@ -1101,10 +1198,28 @@ ngx_http_log_unescaped_variable(ngx_http
         return buf;
     }
 
+    if (ngx_http_log_check_length(r, buf, end, value->len) != NGX_OK) {
+        return NULL;
+    }
+
     return ngx_cpymem(buf, value->data, value->len);
 }
 
 
+static ngx_int_t
+ngx_http_log_check_length(ngx_http_request_t *r, u_char *buf, u_char *end,
+    size_t len)
+{
+    if (end - buf < (ssize_t) len) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                      "no buffer space in log script copy");
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
 static void *
 ngx_http_log_create_main_conf(ngx_conf_t *cf)
 {
diff --git a/src/stream/ngx_stream_log_module.c b/src/stream/ngx_stream_log_module.c
--- a/src/stream/ngx_stream_log_module.c
+++ b/src/stream/ngx_stream_log_module.c
@@ -17,7 +17,7 @@
 typedef struct ngx_stream_log_op_s  ngx_stream_log_op_t;
 
 typedef u_char *(*ngx_stream_log_op_run_pt) (ngx_stream_session_t *s,
-    u_char *buf, ngx_stream_log_op_t *op);
+    u_char *buf, u_char *end, ngx_stream_log_op_t *op);
 
 typedef size_t (*ngx_stream_log_op_getlen_pt) (ngx_stream_session_t *s,
     uintptr_t data);
@@ -115,16 +115,19 @@ static ngx_int_t ngx_stream_log_variable
 static size_t ngx_stream_log_variable_getlen(ngx_stream_session_t *s,
     uintptr_t data);
 static u_char *ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf,
-    ngx_stream_log_op_t *op);
+    u_char *end, ngx_stream_log_op_t *op);
 static uintptr_t ngx_stream_log_escape(u_char *dst, u_char *src, size_t size);
 static size_t ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s,
     uintptr_t data);
 static u_char *ngx_stream_log_json_variable(ngx_stream_session_t *s,
-    u_char *buf, ngx_stream_log_op_t *op);
+    u_char *buf, u_char *end, ngx_stream_log_op_t *op);
 static size_t ngx_stream_log_unescaped_variable_getlen(ngx_stream_session_t *s,
     uintptr_t data);
 static u_char *ngx_stream_log_unescaped_variable(ngx_stream_session_t *s,
-    u_char *buf, ngx_stream_log_op_t *op);
+    u_char *buf, u_char *end, ngx_stream_log_op_t *op);
+
+static ngx_int_t ngx_stream_log_check_length(ngx_stream_session_t *s,
+    u_char *buf, u_char *end, size_t len);
 
 
 static void *ngx_stream_log_create_main_conf(ngx_conf_t *cf);
@@ -200,7 +203,7 @@ ngx_module_t  ngx_stream_log_module = {
 static ngx_int_t
 ngx_stream_log_handler(ngx_stream_session_t *s)
 {
-    u_char                     *line, *p;
+    u_char                     *line, *p, *end;
     size_t                      len;
     ngx_str_t                   val;
     ngx_uint_t                  i, l;
@@ -256,6 +259,8 @@ ngx_stream_log_handler(ngx_stream_sessio
             }
         }
 
+        len += NGX_LINEFEED_SIZE;
+
         if (log[l].syslog_peer) {
 
             /* length of syslog's PRI and HEADER message parts */
@@ -266,8 +271,6 @@ ngx_stream_log_handler(ngx_stream_sessio
             goto alloc_line;
         }
 
-        len += NGX_LINEFEED_SIZE;
-
         buffer = log[l].file ? log[l].file->data : NULL;
 
         if (buffer) {
@@ -283,13 +286,18 @@ ngx_stream_log_handler(ngx_stream_sessio
             if (len <= (size_t) (buffer->last - buffer->pos)) {
 
                 p = buffer->pos;
+                end = p + len - NGX_LINEFEED_SIZE;
 
                 if (buffer->event && p == buffer->start) {
                     ngx_add_timer(buffer->event, buffer->flush);
                 }
 
-                for (i = 0; i < log[l].format->ops->nelts; i++) {
-                    p = op[i].run(s, p, &op[i]);
+                for (i = 0; i < log[l].format->ops->nelts && p; i++) {
+                    p = op[i].run(s, p, end, &op[i]);
+                }
+
+                if (p == NULL) {
+                    return NGX_ERROR;
                 }
 
                 ngx_linefeed(p);
@@ -312,13 +320,18 @@ ngx_stream_log_handler(ngx_stream_sessio
         }
 
         p = line;
+        end = p + len - NGX_LINEFEED_SIZE;
 
         if (log[l].syslog_peer) {
             p = ngx_syslog_add_header(log[l].syslog_peer, line);
         }
 
-        for (i = 0; i < log[l].format->ops->nelts; i++) {
-            p = op[i].run(s, p, &op[i]);
+        for (i = 0; i < log[l].format->ops->nelts && p; i++) {
+            p = op[i].run(s, p, end, &op[i]);
+        }
+
+        if (p == NULL) {
+            return NGX_ERROR;
         }
 
         if (log[l].syslog_peer) {
@@ -650,7 +663,7 @@ ngx_stream_log_flush_handler(ngx_event_t
 
 
 static u_char *
-ngx_stream_log_copy_short(ngx_stream_session_t *s, u_char *buf,
+ngx_stream_log_copy_short(ngx_stream_session_t *s, u_char *buf, u_char *end,
     ngx_stream_log_op_t *op)
 {
     size_t     len;
@@ -659,6 +672,10 @@ ngx_stream_log_copy_short(ngx_stream_ses
     len = op->len;
     data = op->data;
 
+    if (ngx_stream_log_check_length(s, buf, end, len) != NGX_OK) {
+        return NULL;
+    }
+
     while (len--) {
         *buf++ = (u_char) (data & 0xff);
         data >>= 8;
@@ -669,9 +686,13 @@ ngx_stream_log_copy_short(ngx_stream_ses
 
 
 static u_char *
-ngx_stream_log_copy_long(ngx_stream_session_t *s, u_char *buf,
+ngx_stream_log_copy_long(ngx_stream_session_t *s, u_char *buf, u_char *end,
     ngx_stream_log_op_t *op)
 {
+    if (ngx_stream_log_check_length(s, buf, end, op->len) != NGX_OK) {
+        return NULL;
+    }
+
     return ngx_cpymem(buf, (u_char *) op->data, op->len);
 }
 
@@ -732,9 +753,10 @@ ngx_stream_log_variable_getlen(ngx_strea
 
 
 static u_char *
-ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf,
+ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf, u_char *end,
     ngx_stream_log_op_t *op)
 {
+    uintptr_t                     len;
     ngx_stream_variable_value_t  *value;
 
     value = ngx_stream_get_indexed_variable(s, op->data);
@@ -745,9 +767,21 @@ ngx_stream_log_variable(ngx_stream_sessi
     }
 
     if (value->escape == 0) {
+        if (ngx_stream_log_check_length(s, buf, end, value->len) != NGX_OK) {
+            return NULL;
+        }
+
         return ngx_cpymem(buf, value->data, value->len);
 
     } else {
+        len = ngx_stream_log_escape(NULL, value->data, value->len);
+
+        if (ngx_stream_log_check_length(s, buf, end, value->len + len * 3)
+            != NGX_OK)
+        {
+            return NULL;
+        }
+
         return (u_char *) ngx_stream_log_escape(buf, value->data, value->len);
     }
 }
@@ -834,9 +868,10 @@ ngx_stream_log_json_variable_getlen(ngx_
 
 
 static u_char *
-ngx_stream_log_json_variable(ngx_stream_session_t *s, u_char *buf,
+ngx_stream_log_json_variable(ngx_stream_session_t *s, u_char *buf, u_char *end,
     ngx_stream_log_op_t *op)
 {
+    uintptr_t                     len;
     ngx_stream_variable_value_t  *value;
 
     value = ngx_stream_get_indexed_variable(s, op->data);
@@ -846,9 +881,21 @@ ngx_stream_log_json_variable(ngx_stream_
     }
 
     if (value->escape == 0) {
+        if (ngx_stream_log_check_length(s, buf, end, value->len) != NGX_OK) {
+            return NULL;
+        }
+
         return ngx_cpymem(buf, value->data, value->len);
 
     } else {
+        len = ngx_escape_json(NULL, value->data, value->len);
+
+        if (ngx_stream_log_check_length(s, buf, end, value->len + len)
+            != NGX_OK)
+        {
+            return NULL;
+        }
+
         return (u_char *) ngx_escape_json(buf, value->data, value->len);
     }
 }
@@ -874,7 +921,7 @@ ngx_stream_log_unescaped_variable_getlen
 
 static u_char *
 ngx_stream_log_unescaped_variable(ngx_stream_session_t *s, u_char *buf,
-                                  ngx_stream_log_op_t *op)
+    u_char *end, ngx_stream_log_op_t *op)
 {
     ngx_stream_variable_value_t  *value;
 
@@ -884,10 +931,28 @@ ngx_stream_log_unescaped_variable(ngx_st
         return buf;
     }
 
+    if (ngx_stream_log_check_length(s, buf, end, value->len) != NGX_OK) {
+        return NULL;
+    }
+
     return ngx_cpymem(buf, value->data, value->len);
 }
 
 
+static ngx_int_t
+ngx_stream_log_check_length(ngx_stream_session_t *s, u_char *buf, u_char *end,
+    size_t len)
+{
+    if (end - buf < (ssize_t) len) {
+        ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
+                      "no buffer space in log script copy");
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
 static void *
 ngx_stream_log_create_main_conf(ngx_conf_t *cf)
 {



More information about the nginx-devel mailing list