|
|
6b7b20 |
diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h
|
|
|
6b7b20 |
index 59fc867..3b14027 100644
|
|
|
6b7b20 |
--- a/lib/includes/nghttp2/nghttp2.h
|
|
|
6b7b20 |
+++ b/lib/includes/nghttp2/nghttp2.h
|
|
|
6b7b20 |
@@ -221,6 +221,13 @@ typedef struct {
|
|
|
6b7b20 |
*/
|
|
|
6b7b20 |
#define NGHTTP2_CLIENT_MAGIC_LEN 24
|
|
|
6b7b20 |
|
|
|
6b7b20 |
+/**
|
|
|
6b7b20 |
+ * @macro
|
|
|
6b7b20 |
+ *
|
|
|
6b7b20 |
+ * The default max number of settings per SETTINGS frame
|
|
|
6b7b20 |
+ */
|
|
|
6b7b20 |
+#define NGHTTP2_DEFAULT_MAX_SETTINGS 32
|
|
|
6b7b20 |
+
|
|
|
6b7b20 |
/**
|
|
|
6b7b20 |
* @enum
|
|
|
6b7b20 |
*
|
|
|
6b7b20 |
@@ -382,6 +389,11 @@ typedef enum {
|
|
|
6b7b20 |
* Unexpected internal error, but recovered.
|
|
|
6b7b20 |
*/
|
|
|
6b7b20 |
NGHTTP2_ERR_INTERNAL = -534,
|
|
|
6b7b20 |
+ /**
|
|
|
6b7b20 |
+ * When a local endpoint receives too many settings entries
|
|
|
6b7b20 |
+ * in a single SETTINGS frame.
|
|
|
6b7b20 |
+ */
|
|
|
6b7b20 |
+ NGHTTP2_ERR_TOO_MANY_SETTINGS = -537,
|
|
|
6b7b20 |
/**
|
|
|
6b7b20 |
* The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
|
|
|
6b7b20 |
* under unexpected condition and processing was terminated (e.g.,
|
|
|
6b7b20 |
@@ -2106,6 +2118,17 @@ NGHTTP2_EXTERN void
|
|
|
6b7b20 |
nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option,
|
|
|
6b7b20 |
uint32_t val);
|
|
|
6b7b20 |
|
|
|
6b7b20 |
+/**
|
|
|
6b7b20 |
+ * @function
|
|
|
6b7b20 |
+ *
|
|
|
6b7b20 |
+ * This function sets the maximum number of SETTINGS entries per
|
|
|
6b7b20 |
+ * SETTINGS frame that will be accepted. If more than those entries
|
|
|
6b7b20 |
+ * are received, the peer is considered to be misbehaving and session
|
|
|
6b7b20 |
+ * will be closed. The default value is 32.
|
|
|
6b7b20 |
+ */
|
|
|
6b7b20 |
+NGHTTP2_EXTERN void nghttp2_option_set_max_settings(nghttp2_option *option,
|
|
|
6b7b20 |
+ size_t val);
|
|
|
6b7b20 |
+
|
|
|
6b7b20 |
/**
|
|
|
6b7b20 |
* @function
|
|
|
6b7b20 |
*
|
|
|
6b7b20 |
diff --git a/lib/nghttp2_helper.c b/lib/nghttp2_helper.c
|
|
|
6b7b20 |
index 884abc6..b4d9e55 100644
|
|
|
6b7b20 |
--- a/lib/nghttp2_helper.c
|
|
|
6b7b20 |
+++ b/lib/nghttp2_helper.c
|
|
|
6b7b20 |
@@ -297,6 +297,8 @@ const char *nghttp2_strerror(int error_code) {
|
|
|
6b7b20 |
case NGHTTP2_ERR_FLOODED:
|
|
|
6b7b20 |
return "Flooding was detected in this HTTP/2 session, and it must be "
|
|
|
6b7b20 |
"closed";
|
|
|
6b7b20 |
+ case NGHTTP2_ERR_TOO_MANY_SETTINGS:
|
|
|
6b7b20 |
+ return "SETTINGS frame contained more than the maximum allowed entries";
|
|
|
6b7b20 |
default:
|
|
|
6b7b20 |
return "Unknown error code";
|
|
|
6b7b20 |
}
|
|
|
6b7b20 |
diff --git a/lib/nghttp2_option.c b/lib/nghttp2_option.c
|
|
|
6b7b20 |
index 04dbbc6..e8ee7b4 100644
|
|
|
6b7b20 |
--- a/lib/nghttp2_option.c
|
|
|
6b7b20 |
+++ b/lib/nghttp2_option.c
|
|
|
6b7b20 |
@@ -62,3 +62,8 @@ void nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option,
|
|
|
6b7b20 |
option->opt_set_mask |= NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS;
|
|
|
6b7b20 |
option->max_reserved_remote_streams = val;
|
|
|
6b7b20 |
}
|
|
|
6b7b20 |
+
|
|
|
6b7b20 |
+void nghttp2_option_set_max_settings(nghttp2_option *option, size_t val) {
|
|
|
6b7b20 |
+ option->opt_set_mask |= NGHTTP2_OPT_MAX_SETTINGS;
|
|
|
6b7b20 |
+ option->max_settings = val;
|
|
|
6b7b20 |
+}
|
|
|
6b7b20 |
diff --git a/lib/nghttp2_option.h b/lib/nghttp2_option.h
|
|
|
6b7b20 |
index ebf416a..1ae1a4f 100644
|
|
|
6b7b20 |
--- a/lib/nghttp2_option.h
|
|
|
6b7b20 |
+++ b/lib/nghttp2_option.h
|
|
|
6b7b20 |
@@ -59,7 +59,8 @@ typedef enum {
|
|
|
6b7b20 |
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
|
|
|
6b7b20 |
NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2,
|
|
|
6b7b20 |
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3,
|
|
|
6b7b20 |
- NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4
|
|
|
6b7b20 |
+ NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4,
|
|
|
6b7b20 |
+ NGHTTP2_OPT_MAX_SETTINGS = 1 << 12,
|
|
|
6b7b20 |
} nghttp2_option_flag;
|
|
|
6b7b20 |
|
|
|
6b7b20 |
/**
|
|
|
6b7b20 |
@@ -91,6 +92,11 @@ struct nghttp2_option {
|
|
|
6b7b20 |
* NGHTTP2_OPT_NO_HTTP_MESSAGING
|
|
|
6b7b20 |
*/
|
|
|
6b7b20 |
int no_http_messaging;
|
|
|
6b7b20 |
+
|
|
|
6b7b20 |
+ /**
|
|
|
6b7b20 |
+ * NGHTTP2_OPT_MAX_SETTINGS
|
|
|
6b7b20 |
+ */
|
|
|
6b7b20 |
+ size_t max_settings;
|
|
|
6b7b20 |
};
|
|
|
6b7b20 |
|
|
|
6b7b20 |
#endif /* NGHTTP2_OPTION_H */
|
|
|
6b7b20 |
diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c
|
|
|
6b7b20 |
index e42e46b..a3a84b4 100644
|
|
|
6b7b20 |
--- a/lib/nghttp2_session.c
|
|
|
6b7b20 |
+++ b/lib/nghttp2_session.c
|
|
|
6b7b20 |
@@ -375,6 +375,8 @@ static int session_new(nghttp2_session **session_ptr,
|
|
|
6b7b20 |
/* Limit max outgoing concurrent streams to sensible value */
|
|
|
6b7b20 |
(*session_ptr)->remote_settings.max_concurrent_streams = 100;
|
|
|
6b7b20 |
|
|
|
6b7b20 |
+ (*session_ptr)->max_settings = NGHTTP2_DEFAULT_MAX_SETTINGS;
|
|
|
6b7b20 |
+
|
|
|
6b7b20 |
if (option) {
|
|
|
6b7b20 |
if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) &&
|
|
|
6b7b20 |
option->no_auto_window_update) {
|
|
|
6b7b20 |
@@ -405,6 +407,11 @@ static int session_new(nghttp2_session **session_ptr,
|
|
|
6b7b20 |
|
|
|
6b7b20 |
(*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_HTTP_MESSAGING;
|
|
|
6b7b20 |
}
|
|
|
6b7b20 |
+
|
|
|
6b7b20 |
+ if ((option->opt_set_mask & NGHTTP2_OPT_MAX_SETTINGS) &&
|
|
|
6b7b20 |
+ option->max_settings) {
|
|
|
6b7b20 |
+ (*session_ptr)->max_settings = option->max_settings;
|
|
|
6b7b20 |
+ }
|
|
|
6b7b20 |
}
|
|
|
6b7b20 |
|
|
|
6b7b20 |
(*session_ptr)->callbacks = *callbacks;
|
|
|
6b7b20 |
@@ -4837,6 +4844,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
|
|
6b7b20 |
ssize_t padlen;
|
|
|
6b7b20 |
int rv;
|
|
|
6b7b20 |
int busy = 0;
|
|
|
6b7b20 |
+ int max_niv;
|
|
|
6b7b20 |
nghttp2_frame_hd cont_hd;
|
|
|
6b7b20 |
nghttp2_stream *stream;
|
|
|
6b7b20 |
size_t pri_fieldlen;
|
|
|
6b7b20 |
@@ -5123,9 +5131,30 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
|
|
6b7b20 |
break;
|
|
|
6b7b20 |
}
|
|
|
6b7b20 |
|
|
|
6b7b20 |
+ /* Check the settings flood counter early to be safe */
|
|
|
6b7b20 |
+ if (session->obq_flood_counter_ >= NGHTTP2_MAX_OBQ_FLOOD_ITEM &&
|
|
|
6b7b20 |
+ !(iframe->frame.hd.flags & NGHTTP2_FLAG_ACK)) {
|
|
|
6b7b20 |
+ return NGHTTP2_ERR_FLOODED;
|
|
|
6b7b20 |
+ }
|
|
|
6b7b20 |
+
|
|
|
6b7b20 |
iframe->state = NGHTTP2_IB_READ_SETTINGS;
|
|
|
6b7b20 |
|
|
|
6b7b20 |
if (iframe->payloadleft) {
|
|
|
6b7b20 |
+ /* We allocate iv with additional one entry, to store the
|
|
|
6b7b20 |
+ minimum header table size. */
|
|
|
6b7b20 |
+ max_niv =
|
|
|
6b7b20 |
+ iframe->frame.hd.length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1;
|
|
|
6b7b20 |
+
|
|
|
6b7b20 |
+ if (max_niv - 1 > session->max_settings) {
|
|
|
6b7b20 |
+ rv = nghttp2_session_terminate_session_with_reason(
|
|
|
6b7b20 |
+ session, NGHTTP2_ENHANCE_YOUR_CALM,
|
|
|
6b7b20 |
+ "SETTINGS: too many setting entries");
|
|
|
6b7b20 |
+ if (nghttp2_is_fatal(rv)) {
|
|
|
6b7b20 |
+ return rv;
|
|
|
6b7b20 |
+ }
|
|
|
6b7b20 |
+ return (ssize_t)inlen;
|
|
|
6b7b20 |
+ }
|
|
|
6b7b20 |
+
|
|
|
6b7b20 |
inbound_frame_set_mark(iframe, NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH);
|
|
|
6b7b20 |
break;
|
|
|
6b7b20 |
}
|
|
|
6b7b20 |
@@ -6531,6 +6560,11 @@ static int nghttp2_session_upgrade_internal(nghttp2_session *session,
|
|
|
6b7b20 |
if (settings_payloadlen % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) {
|
|
|
6b7b20 |
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
|
|
6b7b20 |
}
|
|
|
6b7b20 |
+ /* SETTINGS frame contains too many settings */
|
|
|
6b7b20 |
+ if (settings_payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH
|
|
|
6b7b20 |
+ > session->max_settings) {
|
|
|
6b7b20 |
+ return NGHTTP2_ERR_TOO_MANY_SETTINGS;
|
|
|
6b7b20 |
+ }
|
|
|
6b7b20 |
rv = nghttp2_frame_unpack_settings_payload2(&iv, &niv, settings_payload,
|
|
|
6b7b20 |
settings_payloadlen, mem);
|
|
|
6b7b20 |
if (rv != 0) {
|
|
|
6b7b20 |
diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h
|
|
|
6b7b20 |
index 204aea9..87aac84 100644
|
|
|
6b7b20 |
--- a/lib/nghttp2_session.h
|
|
|
6b7b20 |
+++ b/lib/nghttp2_session.h
|
|
|
6b7b20 |
@@ -244,6 +244,8 @@ struct nghttp2_session {
|
|
|
6b7b20 |
size_t nvbuflen;
|
|
|
6b7b20 |
/* Counter for detecting flooding in outbound queue */
|
|
|
6b7b20 |
size_t obq_flood_counter_;
|
|
|
6b7b20 |
+ /* The maximum number of settings accepted per SETTINGS frame. */
|
|
|
6b7b20 |
+ size_t max_settings;
|
|
|
6b7b20 |
/* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
|
|
|
6b7b20 |
uint32_t next_stream_id;
|
|
|
6b7b20 |
/* The last stream ID this session initiated. For client session,
|