summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2019-08-11 01:31:20 +0200
committerMichaƫl Zasso <targos@protonmail.com>2019-08-15 09:51:53 +0200
commitba624b6766fffc11fc9a387feee58be2c5e1d8b8 (patch)
tree9b0468b252f6b3b5a669cf0e342c24324cb1d902
parent695e38be69a780417eef32db744528c3c78d6b0b (diff)
downloadandroid-node-v8-ba624b6766fffc11fc9a387feee58be2c5e1d8b8.tar.gz
android-node-v8-ba624b6766fffc11fc9a387feee58be2c5e1d8b8.tar.bz2
android-node-v8-ba624b6766fffc11fc9a387feee58be2c5e1d8b8.zip
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. PR-URL: https://github.com/nodejs/node/pull/29122 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
-rw-r--r--src/node_http2.cc17
-rw-r--r--src/node_http2.h2
2 files changed, 18 insertions, 1 deletions
diff --git a/src/node_http2.cc b/src/node_http2.cc
index a0b87dd94a..0fec129373 100644
--- a/src/node_http2.cc
+++ b/src/node_http2.cc
@@ -1542,9 +1542,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();
@@ -1582,10 +1591,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
@@ -1716,8 +1728,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);
}
diff --git a/src/node_http2.h b/src/node_http2.h
index e0862614f2..21e05157c1 100644
--- a/src/node_http2.h
+++ b/src/node_http2.h
@@ -335,6 +335,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,