aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRoman Arutyunyan <arut@nginx.com>2023-01-03 16:24:45 +0400
committerRoman Arutyunyan <arut@nginx.com>2023-01-03 16:24:45 +0400
commitd04f45ac5bddb034ec8c5b0874a7358a991d1b77 (patch)
tree54f91b662850337657f5109bc70b273f8e04cf25 /src
parentf5aa66bd309a4cbec67285770c77db5d33347c27 (diff)
downloadnginx-d04f45ac5bddb034ec8c5b0874a7358a991d1b77.tar.gz
nginx-d04f45ac5bddb034ec8c5b0874a7358a991d1b77.zip
HTTP/3: handled insertion reference to a going to be evicted entry.
As per RFC 9204, section 3.2.2, a new entry can reference an entry in the dynamic table that will be evicted when adding this new entry into the dynamic table. Previously, such inserts resulted in use-after-free since the old entry was evicted before the insertion (ticket #2431). Now it's evicted after the insertion. This change fixes Insert with Name Reference and Duplicate encoder instructions.
Diffstat (limited to 'src')
-rw-r--r--src/http/v3/ngx_http_v3_table.c37
1 files changed, 16 insertions, 21 deletions
diff --git a/src/http/v3/ngx_http_v3_table.c b/src/http/v3/ngx_http_v3_table.c
index 7e07a15b9..f49a8fc5e 100644
--- a/src/http/v3/ngx_http_v3_table.c
+++ b/src/http/v3/ngx_http_v3_table.c
@@ -13,7 +13,7 @@
#define ngx_http_v3_table_entry_size(n, v) ((n)->len + (v)->len + 32)
-static ngx_int_t ngx_http_v3_evict(ngx_connection_t *c, size_t need);
+static ngx_int_t ngx_http_v3_evict(ngx_connection_t *c, size_t target);
static void ngx_http_v3_unblock(void *data);
static ngx_int_t ngx_http_v3_new_entry(ngx_connection_t *c);
@@ -204,13 +204,15 @@ ngx_http_v3_insert(ngx_connection_t *c, ngx_str_t *name, ngx_str_t *value)
size = ngx_http_v3_table_entry_size(name, value);
- if (ngx_http_v3_evict(c, size) != NGX_OK) {
- return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR;
- }
-
h3c = ngx_http_v3_get_session(c);
dt = &h3c->table;
+ if (size > dt->capacity) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "not enough dynamic table capacity");
+ return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR;
+ }
+
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http3 insert [%ui] \"%V\":\"%V\", size:%uz",
dt->base + dt->nelts, name, value, size);
@@ -234,6 +236,10 @@ ngx_http_v3_insert(ngx_connection_t *c, ngx_str_t *name, ngx_str_t *value)
dt->insert_count++;
+ if (ngx_http_v3_evict(c, dt->capacity) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
ngx_post_event(&dt->send_insert_count, &ngx_posted_events);
if (ngx_http_v3_new_entry(c) != NGX_OK) {
@@ -293,14 +299,11 @@ ngx_http_v3_set_capacity(ngx_connection_t *c, ngx_uint_t capacity)
return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR;
}
- dt = &h3c->table;
-
- if (dt->size > capacity) {
- if (ngx_http_v3_evict(c, dt->size - capacity) != NGX_OK) {
- return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR;
- }
+ if (ngx_http_v3_evict(c, capacity) != NGX_OK) {
+ return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR;
}
+ dt = &h3c->table;
max = capacity / 32;
prev_max = dt->capacity / 32;
@@ -345,9 +348,9 @@ ngx_http_v3_cleanup_table(ngx_http_v3_session_t *h3c)
static ngx_int_t
-ngx_http_v3_evict(ngx_connection_t *c, size_t need)
+ngx_http_v3_evict(ngx_connection_t *c, size_t target)
{
- size_t size, target;
+ size_t size;
ngx_uint_t n;
ngx_http_v3_field_t *field;
ngx_http_v3_session_t *h3c;
@@ -355,14 +358,6 @@ ngx_http_v3_evict(ngx_connection_t *c, size_t need)
h3c = ngx_http_v3_get_session(c);
dt = &h3c->table;
-
- if (need > dt->capacity) {
- ngx_log_error(NGX_LOG_ERR, c->log, 0,
- "not enough dynamic table capacity");
- return NGX_ERROR;
- }
-
- target = dt->capacity - need;
n = 0;
while (dt->size > target) {