aboutsummaryrefslogtreecommitdiffstats
path: root/meta-networking/recipes-support/nghttp2/nghttp2/CVE-2020-11080-2.patch
blob: d3c57e9a806b85ddcabf26edfb5a1fef00e9aac9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
From 336a98feb0d56b9ac54e12736b18785c27f75090 Mon Sep 17 00:00:00 2001
From: James M Snell <jasnell@gmail.com>
Date: Fri, 17 Apr 2020 16:53:51 -0700
Subject: [PATCH] Implement max settings option

CVE: CVE-2020-11080
Upstream-Status: Backport [https://github.com/nghttp2/nghttp2/commit/336a98feb0d56b9ac54e12736b18785c27f75090.patch]
Comment: No hunks refreshed
Affects-version: < v1.41.0
Signed-off-by: Rahul Taya <Rahul.Taya@kpit.com>
---
 doc/CMakeLists.txt             |  1 +
 doc/Makefile.am                |  1 +
 lib/includes/nghttp2/nghttp2.h | 23 +++++++++++++
 lib/nghttp2_helper.c           |  2 ++
 lib/nghttp2_option.c           |  5 +++
 lib/nghttp2_option.h           |  5 +++
 lib/nghttp2_session.c          | 21 ++++++++++++
 lib/nghttp2_session.h          |  2 ++
 tests/main.c                   |  2 ++
 tests/nghttp2_session_test.c   | 61 ++++++++++++++++++++++++++++++++++
 tests/nghttp2_session_test.h   |  1 +
 11 files changed, 124 insertions(+)

Index: nghttp2-1.40.0/doc/CMakeLists.txt
===================================================================
--- nghttp2-1.40.0.orig/doc/CMakeLists.txt
+++ nghttp2-1.40.0/doc/CMakeLists.txt
@@ -42,6 +42,7 @@ set(APIDOCS
   nghttp2_option_set_no_recv_client_magic.rst
   nghttp2_option_set_peer_max_concurrent_streams.rst
   nghttp2_option_set_user_recv_extension_type.rst
+  nghttp2_option_set_max_settings.rst
   nghttp2_pack_settings_payload.rst
   nghttp2_priority_spec_check_default.rst
   nghttp2_priority_spec_default_init.rst
Index: nghttp2-1.40.0/lib/includes/nghttp2/nghttp2.h
===================================================================
--- nghttp2-1.40.0.orig/lib/includes/nghttp2/nghttp2.h
+++ nghttp2-1.40.0/lib/includes/nghttp2/nghttp2.h
@@ -229,6 +229,13 @@ typedef struct {
 #define NGHTTP2_CLIENT_MAGIC_LEN 24
 
 /**
+ * @macro
+ *
+ * The default max number of settings per SETTINGS frame
+ */
+#define NGHTTP2_DEFAULT_MAX_SETTINGS 32
+
+/**
  * @enum
  *
  * Error codes used in this library.  The code range is [-999, -500],
@@ -399,6 +406,11 @@ typedef enum {
    */
   NGHTTP2_ERR_SETTINGS_EXPECTED = -536,
   /**
+   * When a local endpoint receives too many settings entries
+   * in a single SETTINGS frame.
+   */
+  NGHTTP2_ERR_TOO_MANY_SETTINGS = -537,
+  /**
    * The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
    * under unexpected condition and processing was terminated (e.g.,
    * out of memory).  If application receives this error code, it must
@@ -2661,6 +2673,17 @@ NGHTTP2_EXTERN void nghttp2_option_set_m
 
 /**
  * @function
+ *
+ * This function sets the maximum number of SETTINGS entries per
+ * SETTINGS frame that will be accepted. If more than those entries
+ * are received, the peer is considered to be misbehaving and session
+ * will be closed. The default value is 32.
+ */
+NGHTTP2_EXTERN void nghttp2_option_set_max_settings(nghttp2_option *option,
+                                                    size_t val);
+
+/**
+ * @function
  *
  * Initializes |*session_ptr| for client use.  The all members of
  * |callbacks| are copied to |*session_ptr|.  Therefore |*session_ptr|
Index: nghttp2-1.40.0/lib/nghttp2_helper.c
===================================================================
--- nghttp2-1.40.0.orig/lib/nghttp2_helper.c
+++ nghttp2-1.40.0/lib/nghttp2_helper.c
@@ -334,6 +334,8 @@ const char *nghttp2_strerror(int error_c
   case NGHTTP2_ERR_FLOODED:
     return "Flooding was detected in this HTTP/2 session, and it must be "
            "closed";
+  case NGHTTP2_ERR_TOO_MANY_SETTINGS:
+    return "SETTINGS frame contained more than the maximum allowed entries";
   default:
     return "Unknown error code";
   }
Index: nghttp2-1.40.0/lib/nghttp2_option.c
===================================================================
--- nghttp2-1.40.0.orig/lib/nghttp2_option.c
+++ nghttp2-1.40.0/lib/nghttp2_option.c
@@ -121,3 +121,8 @@ void nghttp2_option_set_max_outbound_ack
   option->opt_set_mask |= NGHTTP2_OPT_MAX_OUTBOUND_ACK;
   option->max_outbound_ack = val;
 }
+
+void nghttp2_option_set_max_settings(nghttp2_option *option, size_t val) {
+  option->opt_set_mask |= NGHTTP2_OPT_MAX_SETTINGS;
+  option->max_settings = val;
+}
Index: nghttp2-1.40.0/lib/nghttp2_option.h
===================================================================
--- nghttp2-1.40.0.orig/lib/nghttp2_option.h
+++ nghttp2-1.40.0/lib/nghttp2_option.h
@@ -67,6 +67,7 @@ typedef enum {
   NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE = 1 << 9,
   NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10,
   NGHTTP2_OPT_MAX_OUTBOUND_ACK = 1 << 11,
+  NGHTTP2_OPT_MAX_SETTINGS = 1 << 12,
 } nghttp2_option_flag;
 
 /**
@@ -86,6 +87,10 @@ struct nghttp2_option {
    */
   size_t max_outbound_ack;
   /**
+   * NGHTTP2_OPT_MAX_SETTINGS
+   */
+  size_t max_settings;
+  /**
    * Bitwise OR of nghttp2_option_flag to determine that which fields
    * are specified.
    */
Index: nghttp2-1.40.0/lib/nghttp2_session.c
===================================================================
--- nghttp2-1.40.0.orig/lib/nghttp2_session.c
+++ nghttp2-1.40.0/lib/nghttp2_session.c
@@ -458,6 +458,7 @@ static int session_new(nghttp2_session *
 
   (*session_ptr)->max_send_header_block_length = NGHTTP2_MAX_HEADERSLEN;
   (*session_ptr)->max_outbound_ack = NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM;
+  (*session_ptr)->max_settings = NGHTTP2_DEFAULT_MAX_SETTINGS;
 
   if (option) {
     if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) &&
@@ -521,6 +522,11 @@ static int session_new(nghttp2_session *
     if (option->opt_set_mask & NGHTTP2_OPT_MAX_OUTBOUND_ACK) {
       (*session_ptr)->max_outbound_ack = option->max_outbound_ack;
     }
+
+    if ((option->opt_set_mask & NGHTTP2_OPT_MAX_SETTINGS) &&
+        option->max_settings) {
+      (*session_ptr)->max_settings = option->max_settings;
+    }
   }
 
   rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater,
@@ -5694,6 +5700,16 @@ ssize_t nghttp2_session_mem_recv(nghttp2
           iframe->max_niv =
               iframe->frame.hd.length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1;
 
+          if (iframe->max_niv - 1 > session->max_settings) {
+            rv = nghttp2_session_terminate_session_with_reason(
+                session, NGHTTP2_ENHANCE_YOUR_CALM,
+                "SETTINGS: too many setting entries");
+            if (nghttp2_is_fatal(rv)) {
+              return rv;
+            }
+            return (ssize_t)inlen;
+          }
+
           iframe->iv = nghttp2_mem_malloc(mem, sizeof(nghttp2_settings_entry) *
                                                    iframe->max_niv);
 
@@ -7460,6 +7476,11 @@ static int nghttp2_session_upgrade_inter
   if (settings_payloadlen % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) {
     return NGHTTP2_ERR_INVALID_ARGUMENT;
   }
+  /* SETTINGS frame contains too many settings */
+  if (settings_payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH
+        > session->max_settings) {
+    return NGHTTP2_ERR_TOO_MANY_SETTINGS;
+  }
   rv = nghttp2_frame_unpack_settings_payload2(&iv, &niv, settings_payload,
                                               settings_payloadlen, mem);
   if (rv != 0) {
Index: nghttp2-1.40.0/lib/nghttp2_session.h
===================================================================
--- nghttp2-1.40.0.orig/lib/nghttp2_session.h
+++ nghttp2-1.40.0/lib/nghttp2_session.h
@@ -267,6 +267,8 @@ struct nghttp2_session {
   /* The maximum length of header block to send.  Calculated by the
      same way as nghttp2_hd_deflate_bound() does. */
   size_t max_send_header_block_length;
+  /* The maximum number of settings accepted per SETTINGS frame. */
+  size_t max_settings;
   /* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
   uint32_t next_stream_id;
   /* The last stream ID this session initiated.  For client session,
Index: nghttp2-1.40.0/tests/main.c
===================================================================
--- nghttp2-1.40.0.orig/tests/main.c
+++ nghttp2-1.40.0/tests/main.c
@@ -315,6 +315,8 @@ int main() {
                    test_nghttp2_session_set_local_window_size) ||
       !CU_add_test(pSuite, "session_cancel_from_before_frame_send",
                    test_nghttp2_session_cancel_from_before_frame_send) ||
+      !CU_add_test(pSuite, "session_too_many_settings",
+                   test_nghttp2_session_too_many_settings) ||
       !CU_add_test(pSuite, "session_removed_closed_stream",
                    test_nghttp2_session_removed_closed_stream) ||
       !CU_add_test(pSuite, "session_pause_data",
Index: nghttp2-1.40.0/tests/nghttp2_session_test.c
===================================================================
--- nghttp2-1.40.0.orig/tests/nghttp2_session_test.c
+++ nghttp2-1.40.0/tests/nghttp2_session_test.c
@@ -10558,6 +10558,67 @@ void test_nghttp2_session_cancel_from_be
   nghttp2_session_del(session);
 }
 
+void test_nghttp2_session_too_many_settings(void) {
+  nghttp2_session *session;
+  nghttp2_option *option;
+  nghttp2_session_callbacks callbacks;
+  nghttp2_frame frame;
+  nghttp2_bufs bufs;
+  nghttp2_buf *buf;
+  ssize_t rv;
+  my_user_data ud;
+  nghttp2_settings_entry iv[3];
+  nghttp2_mem *mem;
+  nghttp2_outbound_item *item;
+
+  mem = nghttp2_mem_default();
+  frame_pack_bufs_init(&bufs);
+
+  memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
+  callbacks.on_frame_recv_callback = on_frame_recv_callback;
+  callbacks.send_callback = null_send_callback;
+
+  nghttp2_option_new(&option);
+  nghttp2_option_set_max_settings(option, 1);
+
+  nghttp2_session_client_new2(&session, &callbacks, &ud, option);
+
+  CU_ASSERT(1 == session->max_settings);
+
+  nghttp2_option_del(option);
+
+  iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
+  iv[0].value = 3000;
+
+  iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
+  iv[1].value = 16384;
+
+  nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE, dup_iv(iv, 2),
+                              2);
+
+  rv = nghttp2_frame_pack_settings(&bufs, &frame.settings);
+
+  CU_ASSERT(0 == rv);
+  CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
+
+  nghttp2_frame_settings_free(&frame.settings, mem);
+
+  buf = &bufs.head->buf;
+  assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
+
+  ud.frame_recv_cb_called = 0;
+
+  rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
+  CU_ASSERT((ssize_t)nghttp2_buf_len(buf) == rv);
+
+  item = nghttp2_session_get_next_ob_item(session);
+  CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
+
+  nghttp2_bufs_reset(&bufs);
+  nghttp2_bufs_free(&bufs);
+  nghttp2_session_del(session);
+}
+
 static void
 prepare_session_removed_closed_stream(nghttp2_session *session,
                                       nghttp2_hd_deflater *deflater) {
Index: nghttp2-1.40.0/tests/nghttp2_session_test.h
===================================================================
--- nghttp2-1.40.0.orig/tests/nghttp2_session_test.h
+++ nghttp2-1.40.0/tests/nghttp2_session_test.h
@@ -156,6 +156,7 @@ void test_nghttp2_session_repeated_prior
 void test_nghttp2_session_repeated_priority_submission(void);
 void test_nghttp2_session_set_local_window_size(void);
 void test_nghttp2_session_cancel_from_before_frame_send(void);
+void test_nghttp2_session_too_many_settings(void);
 void test_nghttp2_session_removed_closed_stream(void);
 void test_nghttp2_session_pause_data(void);
 void test_nghttp2_session_no_closed_streams(void);
Index: nghttp2-1.40.0/doc/Makefile.am
===================================================================
--- nghttp2-1.40.0.orig/doc/Makefile.am
+++ nghttp2-1.40.0/doc/Makefile.am
@@ -69,6 +69,7 @@ APIDOCS= \
 	nghttp2_option_set_peer_max_concurrent_streams.rst \
 	nghttp2_option_set_user_recv_extension_type.rst \
 	nghttp2_option_set_max_outbound_ack.rst \
+    nghttp2_option_set_max_settings.rst \
 	nghttp2_pack_settings_payload.rst \
 	nghttp2_priority_spec_check_default.rst \
 	nghttp2_priority_spec_default_init.rst \