Skip to content

Commit

Permalink
deps: update nghttp2 to 1.41.0
Browse files Browse the repository at this point in the history
Fixes: https://hackerone.com/reports/446662
CVE-ID: CVE-2020-11080
PR-URL: nodejs-private/node-private#204
Reviewed-By: Matteo Collina <[email protected]>
  • Loading branch information
jasnell authored and targos committed Jun 2, 2020
1 parent 290720d commit 0a7bf50
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 127 deletions.
76 changes: 0 additions & 76 deletions deps/nghttp2/lib/CMakeLists.txt

This file was deleted.

23 changes: 23 additions & 0 deletions deps/nghttp2/lib/includes/nghttp2/nghttp2.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,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
*
Expand Down Expand Up @@ -398,6 +405,11 @@ typedef enum {
* receives an other type of frame.
*/
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.,
Expand Down Expand Up @@ -2659,6 +2671,17 @@ NGHTTP2_EXTERN void nghttp2_option_set_no_closed_streams(nghttp2_option *option,
NGHTTP2_EXTERN void nghttp2_option_set_max_outbound_ack(nghttp2_option *option,
size_t val);

/**
* @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
*
Expand Down
4 changes: 2 additions & 2 deletions deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@
* @macro
* Version number of the nghttp2 library release
*/
#define NGHTTP2_VERSION "1.40.0"
#define NGHTTP2_VERSION "1.41.0"

/**
* @macro
* Numerical representation of the version number of the nghttp2 library
* release. This is a 24 bit number with 8 bits for major number, 8 bits
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
*/
#define NGHTTP2_VERSION_NUM 0x012800
#define NGHTTP2_VERSION_NUM 0x012900

#endif /* NGHTTP2VER_H */
2 changes: 2 additions & 0 deletions deps/nghttp2/lib/nghttp2_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,8 @@ const char *nghttp2_strerror(int error_code) {
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";
}
Expand Down
5 changes: 5 additions & 0 deletions deps/nghttp2/lib/nghttp2_option.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,8 @@ void nghttp2_option_set_max_outbound_ack(nghttp2_option *option, size_t val) {
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;
}
5 changes: 5 additions & 0 deletions deps/nghttp2/lib/nghttp2_option.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand All @@ -85,6 +86,10 @@ struct nghttp2_option {
* NGHTTP2_OPT_MAX_OUTBOUND_ACK
*/
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.
Expand Down
88 changes: 43 additions & 45 deletions deps/nghttp2/lib/nghttp2_session.c
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ static int session_new(nghttp2_session **session_ptr,

(*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) &&
Expand Down Expand Up @@ -521,6 +522,11 @@ static int session_new(nghttp2_session **session_ptr,
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,
Expand Down Expand Up @@ -2494,14 +2500,6 @@ static int session_update_stream_consumed_size(nghttp2_session *session,
static int session_update_connection_consumed_size(nghttp2_session *session,
size_t delta_size);

static int session_update_recv_connection_window_size(nghttp2_session *session,
size_t delta_size);

static int session_update_recv_stream_window_size(nghttp2_session *session,
nghttp2_stream *stream,
size_t delta_size,
int send_window_update);

/*
* Called after a frame is sent. This function runs
* on_frame_send_callback and handles stream closure upon END_STREAM
Expand Down Expand Up @@ -2735,7 +2733,7 @@ static int session_after_frame_sent1(nghttp2_session *session) {
if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
rv = session_update_connection_consumed_size(session, 0);
} else {
rv = session_update_recv_connection_window_size(session, 0);
rv = nghttp2_session_update_recv_connection_window_size(session, 0);
}

if (nghttp2_is_fatal(rv)) {
Expand All @@ -2761,7 +2759,8 @@ static int session_after_frame_sent1(nghttp2_session *session) {
if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
rv = session_update_stream_consumed_size(session, stream, 0);
} else {
rv = session_update_recv_stream_window_size(session, stream, 0, 1);
rv =
nghttp2_session_update_recv_stream_window_size(session, stream, 0, 1);
}

if (nghttp2_is_fatal(rv)) {
Expand Down Expand Up @@ -5019,22 +5018,10 @@ static int adjust_recv_window_size(int32_t *recv_window_size_ptr, size_t delta,
return 0;
}

/*
* Accumulates received bytes |delta_size| for stream-level flow
* control and decides whether to send WINDOW_UPDATE to that stream.
* If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, WINDOW_UPDATE will not
* be sent.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
static int session_update_recv_stream_window_size(nghttp2_session *session,
nghttp2_stream *stream,
size_t delta_size,
int send_window_update) {
int nghttp2_session_update_recv_stream_window_size(nghttp2_session *session,
nghttp2_stream *stream,
size_t delta_size,
int send_window_update) {
int rv;
rv = adjust_recv_window_size(&stream->recv_window_size, delta_size,
stream->local_window_size);
Expand Down Expand Up @@ -5063,20 +5050,8 @@ static int session_update_recv_stream_window_size(nghttp2_session *session,
return 0;
}

/*
* Accumulates received bytes |delta_size| for connection-level flow
* control and decides whether to send WINDOW_UPDATE to the
* connection. If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set,
* WINDOW_UPDATE will not be sent.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
static int session_update_recv_connection_window_size(nghttp2_session *session,
size_t delta_size) {
int nghttp2_session_update_recv_connection_window_size(nghttp2_session *session,
size_t delta_size) {
int rv;
rv = adjust_recv_window_size(&session->recv_window_size, delta_size,
session->local_window_size);
Expand Down Expand Up @@ -5678,6 +5653,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
break;
}

/* Check the settings flood counter early to be safe */
if (session->obq_flood_counter_ >= session->max_outbound_ack &&
!(iframe->frame.hd.flags & NGHTTP2_FLAG_ACK)) {
return NGHTTP2_ERR_FLOODED;
}

iframe->state = NGHTTP2_IB_READ_SETTINGS;

if (iframe->payloadleft) {
Expand All @@ -5688,6 +5669,16 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
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);

Expand Down Expand Up @@ -6454,7 +6445,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
}

/* Pad Length field is subject to flow control */
rv = session_update_recv_connection_window_size(session, readlen);
rv = nghttp2_session_update_recv_connection_window_size(session, readlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
Expand All @@ -6477,7 +6468,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,

stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id);
if (stream) {
rv = session_update_recv_stream_window_size(
rv = nghttp2_session_update_recv_stream_window_size(
session, stream, readlen,
iframe->payloadleft ||
(iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
Expand Down Expand Up @@ -6524,7 +6515,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (readlen > 0) {
ssize_t data_readlen;

rv = session_update_recv_connection_window_size(session, readlen);
rv = nghttp2_session_update_recv_connection_window_size(session,
readlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
Expand All @@ -6533,7 +6525,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return (ssize_t)inlen;
}

rv = session_update_recv_stream_window_size(
rv = nghttp2_session_update_recv_stream_window_size(
session, stream, readlen,
iframe->payloadleft ||
(iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
Expand Down Expand Up @@ -6634,7 +6626,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (readlen > 0) {
/* Update connection-level flow control window for ignored
DATA frame too */
rv = session_update_recv_connection_window_size(session, readlen);
rv = nghttp2_session_update_recv_connection_window_size(session,
readlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
Expand Down Expand Up @@ -7454,6 +7447,11 @@ static int nghttp2_session_upgrade_internal(nghttp2_session *session,
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) {
Expand Down
Loading

0 comments on commit 0a7bf50

Please sign in to comment.