Last active
August 14, 2019 00:19
-
-
Save thibaultcha/fabe7857df349ce28ba388474f323429 to your computer and use it in GitHub Desktop.
NGINX [1.11.2 + 1.13.6] CVE-2018-16843 CVE-2018-16844 CVE-2019-9511 CVE-2019-9513 CVE-2019-9516
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c | |
index 19e5f3a0..cef8b5b5 100644 | |
--- a/src/http/v2/ngx_http_v2.c | |
+++ b/src/http/v2/ngx_http_v2.c | |
@@ -623,6 +623,7 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) | |
h2c->pool = NULL; | |
h2c->free_frames = NULL; | |
+ h2c->frames = 0; | |
h2c->free_fake_connections = NULL; | |
#if (NGX_HTTP_SSL) | |
@@ -2589,7 +2590,7 @@ ngx_http_v2_get_frame(ngx_http_v2_connection_t *h2c, size_t length, | |
frame->blocked = 0; | |
- } else { | |
+ } else if (h2c->frames < 10000) { | |
pool = h2c->pool ? h2c->pool : h2c->connection->pool; | |
frame = ngx_pcalloc(pool, sizeof(ngx_http_v2_out_frame_t)); | |
@@ -2613,6 +2614,15 @@ ngx_http_v2_get_frame(ngx_http_v2_connection_t *h2c, size_t length, | |
frame->last = frame->first; | |
frame->handler = ngx_http_v2_frame_handler; | |
+ | |
+ h2c->frames++; | |
+ | |
+ } else { | |
+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
+ "http2 flood detected"); | |
+ | |
+ h2c->connection->error = 1; | |
+ return NULL; | |
} | |
#if (NGX_DEBUG) | |
@@ -4135,13 +4145,20 @@ ngx_http_v2_idle_handler(ngx_event_t *rev) | |
#endif | |
+ h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, | |
+ ngx_http_v2_module); | |
+ | |
+ if (h2c->idle++ > 10 * 1000) { | |
+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
+ "http2 flood detected"); | |
+ ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); | |
+ return; | |
+ } | |
+ | |
c->destroyed = 0; | |
c->idle = 0; | |
ngx_reusable_connection(c, 0); | |
- h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, | |
- ngx_http_v2_module); | |
- | |
h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); | |
if (h2c->pool == NULL) { | |
ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | |
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h | |
index 9e738aa5..524e5aff 100644 | |
--- a/src/http/v2/ngx_http_v2.h | |
+++ b/src/http/v2/ngx_http_v2.h | |
@@ -115,6 +115,8 @@ struct ngx_http_v2_connection_s { | |
ngx_http_connection_t *http_connection; | |
ngx_uint_t processing; | |
+ ngx_uint_t frames; | |
+ ngx_uint_t idle; | |
size_t send_window; | |
size_t recv_window; | |
-- | |
2.20.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c | |
index cef8b5b5..b82f57b4 100644 | |
--- a/src/http/v2/ngx_http_v2.c | |
+++ b/src/http/v2/ngx_http_v2.c | |
@@ -245,6 +245,8 @@ ngx_http_v2_init(ngx_event_t *rev) | |
h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); | |
+ h2c->priority_limit = h2scf->concurrent_streams; | |
+ | |
h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); | |
if (h2c->pool == NULL) { | |
ngx_http_close_connection(c); | |
@@ -1488,6 +1490,14 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, | |
header->name.len = h2c->state.field_end - h2c->state.field_start; | |
header->name.data = h2c->state.field_start; | |
+ if (header->name.len == 0) { | |
+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
+ "client sent zero header name length"); | |
+ | |
+ return ngx_http_v2_connection_error(h2c, | |
+ NGX_HTTP_V2_PROTOCOL_ERROR); | |
+ } | |
+ | |
return ngx_http_v2_state_field_len(h2c, pos, end); | |
} | |
@@ -1737,6 +1747,13 @@ ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos, | |
return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
} | |
+ if (--h2c->priority_limit == 0) { | |
+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
+ "client sent too many PRIORITY frames"); | |
+ | |
+ return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM); | |
+ } | |
+ | |
if (end - pos < NGX_HTTP_V2_PRIORITY_SIZE) { | |
return ngx_http_v2_state_save(h2c, pos, end, | |
ngx_http_v2_state_priority); | |
@@ -2795,6 +2812,8 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c) | |
h2c->processing++; | |
+ h2c->priority_limit += h2scf->concurrent_streams; | |
+ | |
return stream; | |
} | |
@@ -2932,10 +2951,6 @@ ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header) | |
ngx_uint_t i; | |
ngx_http_core_srv_conf_t *cscf; | |
- if (header->name.len == 0) { | |
- return NGX_ERROR; | |
- } | |
- | |
r->invalid_header = 0; | |
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); | |
@@ -4009,6 +4024,8 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) | |
*/ | |
pool = stream->pool; | |
+ h2c->frames -= stream->frames; | |
+ | |
ngx_http_free_request(stream->request, rc); | |
if (pool != h2c->state.pool) { | |
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h | |
index 524e5aff..89b76e0c 100644 | |
--- a/src/http/v2/ngx_http_v2.h | |
+++ b/src/http/v2/ngx_http_v2.h | |
@@ -117,6 +117,7 @@ struct ngx_http_v2_connection_s { | |
ngx_uint_t processing; | |
ngx_uint_t frames; | |
ngx_uint_t idle; | |
+ ngx_uint_t priority_limit; | |
size_t send_window; | |
size_t recv_window; | |
@@ -181,6 +182,8 @@ struct ngx_http_v2_stream_s { | |
ngx_buf_t *preread; | |
+ ngx_uint_t frames; | |
+ | |
ngx_http_v2_out_frame_t *free_frames; | |
ngx_chain_t *free_frame_headers; | |
ngx_chain_t *free_bufs; | |
diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c | |
index 39ff1030..ad877f66 100644 | |
--- a/src/http/v2/ngx_http_v2_filter_module.c | |
+++ b/src/http/v2/ngx_http_v2_filter_module.c | |
@@ -974,22 +974,34 @@ static ngx_http_v2_out_frame_t * | |
ngx_http_v2_filter_get_data_frame(ngx_http_v2_stream_t *stream, | |
size_t len, ngx_chain_t *first, ngx_chain_t *last) | |
{ | |
- u_char flags; | |
- ngx_buf_t *buf; | |
- ngx_chain_t *cl; | |
- ngx_http_v2_out_frame_t *frame; | |
+ u_char flags; | |
+ ngx_buf_t *buf; | |
+ ngx_chain_t *cl; | |
+ ngx_http_v2_out_frame_t *frame; | |
+ ngx_http_v2_connection_t *h2c; | |
frame = stream->free_frames; | |
+ h2c = stream->connection; | |
if (frame) { | |
stream->free_frames = frame->next; | |
- } else { | |
+ } else if (h2c->frames < 10000) { | |
frame = ngx_palloc(stream->request->pool, | |
sizeof(ngx_http_v2_out_frame_t)); | |
if (frame == NULL) { | |
return NULL; | |
} | |
+ | |
+ stream->frames++; | |
+ h2c->frames++; | |
+ | |
+ } else { | |
+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
+ "http2 flood detected"); | |
+ | |
+ h2c->connection->error = 1; | |
+ return NULL; | |
} | |
flags = last->buf->last_buf ? NGX_HTTP_V2_END_STREAM_FLAG : 0; | |
-- | |
2.20.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c | |
index 2c621907..83f9c4a4 100644 | |
--- a/src/http/v2/ngx_http_v2.c | |
+++ b/src/http/v2/ngx_http_v2.c | |
@@ -635,6 +635,7 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) | |
h2c->pool = NULL; | |
h2c->free_frames = NULL; | |
+ h2c->frames = 0; | |
h2c->free_fake_connections = NULL; | |
#if (NGX_HTTP_SSL) | |
@@ -2678,7 +2679,7 @@ ngx_http_v2_get_frame(ngx_http_v2_connection_t *h2c, size_t length, | |
frame->blocked = 0; | |
- } else { | |
+ } else if (h2c->frames < 10000) { | |
pool = h2c->pool ? h2c->pool : h2c->connection->pool; | |
frame = ngx_pcalloc(pool, sizeof(ngx_http_v2_out_frame_t)); | |
@@ -2702,6 +2703,15 @@ ngx_http_v2_get_frame(ngx_http_v2_connection_t *h2c, size_t length, | |
frame->last = frame->first; | |
frame->handler = ngx_http_v2_frame_handler; | |
+ | |
+ h2c->frames++; | |
+ | |
+ } else { | |
+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
+ "http2 flood detected"); | |
+ | |
+ h2c->connection->error = 1; | |
+ return NULL; | |
} | |
#if (NGX_DEBUG) | |
@@ -4227,12 +4237,19 @@ ngx_http_v2_idle_handler(ngx_event_t *rev) | |
#endif | |
- c->destroyed = 0; | |
- ngx_reusable_connection(c, 0); | |
- | |
h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, | |
ngx_http_v2_module); | |
+ if (h2c->idle++ > 10 * h2scf->max_requests) { | |
+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
+ "http2 flood detected"); | |
+ ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); | |
+ return; | |
+ } | |
+ | |
+ c->destroyed = 0; | |
+ ngx_reusable_connection(c, 0); | |
+ | |
h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); | |
if (h2c->pool == NULL) { | |
ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | |
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h | |
index 42e0eb13..83dbea31 100644 | |
--- a/src/http/v2/ngx_http_v2.h | |
+++ b/src/http/v2/ngx_http_v2.h | |
@@ -115,6 +115,8 @@ struct ngx_http_v2_connection_s { | |
ngx_http_connection_t *http_connection; | |
ngx_uint_t processing; | |
+ ngx_uint_t frames; | |
+ ngx_uint_t idle; | |
size_t send_window; | |
size_t recv_window; | |
-- | |
2.20.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c | |
index 83f9c4a4..db3f09a9 100644 | |
--- a/src/http/v2/ngx_http_v2.c | |
+++ b/src/http/v2/ngx_http_v2.c | |
@@ -249,6 +249,8 @@ ngx_http_v2_init(ngx_event_t *rev) | |
h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); | |
+ h2c->priority_limit = h2scf->concurrent_streams; | |
+ | |
h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); | |
if (h2c->pool == NULL) { | |
ngx_http_close_connection(c); | |
@@ -1518,6 +1520,14 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, | |
header->name.len = h2c->state.field_end - h2c->state.field_start; | |
header->name.data = h2c->state.field_start; | |
+ if (header->name.len == 0) { | |
+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
+ "client sent zero header name length"); | |
+ | |
+ return ngx_http_v2_connection_error(h2c, | |
+ NGX_HTTP_V2_PROTOCOL_ERROR); | |
+ } | |
+ | |
return ngx_http_v2_state_field_len(h2c, pos, end); | |
} | |
@@ -1775,6 +1785,13 @@ ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos, | |
return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
} | |
+ if (--h2c->priority_limit == 0) { | |
+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
+ "client sent too many PRIORITY frames"); | |
+ | |
+ return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM); | |
+ } | |
+ | |
if (end - pos < NGX_HTTP_V2_PRIORITY_SIZE) { | |
return ngx_http_v2_state_save(h2c, pos, end, | |
ngx_http_v2_state_priority); | |
@@ -2884,6 +2901,8 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c) | |
h2c->processing++; | |
+ h2c->priority_limit += h2scf->concurrent_streams; | |
+ | |
return stream; | |
} | |
@@ -3021,10 +3040,6 @@ ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header) | |
ngx_uint_t i; | |
ngx_http_core_srv_conf_t *cscf; | |
- if (header->name.len == 0) { | |
- return NGX_ERROR; | |
- } | |
- | |
r->invalid_header = 0; | |
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); | |
@@ -4096,6 +4111,8 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) | |
*/ | |
pool = stream->pool; | |
+ h2c->frames -= stream->frames; | |
+ | |
ngx_http_free_request(stream->request, rc); | |
if (pool != h2c->state.pool) { | |
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h | |
index 83dbea31..f5272398 100644 | |
--- a/src/http/v2/ngx_http_v2.h | |
+++ b/src/http/v2/ngx_http_v2.h | |
@@ -117,6 +117,7 @@ struct ngx_http_v2_connection_s { | |
ngx_uint_t processing; | |
ngx_uint_t frames; | |
ngx_uint_t idle; | |
+ ngx_uint_t priority_limit; | |
size_t send_window; | |
size_t recv_window; | |
@@ -182,6 +183,8 @@ struct ngx_http_v2_stream_s { | |
ngx_buf_t *preread; | |
+ ngx_uint_t frames; | |
+ | |
ngx_http_v2_out_frame_t *free_frames; | |
ngx_chain_t *free_frame_headers; | |
ngx_chain_t *free_bufs; | |
diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c | |
index 90707850..b73ae40e 100644 | |
--- a/src/http/v2/ngx_http_v2_filter_module.c | |
+++ b/src/http/v2/ngx_http_v2_filter_module.c | |
@@ -1167,22 +1167,34 @@ static ngx_http_v2_out_frame_t * | |
ngx_http_v2_filter_get_data_frame(ngx_http_v2_stream_t *stream, | |
size_t len, ngx_chain_t *first, ngx_chain_t *last) | |
{ | |
- u_char flags; | |
- ngx_buf_t *buf; | |
- ngx_chain_t *cl; | |
- ngx_http_v2_out_frame_t *frame; | |
+ u_char flags; | |
+ ngx_buf_t *buf; | |
+ ngx_chain_t *cl; | |
+ ngx_http_v2_out_frame_t *frame; | |
+ ngx_http_v2_connection_t *h2c; | |
frame = stream->free_frames; | |
+ h2c = stream->connection; | |
if (frame) { | |
stream->free_frames = frame->next; | |
- } else { | |
+ } else if (h2c->frames < 10000) { | |
frame = ngx_palloc(stream->request->pool, | |
sizeof(ngx_http_v2_out_frame_t)); | |
if (frame == NULL) { | |
return NULL; | |
} | |
+ | |
+ stream->frames++; | |
+ h2c->frames++; | |
+ | |
+ } else { | |
+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
+ "http2 flood detected"); | |
+ | |
+ h2c->connection->error = 1; | |
+ return NULL; | |
} | |
flags = last->buf->last_buf ? NGX_HTTP_V2_END_STREAM_FLAG : 0; | |
-- | |
2.20.1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment