CBL-Mariner/SPECS/nginx/CVE-2023-44487.patch

156 строки
5.7 KiB
Diff

diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
index 7c05ff1e7..13dcd0e0f 100644
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -194,6 +194,9 @@ static void ngx_http_v2_node_children_update(ngx_http_v2_node_t *node);
static void ngx_http_v2_pool_cleanup(void *data);
+static void ngx_http_v2_update_stream_rate(ngx_http_v2_connection_t *h2c);
+
+
static ngx_http_v2_handler_pt ngx_http_v2_frame_states[] = {
ngx_http_v2_state_data, /* NGX_HTTP_V2_DATA_FRAME */
@@ -1190,6 +1193,23 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos,
return ngx_http_v2_state_complete(h2c, pos, end);
}
+static void
+ngx_http_v2_update_stream_rate(ngx_http_v2_connection_t *h2c)
+{
+ ngx_http_v2_srv_conf_t *h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
+ ngx_http_v2_module);
+
+ /* dividing time by configured interval gives us the fixed window id */
+ if (h2c->last_stream_record_time / h2scf->stream_rate_interval_ms
+ != ngx_current_msec / h2scf->stream_rate_interval_ms)
+ {
+ h2c->stream_rate = 0;
+ h2c->last_stream_record_time = ngx_current_msec;
+ }
+
+ h2c->stream_rate++;
+}
+
static u_char *
ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos,
@@ -1321,6 +1341,27 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos,
goto rst_stream;
}
+ /*
+ * track the number of streams per connection
+ * if stream rate exceeds the limit, send a GOAWAY frame
+ */
+ ngx_http_v2_update_stream_rate(h2c);
+
+ if (h2scf->max_stream_rate != 0
+ && h2c->stream_rate >= (double) h2scf->max_stream_rate) {
+ ngx_log_error(NGX_LOG_ERR, h2c->connection->log, 0,
+ "frameshift detected, conn: %d, mitigation enabled: %d, stream rate: %ui",
+ h2c->connection->fd, h2scf->enable_frameshift_mitigation, h2c->stream_rate);
+
+ if (h2scf->enable_frameshift_mitigation) {
+ /*
+ * finalize connection sends goaway and closes the connection
+ * when there are no more active streams
+ */
+ return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM);
+ }
+ }
+
if (!h2c->settings_ack
&& !(h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG)
&& h2scf->preread_size < NGX_HTTP_V2_DEFAULT_WINDOW)
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
index cb9014ccf..cf5510165 100644
--- a/src/http/v2/ngx_http_v2_module.h
+++ b/src/http/v2/ngx_http_v2_module.h
@@ -26,6 +26,9 @@ typedef struct {
ngx_uint_t concurrent_pushes;
size_t preread_size;
ngx_uint_t streams_index_mask;
+ ngx_uint_t max_stream_rate;
+ ngx_msec_t stream_rate_interval_ms;
+ ngx_flag_t enable_frameshift_mitigation;
} ngx_http_v2_srv_conf_t;
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
index cb9014ccf..cf5510165 100644
--- a/src/http/v2/ngx_http_v2.h
+++ b/src/http/v2/ngx_http_v2.h
@@ -126,6 +126,9 @@ struct ngx_http_v2_connection_s {
ngx_uint_t idle;
ngx_uint_t priority_limit;
+ ngx_uint_t stream_rate;
+ ngx_msec_t last_stream_record_time;
+
ngx_uint_t pushing;
ngx_uint_t concurrent_pushes;
diff --git a/src/http/v2/ngx_http_v2_module.c b/src/http/v2/ngx_http_v2_module.c
index 62af9a543..90266404c 100644
--- a/src/http/v2/ngx_http_v2_module.c
+++ b/src/http/v2/ngx_http_v2_module.c
@@ -103,6 +103,27 @@ static ngx_command_t ngx_http_v2_commands[] = {
offsetof(ngx_http_v2_srv_conf_t, concurrent_pushes),
NULL },
+ { ngx_string("http2_max_stream_rate"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ NGX_HTTP_SRV_CONF_OFFSET,
+ offsetof(ngx_http_v2_srv_conf_t, max_stream_rate),
+ NULL },
+
+ { ngx_string("http2_stream_rate_interval_ms"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_msec_slot,
+ NGX_HTTP_SRV_CONF_OFFSET,
+ offsetof(ngx_http_v2_srv_conf_t, stream_rate_interval_ms),
+ NULL },
+
+ { ngx_string("http2_frameshift_mitigation"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_SRV_CONF_OFFSET,
+ offsetof(ngx_http_v2_srv_conf_t, enable_frameshift_mitigation),
+ NULL },
+
{ ngx_string("http2_max_requests"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_http_v2_obsolete,
@@ -323,6 +344,12 @@ ngx_http_v2_create_srv_conf(ngx_conf_t *cf)
h2scf->streams_index_mask = NGX_CONF_UNSET_UINT;
+ h2scf->max_stream_rate = NGX_CONF_UNSET_UINT;
+
+ h2scf->stream_rate_interval_ms = NGX_CONF_UNSET_MSEC;
+
+ h2scf->enable_frameshift_mitigation = NGX_CONF_UNSET;
+
return h2scf;
}
@@ -345,6 +372,15 @@ ngx_http_v2_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_uint_value(conf->streams_index_mask,
prev->streams_index_mask, 32 - 1);
+ ngx_conf_merge_uint_value(conf->max_stream_rate,
+ prev->max_stream_rate, 0);
+
+ ngx_conf_merge_uint_value(conf->stream_rate_interval_ms,
+ prev->stream_rate_interval_ms, 100.0);
+
+ ngx_conf_merge_value(conf->enable_frameshift_mitigation,
+ prev->enable_frameshift_mitigation, 0);
+
return NGX_CONF_OK;
}