diff options
| author | aszh07 <mail2szahir@gmail.com> | 2024-03-21 15:33:32 +0530 |
|---|---|---|
| committer | Steve Sakoman <steve@sakoman.com> | 2024-04-05 07:23:58 -0700 |
| commit | cf1c9d3daaccb5909d19d1cf4baaa6a152e0e73a (patch) | |
| tree | 34ce7b2faf0214e245486515bdb258ae80dc3474 /meta/recipes-support | |
| parent | b6f6c729453cb88961488e3332046517e2fe99bb (diff) | |
| download | poky-cf1c9d3daaccb5909d19d1cf4baaa6a152e0e73a.tar.gz | |
nghttp2: fix CVE-2023-44487
The HTTP/2 protocol allows a denial of service (server resource consumption)
because request cancellation can reset many streams quickly, as exploited in
the wild in August through October 2023.
References:
https://nvd.nist.gov/vuln/detail/CVE-2023-44487
https://github.com/nghttp2/nghttp2/commit/72b4af6143681f528f1d237b21a9a7aee1738832
(From OE-Core rev: 0156b57dcdb2e5acdd9421a7c24c235f13da2d97)
Signed-off-by: Zahir Hussain <zahir.basha@kpit.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
Diffstat (limited to 'meta/recipes-support')
| -rw-r--r-- | meta/recipes-support/nghttp2/nghttp2/CVE-2023-44487.patch | 927 | ||||
| -rw-r--r-- | meta/recipes-support/nghttp2/nghttp2_1.47.0.bb | 1 |
2 files changed, 928 insertions, 0 deletions
diff --git a/meta/recipes-support/nghttp2/nghttp2/CVE-2023-44487.patch b/meta/recipes-support/nghttp2/nghttp2/CVE-2023-44487.patch new file mode 100644 index 0000000000..3cba83307c --- /dev/null +++ b/meta/recipes-support/nghttp2/nghttp2/CVE-2023-44487.patch | |||
| @@ -0,0 +1,927 @@ | |||
| 1 | From 72b4af6143681f528f1d237b21a9a7aee1738832 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | ||
| 3 | Date: Sun, 1 Oct 2023 00:05:01 +0900 | ||
| 4 | Subject: [PATCH] Rework session management | ||
| 5 | |||
| 6 | CVE: CVE-2023-44487 | ||
| 7 | |||
| 8 | Upstream-Status: Backport [https://github.com/nghttp2/nghttp2/commit/72b4af6143681f528f1d237b21a9a7aee1738832] | ||
| 9 | |||
| 10 | Signed-off-by: Zahir Hussain zahir.basha@kpit.com | ||
| 11 | Signed-off-by: aszh07 <mail2szahir@gmail.com> | ||
| 12 | --- | ||
| 13 | CMakeLists.txt | 4 ++ | ||
| 14 | cmakeconfig.h.in | 9 +++ | ||
| 15 | configure.ac | 21 +++++++ | ||
| 16 | doc/Makefile.am | 1 + | ||
| 17 | lib/CMakeLists.txt | 2 + | ||
| 18 | lib/Makefile.am | 4 ++ | ||
| 19 | lib/includes/nghttp2/nghttp2.h | 17 ++++++ | ||
| 20 | lib/nghttp2_option.c | 7 +++ | ||
| 21 | lib/nghttp2_ratelim.c | 75 ++++++++++++++++++++++++ | ||
| 22 | lib/nghttp2_ratelim.h | 57 ++++++++++++++++++ | ||
| 23 | lib/nghttp2_session.c | 34 ++++++++++- | ||
| 24 | lib/nghttp2_session.h | 12 +++- | ||
| 25 | lib/nghttp2_time.c | 62 ++++++++++++++++++++ | ||
| 26 | lib/nghttp2_time.h | 38 ++++++++++++ | ||
| 27 | tests/nghttp2_ratelim_test.c | 101 ++++++++++++++++++++++++++++++++ | ||
| 28 | tests/nghttp2_ratelim_test.h | 35 +++++++++++ | ||
| 29 | tests/nghttp2_session_test.c | 103 +++++++++++++++++++++++++++++++++ | ||
| 30 | tests/nghttp2_session_test.h | 1 + | ||
| 31 | tests/CMakeLists.txt | 1 + | ||
| 32 | tests/Makefile.am | 6 +- | ||
| 33 | lib/nghttp2_option.h | 6 ++ | ||
| 34 | tests/main.c | 7 ++- | ||
| 35 | 22 files changed, 598 insertions(+), 5 deletions(-) | ||
| 36 | create mode 100644 lib/nghttp2_ratelim.c | ||
| 37 | create mode 100644 lib/nghttp2_ratelim.h | ||
| 38 | create mode 100644 lib/nghttp2_time.c | ||
| 39 | create mode 100644 lib/nghttp2_time.h | ||
| 40 | create mode 100644 tests/nghttp2_ratelim_test.c | ||
| 41 | create mode 100644 tests/nghttp2_ratelim_test.h | ||
| 42 | |||
| 43 | --- a/CMakeLists.txt | ||
| 44 | +++ b/CMakeLists.txt | ||
| 45 | @@ -262,6 +262,7 @@ check_include_file("netinet/in.h" HAVE | ||
| 46 | check_include_file("pwd.h" HAVE_PWD_H) | ||
| 47 | check_include_file("sys/socket.h" HAVE_SYS_SOCKET_H) | ||
| 48 | check_include_file("sys/time.h" HAVE_SYS_TIME_H) | ||
| 49 | +check_include_file("sysinfoapi.h" HAVE_SYSINFOAPI_H) | ||
| 50 | check_include_file("syslog.h" HAVE_SYSLOG_H) | ||
| 51 | check_include_file("time.h" HAVE_TIME_H) | ||
| 52 | check_include_file("unistd.h" HAVE_UNISTD_H) | ||
| 53 | @@ -302,8 +303,11 @@ check_type_size("time_t" SIZEOF_TIME_T) | ||
| 54 | include(CheckFunctionExists) | ||
| 55 | check_function_exists(_Exit HAVE__EXIT) | ||
| 56 | check_function_exists(accept4 HAVE_ACCEPT4) | ||
| 57 | +check_function_exists(clock_gettime HAVE_CLOCK_GETTIME) | ||
| 58 | check_function_exists(mkostemp HAVE_MKOSTEMP) | ||
| 59 | |||
| 60 | +check_symbol_exists(GetTickCount64 sysinfoapi.h HAVE_GETTICKCOUNT64) | ||
| 61 | + | ||
| 62 | include(CheckSymbolExists) | ||
| 63 | # XXX does this correctly detect initgroups (un)availability on cygwin? | ||
| 64 | check_symbol_exists(initgroups grp.h HAVE_DECL_INITGROUPS) | ||
| 65 | --- a/cmakeconfig.h.in | ||
| 66 | +++ b/cmakeconfig.h.in | ||
| 67 | @@ -34,9 +34,15 @@ | ||
| 68 | /* Define to 1 if you have the `accept4` function. */ | ||
| 69 | #cmakedefine HAVE_ACCEPT4 1 | ||
| 70 | |||
| 71 | +/* Define to 1 if you have the `clock_gettime` function. */ | ||
| 72 | +#cmakedefine HAVE_CLOCK_GETTIME 1 | ||
| 73 | + | ||
| 74 | /* Define to 1 if you have the `mkostemp` function. */ | ||
| 75 | #cmakedefine HAVE_MKOSTEMP 1 | ||
| 76 | |||
| 77 | +/* Define to 1 if you have the `GetTickCount64` function. */ | ||
| 78 | +#cmakedefine HAVE_GETTICKCOUNT64 1 | ||
| 79 | + | ||
| 80 | /* Define to 1 if you have the `initgroups` function. */ | ||
| 81 | #cmakedefine01 HAVE_DECL_INITGROUPS | ||
| 82 | |||
| 83 | @@ -73,6 +79,9 @@ | ||
| 84 | /* Define to 1 if you have the <sys/time.h> header file. */ | ||
| 85 | #cmakedefine HAVE_SYS_TIME_H 1 | ||
| 86 | |||
| 87 | +/* Define to 1 if you have the <sysinfoapi.h> header file. */ | ||
| 88 | +#cmakedefine HAVE_SYSINFOAPI_H 1 | ||
| 89 | + | ||
| 90 | /* Define to 1 if you have the <syslog.h> header file. */ | ||
| 91 | #cmakedefine HAVE_SYSLOG_H 1 | ||
| 92 | |||
| 93 | --- a/configure.ac | ||
| 94 | +++ b/configure.ac | ||
| 95 | @@ -607,6 +607,7 @@ AC_CHECK_HEADERS([ \ | ||
| 96 | string.h \ | ||
| 97 | sys/socket.h \ | ||
| 98 | sys/time.h \ | ||
| 99 | + sysinfoapi.h \ | ||
| 100 | syslog.h \ | ||
| 101 | time.h \ | ||
| 102 | unistd.h \ | ||
| 103 | @@ -681,6 +682,7 @@ AC_FUNC_STRNLEN | ||
| 104 | AC_CHECK_FUNCS([ \ | ||
| 105 | _Exit \ | ||
| 106 | accept4 \ | ||
| 107 | + clock_gettime \ | ||
| 108 | dup2 \ | ||
| 109 | getcwd \ | ||
| 110 | getpwnam \ | ||
| 111 | @@ -706,6 +708,25 @@ AC_CHECK_FUNCS([ \ | ||
| 112 | AC_CHECK_FUNC([timerfd_create], | ||
| 113 | [have_timerfd_create=yes], [have_timerfd_create=no]) | ||
| 114 | |||
| 115 | +AC_MSG_CHECKING([checking for GetTickCount64]) | ||
| 116 | +AC_LINK_IFELSE([AC_LANG_PROGRAM( | ||
| 117 | +[[ | ||
| 118 | +#include <sysinfoapi.h> | ||
| 119 | +]], | ||
| 120 | +[[ | ||
| 121 | +GetTickCount64(); | ||
| 122 | +]])], | ||
| 123 | +[have_gettickcount64=yes], | ||
| 124 | +[have_gettickcount64=no]) | ||
| 125 | + | ||
| 126 | +if test "x${have_gettickcount64}" = "xyes"; then | ||
| 127 | + AC_MSG_RESULT([yes]) | ||
| 128 | + AC_DEFINE([HAVE_GETTICKCOUNT64], [1], | ||
| 129 | + [Define to 1 if you have `GetTickCount64` function.]) | ||
| 130 | +else | ||
| 131 | + AC_MSG_RESULT([no]) | ||
| 132 | +fi | ||
| 133 | + | ||
| 134 | # For cygwin: we can link initgroups, so AC_CHECK_FUNCS succeeds, but | ||
| 135 | # cygwin disables initgroups due to feature test macro magic with our | ||
| 136 | # configuration. FreeBSD declares initgroups() in unistd.h. | ||
| 137 | --- a/doc/Makefile.am | ||
| 138 | +++ b/doc/Makefile.am | ||
| 139 | @@ -69,6 +69,7 @@ APIDOCS= \ | ||
| 140 | nghttp2_option_set_user_recv_extension_type.rst \ | ||
| 141 | nghttp2_option_set_max_outbound_ack.rst \ | ||
| 142 | nghttp2_option_set_max_settings.rst \ | ||
| 143 | + nghttp2_option_set_stream_reset_rate_limit.rst \ | ||
| 144 | nghttp2_pack_settings_payload.rst \ | ||
| 145 | nghttp2_priority_spec_check_default.rst \ | ||
| 146 | nghttp2_priority_spec_default_init.rst \ | ||
| 147 | --- a/lib/CMakeLists.txt | ||
| 148 | +++ b/lib/CMakeLists.txt | ||
| 149 | @@ -23,6 +23,8 @@ set(NGHTTP2_SOURCES | ||
| 150 | nghttp2_mem.c | ||
| 151 | nghttp2_http.c | ||
| 152 | nghttp2_rcbuf.c | ||
| 153 | + nghttp2_ratelim.c | ||
| 154 | + nghttp2_time.c | ||
| 155 | nghttp2_debug.c | ||
| 156 | ) | ||
| 157 | |||
| 158 | --- a/lib/Makefile.am | ||
| 159 | +++ b/lib/Makefile.am | ||
| 160 | @@ -49,6 +49,8 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c ngh | ||
| 161 | nghttp2_mem.c \ | ||
| 162 | nghttp2_http.c \ | ||
| 163 | nghttp2_rcbuf.c \ | ||
| 164 | + nghttp2_ratelim.c \ | ||
| 165 | + nghttp2_time.c \ | ||
| 166 | nghttp2_debug.c | ||
| 167 | |||
| 168 | HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \ | ||
| 169 | @@ -65,6 +67,8 @@ HFILES = nghttp2_pq.h nghttp2_int.h nght | ||
| 170 | nghttp2_mem.h \ | ||
| 171 | nghttp2_http.h \ | ||
| 172 | nghttp2_rcbuf.h \ | ||
| 173 | + nghttp2_ratelim.h \ | ||
| 174 | + nghttp2_time.h \ | ||
| 175 | nghttp2_debug.h | ||
| 176 | |||
| 177 | libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS) | ||
| 178 | --- a/lib/includes/nghttp2/nghttp2.h | ||
| 179 | +++ b/lib/includes/nghttp2/nghttp2.h | ||
| 180 | @@ -2763,6 +2763,23 @@ nghttp2_session_client_new2(nghttp2_sess | ||
| 181 | /** | ||
| 182 | * @function | ||
| 183 | * | ||
| 184 | + * This function sets the rate limit for the incoming stream reset | ||
| 185 | + * (RST_STREAM frame). It is server use only. It is a token-bucket | ||
| 186 | + * based rate limiter. |burst| specifies the number of tokens that is | ||
| 187 | + * initially available. The maximum number of tokens is capped to | ||
| 188 | + * this value. |rate| specifies the number of tokens that are | ||
| 189 | + * regenerated per second. An incoming RST_STREAM consumes one token. | ||
| 190 | + * If there is no token available, GOAWAY is sent to tear down the | ||
| 191 | + * connection. |burst| and |rate| default to 1000 and 33 | ||
| 192 | + * respectively. | ||
| 193 | + */ | ||
| 194 | +NGHTTP2_EXTERN void | ||
| 195 | +nghttp2_option_set_stream_reset_rate_limit(nghttp2_option *option, | ||
| 196 | + uint64_t burst, uint64_t rate); | ||
| 197 | + | ||
| 198 | +/** | ||
| 199 | + * @function | ||
| 200 | + * | ||
| 201 | * Like `nghttp2_session_server_new()`, but with additional options | ||
| 202 | * specified in the |option|. | ||
| 203 | * | ||
| 204 | --- a/lib/nghttp2_option.c | ||
| 205 | +++ b/lib/nghttp2_option.c | ||
| 206 | @@ -126,3 +126,10 @@ void nghttp2_option_set_max_settings(ngh | ||
| 207 | option->opt_set_mask |= NGHTTP2_OPT_MAX_SETTINGS; | ||
| 208 | option->max_settings = val; | ||
| 209 | } | ||
| 210 | + | ||
| 211 | +void nghttp2_option_set_stream_reset_rate_limit(nghttp2_option *option, | ||
| 212 | + uint64_t burst, uint64_t rate) { | ||
| 213 | + option->opt_set_mask |= NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT; | ||
| 214 | + option->stream_reset_burst = burst; | ||
| 215 | + option->stream_reset_rate = rate; | ||
| 216 | +} | ||
| 217 | --- /dev/null | ||
| 218 | +++ b/lib/nghttp2_ratelim.c | ||
| 219 | @@ -0,0 +1,75 @@ | ||
| 220 | +/* | ||
| 221 | + * nghttp2 - HTTP/2 C Library | ||
| 222 | + * | ||
| 223 | + * Copyright (c) 2023 nghttp2 contributors | ||
| 224 | + * | ||
| 225 | + * Permission is hereby granted, free of charge, to any person obtaining | ||
| 226 | + * a copy of this software and associated documentation files (the | ||
| 227 | + * "Software"), to deal in the Software without restriction, including | ||
| 228 | + * without limitation the rights to use, copy, modify, merge, publish, | ||
| 229 | + * distribute, sublicense, and/or sell copies of the Software, and to | ||
| 230 | + * permit persons to whom the Software is furnished to do so, subject to | ||
| 231 | + * the following conditions: | ||
| 232 | + * | ||
| 233 | + * The above copyright notice and this permission notice shall be | ||
| 234 | + * included in all copies or substantial portions of the Software. | ||
| 235 | + * | ||
| 236 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 237 | + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 238 | + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 239 | + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
| 240 | + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
| 241 | + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
| 242 | + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 243 | + */ | ||
| 244 | +#include "nghttp2_ratelim.h" | ||
| 245 | +#include "nghttp2_helper.h" | ||
| 246 | + | ||
| 247 | +void nghttp2_ratelim_init(nghttp2_ratelim *rl, uint64_t burst, uint64_t rate) { | ||
| 248 | + rl->val = rl->burst = burst; | ||
| 249 | + rl->rate = rate; | ||
| 250 | + rl->tstamp = 0; | ||
| 251 | +} | ||
| 252 | + | ||
| 253 | +void nghttp2_ratelim_update(nghttp2_ratelim *rl, uint64_t tstamp) { | ||
| 254 | + uint64_t d, gain; | ||
| 255 | + | ||
| 256 | + if (tstamp == rl->tstamp) { | ||
| 257 | + return; | ||
| 258 | + } | ||
| 259 | + | ||
| 260 | + if (tstamp > rl->tstamp) { | ||
| 261 | + d = tstamp - rl->tstamp; | ||
| 262 | + } else { | ||
| 263 | + d = 1; | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + rl->tstamp = tstamp; | ||
| 267 | + | ||
| 268 | + if (UINT64_MAX / d < rl->rate) { | ||
| 269 | + rl->val = rl->burst; | ||
| 270 | + | ||
| 271 | + return; | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + gain = rl->rate * d; | ||
| 275 | + | ||
| 276 | + if (UINT64_MAX - gain < rl->val) { | ||
| 277 | + rl->val = rl->burst; | ||
| 278 | + | ||
| 279 | + return; | ||
| 280 | + } | ||
| 281 | + | ||
| 282 | + rl->val += gain; | ||
| 283 | + rl->val = nghttp2_min(rl->val, rl->burst); | ||
| 284 | +} | ||
| 285 | + | ||
| 286 | +int nghttp2_ratelim_drain(nghttp2_ratelim *rl, uint64_t n) { | ||
| 287 | + if (rl->val < n) { | ||
| 288 | + return -1; | ||
| 289 | + } | ||
| 290 | + | ||
| 291 | + rl->val -= n; | ||
| 292 | + | ||
| 293 | + return 0; | ||
| 294 | +} | ||
| 295 | --- /dev/null | ||
| 296 | +++ b/lib/nghttp2_ratelim.h | ||
| 297 | @@ -0,0 +1,57 @@ | ||
| 298 | +/* | ||
| 299 | + * nghttp2 - HTTP/2 C Library | ||
| 300 | + * | ||
| 301 | + * Copyright (c) 2023 nghttp2 contributors | ||
| 302 | + * | ||
| 303 | + * Permission is hereby granted, free of charge, to any person obtaining | ||
| 304 | + * a copy of this software and associated documentation files (the | ||
| 305 | + * "Software"), to deal in the Software without restriction, including | ||
| 306 | + * without limitation the rights to use, copy, modify, merge, publish, | ||
| 307 | + * distribute, sublicense, and/or sell copies of the Software, and to | ||
| 308 | + * permit persons to whom the Software is furnished to do so, subject to | ||
| 309 | + * the following conditions: | ||
| 310 | + * | ||
| 311 | + * The above copyright notice and this permission notice shall be | ||
| 312 | + * included in all copies or substantial portions of the Software. | ||
| 313 | + * | ||
| 314 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 315 | + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 316 | + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 317 | + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
| 318 | + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
| 319 | + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
| 320 | + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 321 | + */ | ||
| 322 | +#ifndef NGHTTP2_RATELIM_H | ||
| 323 | +#define NGHTTP2_RATELIM_H | ||
| 324 | + | ||
| 325 | +#ifdef HAVE_CONFIG_H | ||
| 326 | +# include <config.h> | ||
| 327 | +#endif /* HAVE_CONFIG_H */ | ||
| 328 | + | ||
| 329 | +#include <nghttp2/nghttp2.h> | ||
| 330 | + | ||
| 331 | +typedef struct nghttp2_ratelim { | ||
| 332 | + /* burst is the maximum value of val. */ | ||
| 333 | + uint64_t burst; | ||
| 334 | + /* rate is the amount of value that is regenerated per 1 tstamp. */ | ||
| 335 | + uint64_t rate; | ||
| 336 | + /* val is the amount of value available to drain. */ | ||
| 337 | + uint64_t val; | ||
| 338 | + /* tstamp is the last timestamp in second resolution that is known | ||
| 339 | + to this object. */ | ||
| 340 | + uint64_t tstamp; | ||
| 341 | +} nghttp2_ratelim; | ||
| 342 | + | ||
| 343 | +/* nghttp2_ratelim_init initializes |rl| with the given parameters. */ | ||
| 344 | +void nghttp2_ratelim_init(nghttp2_ratelim *rl, uint64_t burst, uint64_t rate); | ||
| 345 | + | ||
| 346 | +/* nghttp2_ratelim_update updates rl->val with the current |tstamp| | ||
| 347 | + given in second resolution. */ | ||
| 348 | +void nghttp2_ratelim_update(nghttp2_ratelim *rl, uint64_t tstamp); | ||
| 349 | + | ||
| 350 | +/* nghttp2_ratelim_drain drains |n| from rl->val. It returns 0 if it | ||
| 351 | + succeeds, or -1. */ | ||
| 352 | +int nghttp2_ratelim_drain(nghttp2_ratelim *rl, uint64_t n); | ||
| 353 | + | ||
| 354 | +#endif /* NGHTTP2_RATELIM_H */ | ||
| 355 | --- a/lib/nghttp2_session.c | ||
| 356 | +++ b/lib/nghttp2_session.c | ||
| 357 | @@ -36,6 +36,7 @@ | ||
| 358 | #include "nghttp2_option.h" | ||
| 359 | #include "nghttp2_http.h" | ||
| 360 | #include "nghttp2_pq.h" | ||
| 361 | +#include "nghttp2_time.h" | ||
| 362 | #include "nghttp2_debug.h" | ||
| 363 | |||
| 364 | /* | ||
| 365 | @@ -443,6 +444,10 @@ static int session_new(nghttp2_session * | ||
| 366 | NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS; | ||
| 367 | (*session_ptr)->pending_enable_push = 1; | ||
| 368 | |||
| 369 | + nghttp2_ratelim_init(&(*session_ptr)->stream_reset_ratelim, | ||
| 370 | + NGHTTP2_DEFAULT_STREAM_RESET_BURST, | ||
| 371 | + NGHTTP2_DEFAULT_STREAM_RESET_RATE); | ||
| 372 | + | ||
| 373 | if (server) { | ||
| 374 | (*session_ptr)->server = 1; | ||
| 375 | } | ||
| 376 | @@ -527,6 +532,12 @@ static int session_new(nghttp2_session * | ||
| 377 | option->max_settings) { | ||
| 378 | (*session_ptr)->max_settings = option->max_settings; | ||
| 379 | } | ||
| 380 | + | ||
| 381 | + if (option->opt_set_mask & NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT) { | ||
| 382 | + nghttp2_ratelim_init(&(*session_ptr)->stream_reset_ratelim, | ||
| 383 | + option->stream_reset_burst, | ||
| 384 | + option->stream_reset_rate); | ||
| 385 | + } | ||
| 386 | } | ||
| 387 | |||
| 388 | rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater, | ||
| 389 | @@ -4144,6 +4155,23 @@ static int session_process_priority_fram | ||
| 390 | return nghttp2_session_on_priority_received(session, frame); | ||
| 391 | } | ||
| 392 | |||
| 393 | +static int session_update_stream_reset_ratelim(nghttp2_session *session) { | ||
| 394 | + if (!session->server || (session->goaway_flags & NGHTTP2_GOAWAY_SUBMITTED)) { | ||
| 395 | + return 0; | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | + nghttp2_ratelim_update(&session->stream_reset_ratelim, | ||
| 399 | + nghttp2_time_now_sec()); | ||
| 400 | + | ||
| 401 | + if (nghttp2_ratelim_drain(&session->stream_reset_ratelim, 1) == 0) { | ||
| 402 | + return 0; | ||
| 403 | + } | ||
| 404 | + | ||
| 405 | + return nghttp2_session_add_goaway(session, session->last_recv_stream_id, | ||
| 406 | + NGHTTP2_INTERNAL_ERROR, NULL, 0, | ||
| 407 | + NGHTTP2_GOAWAY_AUX_NONE); | ||
| 408 | +} | ||
| 409 | + | ||
| 410 | int nghttp2_session_on_rst_stream_received(nghttp2_session *session, | ||
| 411 | nghttp2_frame *frame) { | ||
| 412 | int rv; | ||
| 413 | @@ -4173,7 +4201,8 @@ int nghttp2_session_on_rst_stream_receiv | ||
| 414 | if (nghttp2_is_fatal(rv)) { | ||
| 415 | return rv; | ||
| 416 | } | ||
| 417 | - return 0; | ||
| 418 | + | ||
| 419 | + return session_update_stream_reset_ratelim(session); | ||
| 420 | } | ||
| 421 | |||
| 422 | static int session_process_rst_stream_frame(nghttp2_session *session) { | ||
| 423 | @@ -6965,6 +6994,9 @@ int nghttp2_session_add_goaway(nghttp2_s | ||
| 424 | nghttp2_mem_free(mem, item); | ||
| 425 | return rv; | ||
| 426 | } | ||
| 427 | + | ||
| 428 | + session->goaway_flags |= NGHTTP2_GOAWAY_SUBMITTED; | ||
| 429 | + | ||
| 430 | return 0; | ||
| 431 | } | ||
| 432 | |||
| 433 | --- a/lib/nghttp2_session.h | ||
| 434 | +++ b/lib/nghttp2_session.h | ||
| 435 | @@ -39,6 +39,7 @@ | ||
| 436 | #include "nghttp2_buf.h" | ||
| 437 | #include "nghttp2_callbacks.h" | ||
| 438 | #include "nghttp2_mem.h" | ||
| 439 | +#include "nghttp2_ratelim.h" | ||
| 440 | |||
| 441 | /* The global variable for tests where we want to disable strict | ||
| 442 | preface handling. */ | ||
| 443 | @@ -102,6 +103,10 @@ typedef struct { | ||
| 444 | /* The default value of maximum number of concurrent streams. */ | ||
| 445 | #define NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS 0xffffffffu | ||
| 446 | |||
| 447 | +/* The default values for stream reset rate limiter. */ | ||
| 448 | +#define NGHTTP2_DEFAULT_STREAM_RESET_BURST 1000 | ||
| 449 | +#define NGHTTP2_DEFAULT_STREAM_RESET_RATE 33 | ||
| 450 | + | ||
| 451 | /* Internal state when receiving incoming frame */ | ||
| 452 | typedef enum { | ||
| 453 | /* Receiving frame header */ | ||
| 454 | @@ -176,7 +181,9 @@ typedef enum { | ||
| 455 | /* Flag means GOAWAY was sent */ | ||
| 456 | NGHTTP2_GOAWAY_SENT = 0x4, | ||
| 457 | /* Flag means GOAWAY was received */ | ||
| 458 | - NGHTTP2_GOAWAY_RECV = 0x8 | ||
| 459 | + NGHTTP2_GOAWAY_RECV = 0x8, | ||
| 460 | + /* Flag means GOAWAY has been submitted at least once */ | ||
| 461 | + NGHTTP2_GOAWAY_SUBMITTED = 0x10 | ||
| 462 | } nghttp2_goaway_flag; | ||
| 463 | |||
| 464 | /* nghttp2_inflight_settings stores the SETTINGS entries which local | ||
| 465 | @@ -230,6 +237,9 @@ struct nghttp2_session { | ||
| 466 | /* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not | ||
| 467 | considered as in-flight. */ | ||
| 468 | nghttp2_inflight_settings *inflight_settings_head; | ||
| 469 | + /* Stream reset rate limiter. If receiving excessive amount of | ||
| 470 | + stream resets, GOAWAY will be sent. */ | ||
| 471 | + nghttp2_ratelim stream_reset_ratelim; | ||
| 472 | /* The number of outgoing streams. This will be capped by | ||
| 473 | remote_settings.max_concurrent_streams. */ | ||
| 474 | size_t num_outgoing_streams; | ||
| 475 | --- /dev/null | ||
| 476 | +++ b/lib/nghttp2_time.c | ||
| 477 | @@ -0,0 +1,62 @@ | ||
| 478 | +/* | ||
| 479 | + * nghttp2 - HTTP/2 C Library | ||
| 480 | + * | ||
| 481 | + * Copyright (c) 2023 nghttp2 contributors | ||
| 482 | + * | ||
| 483 | + * Permission is hereby granted, free of charge, to any person obtaining | ||
| 484 | + * a copy of this software and associated documentation files (the | ||
| 485 | + * "Software"), to deal in the Software without restriction, including | ||
| 486 | + * without limitation the rights to use, copy, modify, merge, publish, | ||
| 487 | + * distribute, sublicense, and/or sell copies of the Software, and to | ||
| 488 | + * permit persons to whom the Software is furnished to do so, subject to | ||
| 489 | + * the following conditions: | ||
| 490 | + * | ||
| 491 | + * The above copyright notice and this permission notice shall be | ||
| 492 | + * included in all copies or substantial portions of the Software. | ||
| 493 | + * | ||
| 494 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 495 | + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 496 | + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 497 | + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
| 498 | + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
| 499 | + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
| 500 | + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 501 | + */ | ||
| 502 | +#include "nghttp2_time.h" | ||
| 503 | + | ||
| 504 | +#ifdef HAVE_TIME_H | ||
| 505 | +# include <time.h> | ||
| 506 | +#endif /* HAVE_TIME_H */ | ||
| 507 | + | ||
| 508 | +#ifdef HAVE_SYSINFOAPI_H | ||
| 509 | +# include <sysinfoapi.h> | ||
| 510 | +#endif /* HAVE_SYSINFOAPI_H */ | ||
| 511 | + | ||
| 512 | +#ifndef HAVE_GETTICKCOUNT64 | ||
| 513 | +static uint64_t time_now_sec(void) { | ||
| 514 | + time_t t = time(NULL); | ||
| 515 | + | ||
| 516 | + if (t == -1) { | ||
| 517 | + return 0; | ||
| 518 | + } | ||
| 519 | + | ||
| 520 | + return (uint64_t)t; | ||
| 521 | +} | ||
| 522 | +#endif /* HAVE_GETTICKCOUNT64 */ | ||
| 523 | + | ||
| 524 | +#ifdef HAVE_CLOCK_GETTIME | ||
| 525 | +uint64_t nghttp2_time_now_sec(void) { | ||
| 526 | + struct timespec tp; | ||
| 527 | + int rv = clock_gettime(CLOCK_MONOTONIC, &tp); | ||
| 528 | + | ||
| 529 | + if (rv == -1) { | ||
| 530 | + return time_now_sec(); | ||
| 531 | + } | ||
| 532 | + | ||
| 533 | + return (uint64_t)tp.tv_sec; | ||
| 534 | +} | ||
| 535 | +#elif defined(HAVE_GETTICKCOUNT64) | ||
| 536 | +uint64_t nghttp2_time_now_sec(void) { return GetTickCount64() / 1000; } | ||
| 537 | +#else /* !HAVE_CLOCK_GETTIME && !HAVE_GETTICKCOUNT64 */ | ||
| 538 | +uint64_t nghttp2_time_now_sec(void) { return time_now_sec(); } | ||
| 539 | +#endif /* !HAVE_CLOCK_GETTIME && !HAVE_GETTICKCOUNT64 */ | ||
| 540 | --- /dev/null | ||
| 541 | +++ b/lib/nghttp2_time.h | ||
| 542 | @@ -0,0 +1,38 @@ | ||
| 543 | +/* | ||
| 544 | + * nghttp2 - HTTP/2 C Library | ||
| 545 | + * | ||
| 546 | + * Copyright (c) 2023 nghttp2 contributors | ||
| 547 | + * | ||
| 548 | + * Permission is hereby granted, free of charge, to any person obtaining | ||
| 549 | + * a copy of this software and associated documentation files (the | ||
| 550 | + * "Software"), to deal in the Software without restriction, including | ||
| 551 | + * without limitation the rights to use, copy, modify, merge, publish, | ||
| 552 | + * distribute, sublicense, and/or sell copies of the Software, and to | ||
| 553 | + * permit persons to whom the Software is furnished to do so, subject to | ||
| 554 | + * the following conditions: | ||
| 555 | + * | ||
| 556 | + * The above copyright notice and this permission notice shall be | ||
| 557 | + * included in all copies or substantial portions of the Software. | ||
| 558 | + * | ||
| 559 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 560 | + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 561 | + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 562 | + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
| 563 | + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
| 564 | + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
| 565 | + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 566 | + */ | ||
| 567 | +#ifndef NGHTTP2_TIME_H | ||
| 568 | +#define NGHTTP2_TIME_H | ||
| 569 | + | ||
| 570 | +#ifdef HAVE_CONFIG_H | ||
| 571 | +# include <config.h> | ||
| 572 | +#endif /* HAVE_CONFIG_H */ | ||
| 573 | + | ||
| 574 | +#include <nghttp2/nghttp2.h> | ||
| 575 | + | ||
| 576 | +/* nghttp2_time_now_sec returns seconds from implementation-specific | ||
| 577 | + timepoint. If it is unable to get seconds, it returns 0. */ | ||
| 578 | +uint64_t nghttp2_time_now_sec(void); | ||
| 579 | + | ||
| 580 | +#endif /* NGHTTP2_TIME_H */ | ||
| 581 | --- /dev/null | ||
| 582 | +++ b/tests/nghttp2_ratelim_test.c | ||
| 583 | @@ -0,0 +1,101 @@ | ||
| 584 | +/* | ||
| 585 | + * nghttp2 - HTTP/2 C Library | ||
| 586 | + * | ||
| 587 | + * Copyright (c) 2023 nghttp2 contributors | ||
| 588 | + * | ||
| 589 | + * Permission is hereby granted, free of charge, to any person obtaining | ||
| 590 | + * a copy of this software and associated documentation files (the | ||
| 591 | + * "Software"), to deal in the Software without restriction, including | ||
| 592 | + * without limitation the rights to use, copy, modify, merge, publish, | ||
| 593 | + * distribute, sublicense, and/or sell copies of the Software, and to | ||
| 594 | + * permit persons to whom the Software is furnished to do so, subject to | ||
| 595 | + * the following conditions: | ||
| 596 | + * | ||
| 597 | + * The above copyright notice and this permission notice shall be | ||
| 598 | + * included in all copies or substantial portions of the Software. | ||
| 599 | + * | ||
| 600 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 601 | + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 602 | + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 603 | + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
| 604 | + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
| 605 | + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
| 606 | + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 607 | + */ | ||
| 608 | +#include "nghttp2_ratelim_test.h" | ||
| 609 | + | ||
| 610 | +#include <stdio.h> | ||
| 611 | + | ||
| 612 | +#include <CUnit/CUnit.h> | ||
| 613 | + | ||
| 614 | +#include "nghttp2_ratelim.h" | ||
| 615 | + | ||
| 616 | +void test_nghttp2_ratelim_update(void) { | ||
| 617 | + nghttp2_ratelim rl; | ||
| 618 | + | ||
| 619 | + nghttp2_ratelim_init(&rl, 1000, 21); | ||
| 620 | + | ||
| 621 | + CU_ASSERT(1000 == rl.val); | ||
| 622 | + CU_ASSERT(1000 == rl.burst); | ||
| 623 | + CU_ASSERT(21 == rl.rate); | ||
| 624 | + CU_ASSERT(0 == rl.tstamp); | ||
| 625 | + | ||
| 626 | + nghttp2_ratelim_update(&rl, 999); | ||
| 627 | + | ||
| 628 | + CU_ASSERT(1000 == rl.val); | ||
| 629 | + CU_ASSERT(999 == rl.tstamp); | ||
| 630 | + | ||
| 631 | + nghttp2_ratelim_drain(&rl, 100); | ||
| 632 | + | ||
| 633 | + CU_ASSERT(900 == rl.val); | ||
| 634 | + | ||
| 635 | + nghttp2_ratelim_update(&rl, 1000); | ||
| 636 | + | ||
| 637 | + CU_ASSERT(921 == rl.val); | ||
| 638 | + | ||
| 639 | + nghttp2_ratelim_update(&rl, 1002); | ||
| 640 | + | ||
| 641 | + CU_ASSERT(963 == rl.val); | ||
| 642 | + | ||
| 643 | + nghttp2_ratelim_update(&rl, 1004); | ||
| 644 | + | ||
| 645 | + CU_ASSERT(1000 == rl.val); | ||
| 646 | + CU_ASSERT(1004 == rl.tstamp); | ||
| 647 | + | ||
| 648 | + /* timer skew */ | ||
| 649 | + nghttp2_ratelim_init(&rl, 1000, 21); | ||
| 650 | + nghttp2_ratelim_update(&rl, 1); | ||
| 651 | + | ||
| 652 | + CU_ASSERT(1000 == rl.val); | ||
| 653 | + | ||
| 654 | + nghttp2_ratelim_update(&rl, 0); | ||
| 655 | + | ||
| 656 | + CU_ASSERT(1000 == rl.val); | ||
| 657 | + | ||
| 658 | + /* rate * duration overflow */ | ||
| 659 | + nghttp2_ratelim_init(&rl, 1000, 100); | ||
| 660 | + nghttp2_ratelim_drain(&rl, 999); | ||
| 661 | + | ||
| 662 | + CU_ASSERT(1 == rl.val); | ||
| 663 | + | ||
| 664 | + nghttp2_ratelim_update(&rl, UINT64_MAX); | ||
| 665 | + | ||
| 666 | + CU_ASSERT(1000 == rl.val); | ||
| 667 | + | ||
| 668 | + /* val + rate * duration overflow */ | ||
| 669 | + nghttp2_ratelim_init(&rl, UINT64_MAX - 1, 2); | ||
| 670 | + nghttp2_ratelim_update(&rl, 1); | ||
| 671 | + | ||
| 672 | + CU_ASSERT(UINT64_MAX - 1 == rl.val); | ||
| 673 | +} | ||
| 674 | + | ||
| 675 | +void test_nghttp2_ratelim_drain(void) { | ||
| 676 | + nghttp2_ratelim rl; | ||
| 677 | + | ||
| 678 | + nghttp2_ratelim_init(&rl, 100, 7); | ||
| 679 | + | ||
| 680 | + CU_ASSERT(-1 == nghttp2_ratelim_drain(&rl, 101)); | ||
| 681 | + CU_ASSERT(0 == nghttp2_ratelim_drain(&rl, 51)); | ||
| 682 | + CU_ASSERT(0 == nghttp2_ratelim_drain(&rl, 49)); | ||
| 683 | + CU_ASSERT(-1 == nghttp2_ratelim_drain(&rl, 1)); | ||
| 684 | +} | ||
| 685 | --- /dev/null | ||
| 686 | +++ b/tests/nghttp2_ratelim_test.h | ||
| 687 | @@ -0,0 +1,35 @@ | ||
| 688 | +/* | ||
| 689 | + * nghttp2 - HTTP/2 C Library | ||
| 690 | + * | ||
| 691 | + * Copyright (c) 2023 nghttp2 contributors | ||
| 692 | + * | ||
| 693 | + * Permission is hereby granted, free of charge, to any person obtaining | ||
| 694 | + * a copy of this software and associated documentation files (the | ||
| 695 | + * "Software"), to deal in the Software without restriction, including | ||
| 696 | + * without limitation the rights to use, copy, modify, merge, publish, | ||
| 697 | + * distribute, sublicense, and/or sell copies of the Software, and to | ||
| 698 | + * permit persons to whom the Software is furnished to do so, subject to | ||
| 699 | + * the following conditions: | ||
| 700 | + * | ||
| 701 | + * The above copyright notice and this permission notice shall be | ||
| 702 | + * included in all copies or substantial portions of the Software. | ||
| 703 | + * | ||
| 704 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 705 | + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 706 | + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 707 | + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
| 708 | + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
| 709 | + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
| 710 | + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 711 | + */ | ||
| 712 | +#ifndef NGHTTP2_RATELIM_TEST_H | ||
| 713 | +#define NGHTTP2_RATELIM_TEST_H | ||
| 714 | + | ||
| 715 | +#ifdef HAVE_CONFIG_H | ||
| 716 | +# include <config.h> | ||
| 717 | +#endif /* HAVE_CONFIG_H */ | ||
| 718 | + | ||
| 719 | +void test_nghttp2_ratelim_update(void); | ||
| 720 | +void test_nghttp2_ratelim_drain(void); | ||
| 721 | + | ||
| 722 | +#endif /* NGHTTP2_RATELIM_TEST_H */ | ||
| 723 | --- a/tests/nghttp2_session_test.c | ||
| 724 | +++ b/tests/nghttp2_session_test.c | ||
| 725 | @@ -10813,6 +10813,109 @@ void test_nghttp2_session_set_stream_use | ||
| 726 | nghttp2_session_del(session); | ||
| 727 | } | ||
| 728 | |||
| 729 | +void test_nghttp2_session_stream_reset_ratelim(void) { | ||
| 730 | + nghttp2_session *session; | ||
| 731 | + nghttp2_session_callbacks callbacks; | ||
| 732 | + nghttp2_frame frame; | ||
| 733 | + ssize_t rv; | ||
| 734 | + nghttp2_bufs bufs; | ||
| 735 | + nghttp2_buf *buf; | ||
| 736 | + nghttp2_mem *mem; | ||
| 737 | + size_t i; | ||
| 738 | + nghttp2_hd_deflater deflater; | ||
| 739 | + size_t nvlen; | ||
| 740 | + nghttp2_nv *nva; | ||
| 741 | + int32_t stream_id; | ||
| 742 | + nghttp2_outbound_item *item; | ||
| 743 | + nghttp2_option *option; | ||
| 744 | + | ||
| 745 | + mem = nghttp2_mem_default(); | ||
| 746 | + frame_pack_bufs_init(&bufs); | ||
| 747 | + | ||
| 748 | + memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); | ||
| 749 | + callbacks.send_callback = null_send_callback; | ||
| 750 | + | ||
| 751 | + nghttp2_option_new(&option); | ||
| 752 | + nghttp2_option_set_stream_reset_rate_limit( | ||
| 753 | + option, NGHTTP2_DEFAULT_STREAM_RESET_BURST, 0); | ||
| 754 | + | ||
| 755 | + nghttp2_session_server_new2(&session, &callbacks, NULL, option); | ||
| 756 | + | ||
| 757 | + nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE, NULL, 0); | ||
| 758 | + rv = nghttp2_frame_pack_settings(&bufs, &frame.settings); | ||
| 759 | + | ||
| 760 | + CU_ASSERT(0 == rv); | ||
| 761 | + | ||
| 762 | + nghttp2_frame_settings_free(&frame.settings, mem); | ||
| 763 | + | ||
| 764 | + buf = &bufs.head->buf; | ||
| 765 | + rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf)); | ||
| 766 | + | ||
| 767 | + CU_ASSERT((ssize_t)nghttp2_buf_len(buf) == rv); | ||
| 768 | + | ||
| 769 | + /* Send SETTINGS ACK */ | ||
| 770 | + rv = nghttp2_session_send(session); | ||
| 771 | + | ||
| 772 | + CU_ASSERT(0 == rv); | ||
| 773 | + | ||
| 774 | + nghttp2_hd_deflate_init(&deflater, mem); | ||
| 775 | + | ||
| 776 | + for (i = 0; i < NGHTTP2_DEFAULT_STREAM_RESET_BURST + 2; ++i) { | ||
| 777 | + stream_id = (int32_t)(i * 2 + 1); | ||
| 778 | + | ||
| 779 | + nghttp2_bufs_reset(&bufs); | ||
| 780 | + | ||
| 781 | + /* HEADERS */ | ||
| 782 | + nvlen = ARRLEN(reqnv); | ||
| 783 | + nghttp2_nv_array_copy(&nva, reqnv, nvlen, mem); | ||
| 784 | + nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, | ||
| 785 | + stream_id, NGHTTP2_HCAT_HEADERS, NULL, nva, | ||
| 786 | + nvlen); | ||
| 787 | + rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater); | ||
| 788 | + | ||
| 789 | + CU_ASSERT(0 == rv); | ||
| 790 | + | ||
| 791 | + nghttp2_frame_headers_free(&frame.headers, mem); | ||
| 792 | + | ||
| 793 | + buf = &bufs.head->buf; | ||
| 794 | + rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf)); | ||
| 795 | + | ||
| 796 | + CU_ASSERT((ssize_t)nghttp2_buf_len(buf) == rv); | ||
| 797 | + | ||
| 798 | + nghttp2_bufs_reset(&bufs); | ||
| 799 | + | ||
| 800 | + /* RST_STREAM */ | ||
| 801 | + nghttp2_frame_rst_stream_init(&frame.rst_stream, stream_id, | ||
| 802 | + NGHTTP2_NO_ERROR); | ||
| 803 | + nghttp2_frame_pack_rst_stream(&bufs, &frame.rst_stream); | ||
| 804 | + nghttp2_frame_rst_stream_free(&frame.rst_stream); | ||
| 805 | + | ||
| 806 | + buf = &bufs.head->buf; | ||
| 807 | + rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf)); | ||
| 808 | + | ||
| 809 | + CU_ASSERT((ssize_t)nghttp2_buf_len(buf) == rv); | ||
| 810 | + | ||
| 811 | + if (i < NGHTTP2_DEFAULT_STREAM_RESET_BURST) { | ||
| 812 | + CU_ASSERT(0 == nghttp2_outbound_queue_size(&session->ob_reg)); | ||
| 813 | + | ||
| 814 | + continue; | ||
| 815 | + } | ||
| 816 | + | ||
| 817 | + CU_ASSERT(1 == nghttp2_outbound_queue_size(&session->ob_reg)); | ||
| 818 | + | ||
| 819 | + item = nghttp2_session_get_next_ob_item(session); | ||
| 820 | + | ||
| 821 | + CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type); | ||
| 822 | + CU_ASSERT(NGHTTP2_DEFAULT_STREAM_RESET_BURST * 2 + 1 == | ||
| 823 | + item->frame.goaway.last_stream_id); | ||
| 824 | + } | ||
| 825 | + | ||
| 826 | + nghttp2_hd_deflate_free(&deflater); | ||
| 827 | + nghttp2_session_del(session); | ||
| 828 | + nghttp2_bufs_free(&bufs); | ||
| 829 | + nghttp2_option_del(option); | ||
| 830 | +} | ||
| 831 | + | ||
| 832 | static void check_nghttp2_http_recv_headers_fail( | ||
| 833 | nghttp2_session *session, nghttp2_hd_deflater *deflater, int32_t stream_id, | ||
| 834 | int stream_state, const nghttp2_nv *nva, size_t nvlen) { | ||
| 835 | --- a/tests/nghttp2_session_test.h | ||
| 836 | +++ b/tests/nghttp2_session_test.h | ||
| 837 | @@ -160,6 +160,7 @@ void test_nghttp2_session_removed_closed | ||
| 838 | void test_nghttp2_session_pause_data(void); | ||
| 839 | void test_nghttp2_session_no_closed_streams(void); | ||
| 840 | void test_nghttp2_session_set_stream_user_data(void); | ||
| 841 | +void test_nghttp2_session_stream_reset_ratelim(void); | ||
| 842 | void test_nghttp2_http_mandatory_headers(void); | ||
| 843 | void test_nghttp2_http_content_length(void); | ||
| 844 | void test_nghttp2_http_content_length_mismatch(void); | ||
| 845 | --- a/tests/CMakeLists.txt | ||
| 846 | +++ b/tests/CMakeLists.txt | ||
| 847 | @@ -21,6 +21,7 @@ if(HAVE_CUNIT) | ||
| 848 | nghttp2_npn_test.c | ||
| 849 | nghttp2_helper_test.c | ||
| 850 | nghttp2_buf_test.c | ||
| 851 | + nghttp2_ratelim_test.c | ||
| 852 | ) | ||
| 853 | |||
| 854 | add_executable(main EXCLUDE_FROM_ALL | ||
| 855 | --- a/tests/Makefile.am | ||
| 856 | +++ b/tests/Makefile.am | ||
| 857 | @@ -40,14 +40,16 @@ OBJECTS = main.c nghttp2_pq_test.c nghtt | ||
| 858 | nghttp2_hd_test.c \ | ||
| 859 | nghttp2_npn_test.c \ | ||
| 860 | nghttp2_helper_test.c \ | ||
| 861 | - nghttp2_buf_test.c | ||
| 862 | + nghttp2_buf_test.c \ | ||
| 863 | + nghttp2_ratelim_test.c | ||
| 864 | |||
| 865 | HFILES = nghttp2_pq_test.h nghttp2_map_test.h nghttp2_queue_test.h \ | ||
| 866 | nghttp2_session_test.h \ | ||
| 867 | nghttp2_frame_test.h nghttp2_stream_test.h nghttp2_hd_test.h \ | ||
| 868 | nghttp2_npn_test.h nghttp2_helper_test.h \ | ||
| 869 | nghttp2_test_helper.h \ | ||
| 870 | - nghttp2_buf_test.h | ||
| 871 | + nghttp2_buf_test.h \ | ||
| 872 | + nghttp2_ratelim_test.h | ||
| 873 | |||
| 874 | main_SOURCES = $(HFILES) $(OBJECTS) | ||
| 875 | |||
| 876 | --- a/lib/nghttp2_option.h | ||
| 877 | +++ b/lib/nghttp2_option.h | ||
| 878 | @@ -68,6 +68,7 @@ typedef enum { | ||
| 879 | NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10, | ||
| 880 | NGHTTP2_OPT_MAX_OUTBOUND_ACK = 1 << 11, | ||
| 881 | NGHTTP2_OPT_MAX_SETTINGS = 1 << 12, | ||
| 882 | + NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT = 1 << 15, | ||
| 883 | } nghttp2_option_flag; | ||
| 884 | |||
| 885 | /** | ||
| 886 | @@ -75,6 +76,11 @@ typedef enum { | ||
| 887 | */ | ||
| 888 | struct nghttp2_option { | ||
| 889 | /** | ||
| 890 | + * NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT | ||
| 891 | + */ | ||
| 892 | + uint64_t stream_reset_burst; | ||
| 893 | + uint64_t stream_reset_rate; | ||
| 894 | + /** | ||
| 895 | * NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH | ||
| 896 | */ | ||
| 897 | size_t max_send_header_block_length; | ||
| 898 | --- a/tests/main.c | ||
| 899 | +++ b/tests/main.c | ||
| 900 | @@ -40,6 +40,7 @@ | ||
| 901 | #include "nghttp2_npn_test.h" | ||
| 902 | #include "nghttp2_helper_test.h" | ||
| 903 | #include "nghttp2_buf_test.h" | ||
| 904 | +#include "nghttp2_ratelim_test.h" | ||
| 905 | |||
| 906 | extern int nghttp2_enable_strict_preface; | ||
| 907 | |||
| 908 | @@ -323,6 +324,8 @@ int main() { | ||
| 909 | test_nghttp2_session_no_closed_streams) || | ||
| 910 | !CU_add_test(pSuite, "session_set_stream_user_data", | ||
| 911 | test_nghttp2_session_set_stream_user_data) || | ||
| 912 | + !CU_add_test(pSuite, "session_stream_reset_ratelim", | ||
| 913 | + test_nghttp2_session_stream_reset_ratelim) || | ||
| 914 | !CU_add_test(pSuite, "http_mandatory_headers", | ||
| 915 | test_nghttp2_http_mandatory_headers) || | ||
| 916 | !CU_add_test(pSuite, "http_content_length", | ||
| 917 | @@ -418,7 +421,9 @@ int main() { | ||
| 918 | !CU_add_test(pSuite, "bufs_advance", test_nghttp2_bufs_advance) || | ||
| 919 | !CU_add_test(pSuite, "bufs_next_present", | ||
| 920 | test_nghttp2_bufs_next_present) || | ||
| 921 | - !CU_add_test(pSuite, "bufs_realloc", test_nghttp2_bufs_realloc)) { | ||
| 922 | + !CU_add_test(pSuite, "bufs_realloc", test_nghttp2_bufs_realloc) || | ||
| 923 | + !CU_add_test(pSuite, "ratelim_update", test_nghttp2_ratelim_update) || | ||
| 924 | + !CU_add_test(pSuite, "ratelim_drain", test_nghttp2_ratelim_drain)) { | ||
| 925 | CU_cleanup_registry(); | ||
| 926 | return (int)CU_get_error(); | ||
| 927 | } | ||
diff --git a/meta/recipes-support/nghttp2/nghttp2_1.47.0.bb b/meta/recipes-support/nghttp2/nghttp2_1.47.0.bb index 0b9091f7e8..b67313b5c2 100644 --- a/meta/recipes-support/nghttp2/nghttp2_1.47.0.bb +++ b/meta/recipes-support/nghttp2/nghttp2_1.47.0.bb | |||
| @@ -10,6 +10,7 @@ SRC_URI = "\ | |||
| 10 | https://github.com/nghttp2/nghttp2/releases/download/v${PV}/nghttp2-${PV}.tar.xz \ | 10 | https://github.com/nghttp2/nghttp2/releases/download/v${PV}/nghttp2-${PV}.tar.xz \ |
| 11 | file://0001-fetch-ocsp-response-use-python3.patch \ | 11 | file://0001-fetch-ocsp-response-use-python3.patch \ |
| 12 | file://CVE-2023-35945.patch \ | 12 | file://CVE-2023-35945.patch \ |
| 13 | file://CVE-2023-44487.patch \ | ||
| 13 | " | 14 | " |
| 14 | SRC_URI[sha256sum] = "68271951324554c34501b85190f22f2221056db69f493afc3bbac8e7be21e7cc" | 15 | SRC_URI[sha256sum] = "68271951324554c34501b85190f22f2221056db69f493afc3bbac8e7be21e7cc" |
| 15 | 16 | ||
