diff --git a/src/node_http2.cc b/src/node_http2.cc index 3f24c3a25ee..63617cfd9f9 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -6,6 +6,7 @@ #include "node_http2.h" #include "node_http2_state.h" #include "node_perf.h" +#include "node_revert.h" #include "util-inl.h" #include @@ -921,11 +922,17 @@ int Http2Session::OnBeginHeadersCallback(nghttp2_session* handle, if (UNLIKELY(!session->CanAddStream() || Http2Stream::New(session, id, frame->headers.cat) == nullptr)) { + if (session->rejected_stream_count_++ > 100 && + !IsReverted(SECURITY_REVERT_CVE_2019_9514)) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } // Too many concurrent streams being opened nghttp2_submit_rst_stream(**session, NGHTTP2_FLAG_NONE, id, NGHTTP2_ENHANCE_YOUR_CALM); return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; } + + session->rejected_stream_count_ = 0; } else if (!stream->IsDestroyed()) { stream->StartHeaders(frame->headers.cat); } diff --git a/src/node_http2.h b/src/node_http2.h index 47d25f2b076..1739a29b256 100644 --- a/src/node_http2.h +++ b/src/node_http2.h @@ -1005,6 +1005,11 @@ class Http2Session : public AsyncWrap, public StreamListener { std::vector outgoing_buffers_; std::vector outgoing_storage_; std::vector pending_rst_streams_; + // Count streams that have been rejected while being opened. Exceeding a fixed + // limit will result in the session being destroyed, as an indication of a + // misbehaving peer. This counter is reset once new streams are being + // accepted again. + int32_t rejected_stream_count_ = 0; void CopyDataIntoOutgoing(const uint8_t* src, size_t src_length); void ClearOutgoing(int status); diff --git a/src/node_revert.h b/src/node_revert.h index 38e2ba71053..b0853ee75f1 100644 --- a/src/node_revert.h +++ b/src/node_revert.h @@ -15,8 +15,11 @@ **/ namespace node { -#define SECURITY_REVERSIONS(XX) +#define SECURITY_REVERSIONS(XX) \ + XX(CVE_2019_9514, "CVE-2019-9514", "HTTP/2 Reset Flood") \ // XX(CVE_2016_PEND, "CVE-2016-PEND", "Vulnerability Title") + // TODO(addaleax): Remove all of the above before Node.js 13 as the comment + // at the start of the file indicates. enum reversion { #define V(code, ...) SECURITY_REVERT_##code,