|
| 1 | +From 875373fb67097281d4a4ff461e531b9bef947818 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Vince Perri <5596945+vinceaperri@users.noreply.github.com> |
| 3 | +Date: Thu, 21 Nov 2024 14:11:36 +0000 |
| 4 | +Subject: [PATCH] Limit CONTINUATION frames following an incoming HEADER frame |
| 5 | + |
| 6 | +Original patch: https://github.com/nghttp2/nghttp2/commit/00201ecd8f982da3b67d4f6868af72a1b03b14e0 |
| 7 | +--- |
| 8 | + Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h | 7 ++++++- |
| 9 | + Utilities/cmnghttp2/lib/nghttp2_helper.c | 2 ++ |
| 10 | + Utilities/cmnghttp2/lib/nghttp2_session.c | 8 ++++++++ |
| 11 | + Utilities/cmnghttp2/lib/nghttp2_session.h | 10 ++++++++++ |
| 12 | + 4 files changed, 26 insertions(+), 1 deletion(-) |
| 13 | + |
| 14 | +diff --git a/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h b/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h |
| 15 | +index e4e1d4fc..a140199a 100644 |
| 16 | +--- a/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h |
| 17 | ++++ b/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h |
| 18 | +@@ -428,7 +428,12 @@ typedef enum { |
| 19 | + * exhaustion on server side to send these frames forever and does |
| 20 | + * not read network. |
| 21 | + */ |
| 22 | +- NGHTTP2_ERR_FLOODED = -904 |
| 23 | ++ NGHTTP2_ERR_FLOODED = -904, |
| 24 | ++ /** |
| 25 | ++ * When a local endpoint receives too many CONTINUATION frames |
| 26 | ++ * following a HEADER frame. |
| 27 | ++ */ |
| 28 | ++ NGHTTP2_ERR_TOO_MANY_CONTINUATIONS = -905, |
| 29 | + } nghttp2_error; |
| 30 | + |
| 31 | + /** |
| 32 | +diff --git a/Utilities/cmnghttp2/lib/nghttp2_helper.c b/Utilities/cmnghttp2/lib/nghttp2_helper.c |
| 33 | +index 91136a61..f150ab54 100644 |
| 34 | +--- a/Utilities/cmnghttp2/lib/nghttp2_helper.c |
| 35 | ++++ b/Utilities/cmnghttp2/lib/nghttp2_helper.c |
| 36 | +@@ -334,6 +334,8 @@ const char *nghttp2_strerror(int error_code) { |
| 37 | + case NGHTTP2_ERR_FLOODED: |
| 38 | + return "Flooding was detected in this HTTP/2 session, and it must be " |
| 39 | + "closed"; |
| 40 | ++ case NGHTTP2_ERR_TOO_MANY_CONTINUATIONS: |
| 41 | ++ return "Too many CONTINUATION frames following a HEADER frame"; |
| 42 | + default: |
| 43 | + return "Unknown error code"; |
| 44 | + } |
| 45 | +diff --git a/Utilities/cmnghttp2/lib/nghttp2_session.c b/Utilities/cmnghttp2/lib/nghttp2_session.c |
| 46 | +index a3c0b708..f02e3f95 100644 |
| 47 | +--- a/Utilities/cmnghttp2/lib/nghttp2_session.c |
| 48 | ++++ b/Utilities/cmnghttp2/lib/nghttp2_session.c |
| 49 | +@@ -463,6 +463,7 @@ static int session_new(nghttp2_session **session_ptr, |
| 50 | + |
| 51 | + (*session_ptr)->max_send_header_block_length = NGHTTP2_MAX_HEADERSLEN; |
| 52 | + (*session_ptr)->max_outbound_ack = NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM; |
| 53 | ++ (*session_ptr)->max_continuations = NGHTTP2_DEFAULT_MAX_CONTINUATIONS; |
| 54 | + |
| 55 | + if (option) { |
| 56 | + if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) && |
| 57 | +@@ -6297,6 +6298,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, |
| 58 | + } |
| 59 | + } |
| 60 | + session_inbound_frame_reset(session); |
| 61 | ++ |
| 62 | ++ session->num_continuations = 0; |
| 63 | + } |
| 64 | + break; |
| 65 | + } |
| 66 | +@@ -6418,6 +6421,11 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, |
| 67 | + } |
| 68 | + #endif /* DEBUGBUILD */ |
| 69 | + |
| 70 | ++ |
| 71 | ++ if (++session->num_continuations > session->max_continuations) { |
| 72 | ++ return NGHTTP2_ERR_TOO_MANY_CONTINUATIONS; |
| 73 | ++ } |
| 74 | ++ |
| 75 | + readlen = inbound_frame_buf_read(iframe, in, last); |
| 76 | + in += readlen; |
| 77 | + |
| 78 | +diff --git a/Utilities/cmnghttp2/lib/nghttp2_session.h b/Utilities/cmnghttp2/lib/nghttp2_session.h |
| 79 | +index b75294c3..f53acac7 100644 |
| 80 | +--- a/Utilities/cmnghttp2/lib/nghttp2_session.h |
| 81 | ++++ b/Utilities/cmnghttp2/lib/nghttp2_session.h |
| 82 | +@@ -107,6 +107,10 @@ typedef struct { |
| 83 | + #define NGHTTP2_DEFAULT_STREAM_RESET_BURST 1000 |
| 84 | + #define NGHTTP2_DEFAULT_STREAM_RESET_RATE 33 |
| 85 | + |
| 86 | ++/* The default max number of CONTINUATION frames following an incoming |
| 87 | ++ HEADER frame. */ |
| 88 | ++#define NGHTTP2_DEFAULT_MAX_CONTINUATIONS 8 |
| 89 | ++ |
| 90 | + /* Internal state when receiving incoming frame */ |
| 91 | + typedef enum { |
| 92 | + /* Receiving frame header */ |
| 93 | +@@ -277,6 +281,12 @@ struct nghttp2_session { |
| 94 | + /* The maximum length of header block to send. Calculated by the |
| 95 | + same way as nghttp2_hd_deflate_bound() does. */ |
| 96 | + size_t max_send_header_block_length; |
| 97 | ++ /* The maximum number of CONTINUATION frames following an incoming |
| 98 | ++ HEADER frame. */ |
| 99 | ++ size_t max_continuations; |
| 100 | ++ /* The number of CONTINUATION frames following an incoming HEADER |
| 101 | ++ frame. This variable is reset when END_HEADERS flag is seen. */ |
| 102 | ++ size_t num_continuations; |
| 103 | + /* Next Stream ID. Made unsigned int to detect >= (1 << 31). */ |
| 104 | + uint32_t next_stream_id; |
| 105 | + /* The last stream ID this session initiated. For client session, |
| 106 | +-- |
| 107 | +2.34.1 |
| 108 | + |
0 commit comments