Skip to content
Permalink
Browse files

http2: stop reading from socket if writes are in progress

If a write to the underlying socket finishes asynchronously, that
means that we cannot write any more data at that point without waiting
for it to finish. If this happens, we should also not be producing any
more input.

This is part of mitigating CVE-2019-9511/CVE-2019-9517.

Backport-PR-URL: #29123
PR-URL: #29122
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information...
addaleax authored and BethGriggs committed Aug 10, 2019
1 parent 17357d3 commit 0ce699c7b120ae7c672f4ffd0dc1562db3dae0a7
Showing with 18 additions and 1 deletion.
  1. +16 −1 src/node_http2.cc
  2. +2 −0 src/node_http2.h
@@ -1574,9 +1574,18 @@ void Http2Session::HandleSettingsFrame(const nghttp2_frame* frame) {
void Http2Session::OnStreamAfterWrite(WriteWrap* w, int status) {
Debug(this, "write finished with status %d", status);

CHECK_NE(flags_ & SESSION_STATE_WRITE_IN_PROGRESS, 0);
flags_ &= ~SESSION_STATE_WRITE_IN_PROGRESS;

// Inform all pending writes about their completion.
ClearOutgoing(status);

if ((flags_ & SESSION_STATE_READING_STOPPED) &&
nghttp2_session_want_read(session_)) {
flags_ &= ~SESSION_STATE_READING_STOPPED;
stream_->ReadStart();
}

if (!(flags_ & SESSION_STATE_WRITE_SCHEDULED)) {
// Schedule a new write if nghttp2 wants to send data.
MaybeScheduleWrite();
@@ -1616,10 +1625,13 @@ void Http2Session::MaybeScheduleWrite() {
}

void Http2Session::MaybeStopReading() {
if (flags_ & SESSION_STATE_READING_STOPPED) return;
int want_read = nghttp2_session_want_read(session_);
Debug(this, "wants read? %d", want_read);
if (want_read == 0)
if (want_read == 0 || (flags_ & SESSION_STATE_WRITE_IN_PROGRESS)) {
flags_ |= SESSION_STATE_READING_STOPPED;
stream_->ReadStop();
}
}

// Unset the sending state, finish up all current writes, and reset
@@ -1746,8 +1758,11 @@ uint8_t Http2Session::SendPendingData() {

chunks_sent_since_last_write_++;

CHECK_EQ(flags_ & SESSION_STATE_WRITE_IN_PROGRESS, 0);
flags_ |= SESSION_STATE_WRITE_IN_PROGRESS;
StreamWriteResult res = underlying_stream()->Write(*bufs, count);
if (!res.async) {
flags_ &= ~SESSION_STATE_WRITE_IN_PROGRESS;
ClearOutgoing(res.err);
}

@@ -334,6 +334,8 @@ enum session_state_flags {
SESSION_STATE_CLOSED = 0x4,
SESSION_STATE_CLOSING = 0x8,
SESSION_STATE_SENDING = 0x10,
SESSION_STATE_WRITE_IN_PROGRESS = 0x20,
SESSION_STATE_READING_STOPPED = 0x40,
};

typedef uint32_t(*get_setting)(nghttp2_session* session,

0 comments on commit 0ce699c

Please sign in to comment.
You can’t perform that action at this time.