http2: pause input processing if sending output · nodejs/node@6d687f7 · GitHub
Skip to content

Commit 6d687f7

Browse files
addaleaxBethGriggs
authored andcommitted
http2: pause input processing if sending output
If we are waiting for the ability to send more output, we should not process more input. This commit a) makes us send output earlier, during processing of input, if we accumulate a lot and b) allows interrupting the call into nghttp2 that processes input data and resuming it at a later time, if we do find ourselves in a position where we are waiting to be able to send more output. This is part of mitigating CVE-2019-9511/CVE-2019-9517. Backport-PR-URL: #29124 PR-URL: #29122 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 854dba6 commit 6d687f7

3 files changed

Lines changed: 141 additions & 45 deletions

File tree

src/node_http2.cc

Lines changed: 90 additions & 43 deletions

src/node_http2.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ enum session_state_flags {
386386
SESSION_STATE_SENDING = 0x10,
387387
SESSION_STATE_WRITE_IN_PROGRESS = 0x20,
388388
SESSION_STATE_READING_STOPPED = 0x40,
389+
SESSION_STATE_NGHTTP2_RECV_PAUSED = 0x80
389390
};
390391

391392
// This allows for 4 default-sized frames with their frame headers
@@ -831,8 +832,8 @@ class Http2Session : public AsyncWrap {
831832
// Indicates whether there currently exist outgoing buffers for this stream.
832833
bool HasWritesOnSocketForStream(Http2Stream* stream);
833834

834-
// Write data to the session
835-
inline ssize_t Write(const uv_buf_t* bufs, size_t nbufs);
835+
// Write data from stream_buf_ to the session
836+
ssize_t ConsumeHTTP2Data();
836837

837838
size_t self_size() const override { return sizeof(*this); }
838839

@@ -896,6 +897,9 @@ class Http2Session : public AsyncWrap {
896897
}
897898

898899
void DecrementCurrentSessionMemory(uint64_t amount) {
900+
#ifdef DEBUG
901+
CHECK_LE(amount, current_session_memory_);
902+
#endif
899903
current_session_memory_ -= amount;
900904
}
901905

@@ -1061,8 +1065,11 @@ class Http2Session : public AsyncWrap {
10611065
uint32_t chunks_sent_since_last_write_ = 0;
10621066

10631067
uv_buf_t stream_buf_ = uv_buf_init(nullptr, 0);
1068+
// When processing input data, either stream_buf_ab_ or stream_buf_allocation_
1069+
// will be set. stream_buf_ab_ is lazily created from stream_buf_allocation_.
10641070
v8::Global<v8::ArrayBuffer> stream_buf_ab_;
10651071
uv_buf_t stream_buf_allocation_ = uv_buf_init(nullptr, 0);
1072+
size_t stream_buf_offset_ = 0;
10661073

10671074
size_t max_outstanding_pings_ = DEFAULT_MAX_PINGS;
10681075
std::queue<Http2Ping*> outstanding_pings_;
@@ -1072,6 +1079,7 @@ class Http2Session : public AsyncWrap {
10721079

10731080
std::vector<nghttp2_stream_write> outgoing_buffers_;
10741081
std::vector<uint8_t> outgoing_storage_;
1082+
size_t outgoing_length_ = 0;
10751083
std::vector<int32_t> pending_rst_streams_;
10761084
// Count streams that have been rejected while being opened. Exceeding a fixed
10771085
// limit will result in the session being destroyed, as an indication of a
@@ -1081,6 +1089,7 @@ class Http2Session : public AsyncWrap {
10811089
// Also use the invalid frame count as a measure for rejecting input frames.
10821090
int32_t invalid_frame_count_ = 0;
10831091

1092+
void PushOutgoingBuffer(nghttp2_stream_write&& write);
10841093
void CopyDataIntoOutgoing(const uint8_t* src, size_t src_length);
10851094
void ClearOutgoing(int status);
10861095

Lines changed: 40 additions & 0 deletions

0 commit comments

Comments
 (0)