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.

Signed-off-by: Roman Arutyunyan <arut@nginx.com>
Origin: <https://freenginx.org/hg/nginx/rev/ceff7ca7785a>
This commit is contained in:
Maxim Dounin authored and Roman Arutyunyan committed 2026-07-15 19:51:22 +04:00
1 parent b767540492
commit 4d32a2703c
2 files changed
+235 -51

No files matched your search

+85 -16
View File
@@ -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_compile(ngx_conf_t *cf,
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, size;
ssize_t n;
ngx_str_t val;
@@ -257,6 +260,8 @@ ngx_stream_log_handler(ngx_stream_session_t *s)
}
}
len += NGX_LINEFEED_SIZE;
if (log[l].syslog_peer) {
/* length of syslog's PRI and HEADER message parts */
@@ -267,8 +272,6 @@ ngx_stream_log_handler(ngx_stream_session_t *s)
goto alloc_line;
}
len += NGX_LINEFEED_SIZE;
buffer = log[l].file ? log[l].file->data : NULL;
if (buffer) {
@@ -284,13 +287,18 @@ ngx_stream_log_handler(ngx_stream_session_t *s)
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);
@@ -313,13 +321,18 @@ ngx_stream_log_handler(ngx_stream_session_t *s)
}
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) {
@@ -663,7 +676,7 @@ ngx_stream_log_flush_handler(ngx_event_t *ev)
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;
@@ -672,6 +685,10 @@ ngx_stream_log_copy_short(ngx_stream_session_t *s, u_char *buf,
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;
@@ -682,9 +699,13 @@ ngx_stream_log_copy_short(ngx_stream_session_t *s, u_char *buf,
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);
}
@@ -745,22 +766,39 @@ 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_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);
if (value == NULL || value->not_found) {
if (ngx_stream_log_check_length(s, buf, end, 1) != NGX_OK) {
return NULL;
}
*buf = '-';
return buf + 1;
}
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);
}
}
@@ -847,9 +885,10 @@ 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_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);
@@ -859,9 +898,21 @@ ngx_stream_log_json_variable(ngx_stream_session_t *s, u_char *buf,
}
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);
}
}
@@ -887,7 +938,7 @@ ngx_stream_log_unescaped_variable_getlen(ngx_stream_session_t *s,
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;
@@ -897,10 +948,28 @@ ngx_stream_log_unescaped_variable(ngx_stream_session_t *s, u_char *buf,
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)
{