|
| 1 | +From 0480c05df47962b324f7e918a71f764102ff7441 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Tatsuhiro Tsujikawa < [email protected]> |
| 3 | +Date: Sat, 9 Mar 2024 16:26:42 +0900 |
| 4 | +Subject: [PATCH 1/2] Limit CONTINUATION frames following an incoming HEADER |
| 5 | + frame |
| 6 | + |
| 7 | +Signed-off-by: Muhammad Falak R Wani < [email protected]> |
| 8 | +--- |
| 9 | + lib/includes/nghttp2/nghttp2.h | 7 ++++++- |
| 10 | + lib/nghttp2_helper.c | 2 ++ |
| 11 | + lib/nghttp2_session.c | 7 +++++++ |
| 12 | + lib/nghttp2_session.h | 10 ++++++++++ |
| 13 | + 4 files changed, 25 insertions(+), 1 deletion(-) |
| 14 | + |
| 15 | +diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h |
| 16 | +index fa22081c..b394bde9 100644 |
| 17 | +--- a/lib/includes/nghttp2/nghttp2.h |
| 18 | ++++ b/lib/includes/nghttp2/nghttp2.h |
| 19 | +@@ -440,7 +440,12 @@ typedef enum { |
| 20 | + * exhaustion on server side to send these frames forever and does |
| 21 | + * not read network. |
| 22 | + */ |
| 23 | +- NGHTTP2_ERR_FLOODED = -904 |
| 24 | ++ NGHTTP2_ERR_FLOODED = -904, |
| 25 | ++ /** |
| 26 | ++ * When a local endpoint receives too many CONTINUATION frames |
| 27 | ++ * following a HEADER frame. |
| 28 | ++ */ |
| 29 | ++ NGHTTP2_ERR_TOO_MANY_CONTINUATIONS = -905, |
| 30 | + } nghttp2_error; |
| 31 | + |
| 32 | + /** |
| 33 | +diff --git a/lib/nghttp2_helper.c b/lib/nghttp2_helper.c |
| 34 | +index 93dd4754..b3563d98 100644 |
| 35 | +--- a/lib/nghttp2_helper.c |
| 36 | ++++ b/lib/nghttp2_helper.c |
| 37 | +@@ -336,6 +336,8 @@ const char *nghttp2_strerror(int error_code) { |
| 38 | + "closed"; |
| 39 | + case NGHTTP2_ERR_TOO_MANY_SETTINGS: |
| 40 | + return "SETTINGS frame contained more than the maximum allowed entries"; |
| 41 | ++ case NGHTTP2_ERR_TOO_MANY_CONTINUATIONS: |
| 42 | ++ return "Too many CONTINUATION frames following a HEADER frame"; |
| 43 | + default: |
| 44 | + return "Unknown error code"; |
| 45 | + } |
| 46 | +diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c |
| 47 | +index ec5024d0..8e4d2e7e 100644 |
| 48 | +--- a/lib/nghttp2_session.c |
| 49 | ++++ b/lib/nghttp2_session.c |
| 50 | +@@ -496,6 +496,7 @@ static int session_new(nghttp2_session **session_ptr, |
| 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_settings = NGHTTP2_DEFAULT_MAX_SETTINGS; |
| 54 | ++ (*session_ptr)->max_continuations = NGHTTP2_DEFAULT_MAX_CONTINUATIONS; |
| 55 | + |
| 56 | + if (option) { |
| 57 | + if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) && |
| 58 | +@@ -6778,6 +6779,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, |
| 59 | + } |
| 60 | + } |
| 61 | + session_inbound_frame_reset(session); |
| 62 | ++ |
| 63 | ++ session->num_continuations = 0; |
| 64 | + } |
| 65 | + break; |
| 66 | + } |
| 67 | +@@ -6899,6 +6902,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, |
| 68 | + } |
| 69 | + #endif /* DEBUGBUILD */ |
| 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/lib/nghttp2_session.h b/lib/nghttp2_session.h |
| 79 | +index b119329a..ef8f7b27 100644 |
| 80 | +--- a/lib/nghttp2_session.h |
| 81 | ++++ b/lib/nghttp2_session.h |
| 82 | +@@ -110,6 +110,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 | +@@ -290,6 +294,12 @@ struct nghttp2_session { |
| 94 | + size_t max_send_header_block_length; |
| 95 | + /* The maximum number of settings accepted per SETTINGS frame. */ |
| 96 | + size_t max_settings; |
| 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.47.0 |
| 108 | + |
| 109 | +From 90f8bb08e4322ac9f58110a8c87a8385e424f53d Mon Sep 17 00:00:00 2001 |
| 110 | +From: Tatsuhiro Tsujikawa < [email protected]> |
| 111 | +Date: Sat, 9 Mar 2024 16:48:10 +0900 |
| 112 | +Subject: [PATCH 2/2] Add nghttp2_option_set_max_continuations |
| 113 | + |
| 114 | +Signed-off-by: Muhammad Falak R Wani < [email protected]> |
| 115 | +--- |
| 116 | + doc/Makefile.am | 1 + |
| 117 | + lib/includes/nghttp2/nghttp2.h | 11 +++++++++++ |
| 118 | + lib/nghttp2_option.c | 5 +++++ |
| 119 | + lib/nghttp2_option.h | 5 +++++ |
| 120 | + lib/nghttp2_session.c | 4 ++++ |
| 121 | + 5 files changed, 26 insertions(+) |
| 122 | + |
| 123 | +diff --git a/doc/Makefile.am b/doc/Makefile.am |
| 124 | +index 96f449ff..5636a137 100644 |
| 125 | +--- a/doc/Makefile.am |
| 126 | ++++ b/doc/Makefile.am |
| 127 | +@@ -73,6 +73,7 @@ APIDOCS= \ |
| 128 | + nghttp2_option_set_peer_max_concurrent_streams.rst \ |
| 129 | + nghttp2_option_set_server_fallback_rfc7540_priorities.rst \ |
| 130 | + nghttp2_option_set_user_recv_extension_type.rst \ |
| 131 | ++ nghttp2_option_set_max_continuations.rst \ |
| 132 | + nghttp2_option_set_max_outbound_ack.rst \ |
| 133 | + nghttp2_option_set_max_settings.rst \ |
| 134 | + nghttp2_option_set_stream_reset_rate_limit.rst \ |
| 135 | +diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h |
| 136 | +index b394bde9..4d3339b5 100644 |
| 137 | +--- a/lib/includes/nghttp2/nghttp2.h |
| 138 | ++++ b/lib/includes/nghttp2/nghttp2.h |
| 139 | +@@ -2778,6 +2778,17 @@ NGHTTP2_EXTERN void |
| 140 | + nghttp2_option_set_stream_reset_rate_limit(nghttp2_option *option, |
| 141 | + uint64_t burst, uint64_t rate); |
| 142 | + |
| 143 | ++/** |
| 144 | ++ * @function |
| 145 | ++ * |
| 146 | ++ * This function sets the maximum number of CONTINUATION frames |
| 147 | ++ * following an incoming HEADER frame. If more than those frames are |
| 148 | ++ * received, the remote endpoint is considered to be misbehaving and |
| 149 | ++ * session will be closed. The default value is 8. |
| 150 | ++ */ |
| 151 | ++NGHTTP2_EXTERN void nghttp2_option_set_max_continuations(nghttp2_option *option, |
| 152 | ++ size_t val); |
| 153 | ++ |
| 154 | + /** |
| 155 | + * @function |
| 156 | + * |
| 157 | +diff --git a/lib/nghttp2_option.c b/lib/nghttp2_option.c |
| 158 | +index 43d4e952..53144b9b 100644 |
| 159 | +--- a/lib/nghttp2_option.c |
| 160 | ++++ b/lib/nghttp2_option.c |
| 161 | +@@ -150,3 +150,8 @@ void nghttp2_option_set_stream_reset_rate_limit(nghttp2_option *option, |
| 162 | + option->stream_reset_burst = burst; |
| 163 | + option->stream_reset_rate = rate; |
| 164 | + } |
| 165 | ++ |
| 166 | ++void nghttp2_option_set_max_continuations(nghttp2_option *option, size_t val) { |
| 167 | ++ option->opt_set_mask |= NGHTTP2_OPT_MAX_CONTINUATIONS; |
| 168 | ++ option->max_continuations = val; |
| 169 | ++} |
| 170 | +diff --git a/lib/nghttp2_option.h b/lib/nghttp2_option.h |
| 171 | +index 2259e184..c89cb97f 100644 |
| 172 | +--- a/lib/nghttp2_option.h |
| 173 | ++++ b/lib/nghttp2_option.h |
| 174 | +@@ -71,6 +71,7 @@ typedef enum { |
| 175 | + NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 13, |
| 176 | + NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 14, |
| 177 | + NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT = 1 << 15, |
| 178 | ++ NGHTTP2_OPT_MAX_CONTINUATIONS = 1 << 16, |
| 179 | + } nghttp2_option_flag; |
| 180 | + |
| 181 | + /** |
| 182 | +@@ -98,6 +99,10 @@ struct nghttp2_option { |
| 183 | + * NGHTTP2_OPT_MAX_SETTINGS |
| 184 | + */ |
| 185 | + size_t max_settings; |
| 186 | ++ /** |
| 187 | ++ * NGHTTP2_OPT_MAX_CONTINUATIONS |
| 188 | ++ */ |
| 189 | ++ size_t max_continuations; |
| 190 | + /** |
| 191 | + * Bitwise OR of nghttp2_option_flag to determine that which fields |
| 192 | + * are specified. |
| 193 | +diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c |
| 194 | +index 8e4d2e7e..ced7517b 100644 |
| 195 | +--- a/lib/nghttp2_session.c |
| 196 | ++++ b/lib/nghttp2_session.c |
| 197 | +@@ -585,6 +585,10 @@ static int session_new(nghttp2_session **session_ptr, |
| 198 | + option->stream_reset_burst, |
| 199 | + option->stream_reset_rate); |
| 200 | + } |
| 201 | ++ |
| 202 | ++ if (option->opt_set_mask & NGHTTP2_OPT_MAX_CONTINUATIONS) { |
| 203 | ++ (*session_ptr)->max_continuations = option->max_continuations; |
| 204 | ++ } |
| 205 | + } |
| 206 | + |
| 207 | + rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater, |
| 208 | +-- |
| 209 | +2.47.0 |
| 210 | + |
0 commit comments