summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraszh07 <mail2szahir@gmail.com>2024-03-21 15:33:32 +0530
committerSteve Sakoman <steve@sakoman.com>2024-04-05 07:23:58 -0700
commitcf1c9d3daaccb5909d19d1cf4baaa6a152e0e73a (patch)
tree34ce7b2faf0214e245486515bdb258ae80dc3474
parentb6f6c729453cb88961488e3332046517e2fe99bb (diff)
downloadpoky-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>
-rw-r--r--meta/recipes-support/nghttp2/nghttp2/CVE-2023-44487.patch927
-rw-r--r--meta/recipes-support/nghttp2/nghttp2_1.47.0.bb1
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 @@
1From 72b4af6143681f528f1d237b21a9a7aee1738832 Mon Sep 17 00:00:00 2001
2From: Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
3Date: Sun, 1 Oct 2023 00:05:01 +0900
4Subject: [PATCH] Rework session management
5
6CVE: CVE-2023-44487
7
8Upstream-Status: Backport [https://github.com/nghttp2/nghttp2/commit/72b4af6143681f528f1d237b21a9a7aee1738832]
9
10Signed-off-by: Zahir Hussain zahir.basha@kpit.com
11Signed-off-by: aszh07 <mail2szahir@gmail.com>
12---
13CMakeLists.txt | 4 ++
14cmakeconfig.h.in | 9 +++
15configure.ac | 21 +++++++
16doc/Makefile.am | 1 +
17lib/CMakeLists.txt | 2 +
18lib/Makefile.am | 4 ++
19lib/includes/nghttp2/nghttp2.h | 17 ++++++
20lib/nghttp2_option.c | 7 +++
21lib/nghttp2_ratelim.c | 75 ++++++++++++++++++++++++
22lib/nghttp2_ratelim.h | 57 ++++++++++++++++++
23lib/nghttp2_session.c | 34 ++++++++++-
24lib/nghttp2_session.h | 12 +++-
25lib/nghttp2_time.c | 62 ++++++++++++++++++++
26lib/nghttp2_time.h | 38 ++++++++++++
27tests/nghttp2_ratelim_test.c | 101 ++++++++++++++++++++++++++++++++
28tests/nghttp2_ratelim_test.h | 35 +++++++++++
29tests/nghttp2_session_test.c | 103 +++++++++++++++++++++++++++++++++
30tests/nghttp2_session_test.h | 1 +
31tests/CMakeLists.txt | 1 +
32tests/Makefile.am | 6 +-
33lib/nghttp2_option.h | 6 ++
34tests/main.c | 7 ++-
3522 files changed, 598 insertions(+), 5 deletions(-)
36create mode 100644 lib/nghttp2_ratelim.c
37create mode 100644 lib/nghttp2_ratelim.h
38create mode 100644 lib/nghttp2_time.c
39create mode 100644 lib/nghttp2_time.h
40create mode 100644 tests/nghttp2_ratelim_test.c
41create 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"
14SRC_URI[sha256sum] = "68271951324554c34501b85190f22f2221056db69f493afc3bbac8e7be21e7cc" 15SRC_URI[sha256sum] = "68271951324554c34501b85190f22f2221056db69f493afc3bbac8e7be21e7cc"
15 16