Skip to content

Commit 7f17866

Browse files
danbevrichardlau
authored andcommittedDec 23, 2020
src: use unique_ptr for WriteWrap
This commit attempts to avoid a use-after-free error by using unqiue_ptr and passing a reference to it. CVE-ID: CVE-2020-8265 Fixes: nodejs-private/node-private#227 PR-URL: nodejs-private/node-private#238 Reviewed-By: Michael Dawson <midawson@redhat.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Richard Lau <rlau@redhat.com>
1 parent f08d0fe commit 7f17866

11 files changed

+28
-26
lines changed
 

‎src/js_stream.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ int JSStream::DoShutdown(ShutdownWrap* req_wrap) {
105105
}
106106

107107

108-
int JSStream::DoWrite(WriteWrap* w,
108+
int JSStream::DoWrite(std::unique_ptr<WriteWrap>& w,
109109
uv_buf_t* bufs,
110110
size_t count,
111111
uv_stream_t* send_handle) {
@@ -122,7 +122,7 @@ int JSStream::DoWrite(WriteWrap* w,
122122
}
123123

124124
Local<Value> argv[] = {
125-
w->object(),
125+
w.get()->object(),
126126
bufs_arr
127127
};
128128

‎src/js_stream.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class JSStream : public AsyncWrap, public StreamBase {
2222
int ReadStop() override;
2323

2424
int DoShutdown(ShutdownWrap* req_wrap) override;
25-
int DoWrite(WriteWrap* w,
25+
int DoWrite(std::unique_ptr<WriteWrap>& w,
2626
uv_buf_t* bufs,
2727
size_t count,
2828
uv_stream_t* send_handle) override;

‎src/node_file.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ class FileHandle : public AsyncWrap, public StreamBase {
287287
ShutdownWrap* CreateShutdownWrap(v8::Local<v8::Object> object) override;
288288
int DoShutdown(ShutdownWrap* req_wrap) override;
289289

290-
int DoWrite(WriteWrap* w,
290+
int DoWrite(std::unique_ptr<WriteWrap>& w,
291291
uv_buf_t* bufs,
292292
size_t count,
293293
uv_stream_t* send_handle) override {

‎src/node_http2.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -2315,7 +2315,7 @@ int Http2Stream::ReadStop() {
23152315
// chunks of data have been flushed to the underlying nghttp2_session.
23162316
// Note that this does *not* mean that the data has been flushed
23172317
// to the socket yet.
2318-
int Http2Stream::DoWrite(WriteWrap* req_wrap,
2318+
int Http2Stream::DoWrite(std::unique_ptr<WriteWrap>& req_wrap,
23192319
uv_buf_t* bufs,
23202320
size_t nbufs,
23212321
uv_stream_t* send_handle) {
@@ -2330,7 +2330,7 @@ int Http2Stream::DoWrite(WriteWrap* req_wrap,
23302330
// Store the req_wrap on the last write info in the queue, so that it is
23312331
// only marked as finished once all buffers associated with it are finished.
23322332
queue_.emplace(nghttp2_stream_write {
2333-
i == nbufs - 1 ? req_wrap : nullptr,
2333+
i == nbufs - 1 ? req_wrap.get() : nullptr,
23342334
bufs[i]
23352335
});
23362336
IncrementAvailableOutboundLength(bufs[i].len);

‎src/node_http2.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ class Http2Stream : public AsyncWrap,
568568

569569
AsyncWrap* GetAsyncWrap() override { return this; }
570570

571-
int DoWrite(WriteWrap* w, uv_buf_t* bufs, size_t count,
571+
int DoWrite(std::unique_ptr<WriteWrap>& w, uv_buf_t* bufs, size_t count,
572572
uv_stream_t* send_handle) override;
573573

574574
void MemoryInfo(MemoryTracker* tracker) const override {

‎src/stream_base-inl.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -216,14 +216,14 @@ inline StreamWriteResult StreamBase::Write(
216216
}
217217

218218
AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(GetAsyncWrap());
219-
WriteWrap* req_wrap = CreateWriteWrap(req_wrap_obj);
219+
std::unique_ptr<WriteWrap> req_wrap{CreateWriteWrap(req_wrap_obj)};
220220

221221
err = DoWrite(req_wrap, bufs, count, send_handle);
222222
bool async = err == 0;
223223

224-
if (!async) {
224+
if (!async && req_wrap != nullptr) {
225225
req_wrap->Dispose();
226-
req_wrap = nullptr;
226+
req_wrap.release();
227227
}
228228

229229
const char* msg = Error();
@@ -232,7 +232,7 @@ inline StreamWriteResult StreamBase::Write(
232232
ClearError();
233233
}
234234

235-
return StreamWriteResult { async, err, req_wrap, total_bytes };
235+
return StreamWriteResult { async, err, req_wrap.release(), total_bytes };
236236
}
237237

238238
template <typename OtherBase>

‎src/stream_base.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,11 @@ class StreamResource {
215215
virtual int DoTryWrite(uv_buf_t** bufs, size_t* count);
216216
// Perform a write of data, and either call req_wrap->Done() when finished
217217
// and return 0, or return a libuv error code for synchronous failures.
218-
virtual int DoWrite(WriteWrap* w,
219-
uv_buf_t* bufs,
220-
size_t count,
221-
uv_stream_t* send_handle) = 0;
218+
virtual int DoWrite(
219+
/* NOLINT (runtime/references) */ std::unique_ptr<WriteWrap>& w,
220+
uv_buf_t* bufs,
221+
size_t count,
222+
uv_stream_t* send_handle) = 0;
222223

223224
// Returns true if the stream supports the `OnStreamWantsWrite()` interface.
224225
virtual bool HasWantsWrite() const { return false; }

‎src/stream_wrap.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -351,11 +351,11 @@ int LibuvStreamWrap::DoTryWrite(uv_buf_t** bufs, size_t* count) {
351351
}
352352

353353

354-
int LibuvStreamWrap::DoWrite(WriteWrap* req_wrap,
354+
int LibuvStreamWrap::DoWrite(std::unique_ptr<WriteWrap>& req_wrap,
355355
uv_buf_t* bufs,
356356
size_t count,
357357
uv_stream_t* send_handle) {
358-
LibuvWriteWrap* w = static_cast<LibuvWriteWrap*>(req_wrap);
358+
LibuvWriteWrap* w = static_cast<LibuvWriteWrap*>(req_wrap.get());
359359
int r;
360360
if (send_handle == nullptr) {
361361
r = w->Dispatch(uv_write, stream(), bufs, count, AfterUvWrite);

‎src/stream_wrap.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class LibuvStreamWrap : public HandleWrap, public StreamBase {
5151
// Resource implementation
5252
int DoShutdown(ShutdownWrap* req_wrap) override;
5353
int DoTryWrite(uv_buf_t** bufs, size_t* count) override;
54-
int DoWrite(WriteWrap* w,
54+
int DoWrite(std::unique_ptr<WriteWrap>& w,
5555
uv_buf_t* bufs,
5656
size_t count,
5757
uv_stream_t* send_handle) override;

‎src/tls_wrap.cc

+7-6
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,7 @@ bool TLSWrap::InvokeQueued(int status, const char* error_str) {
9191
return false;
9292

9393
if (current_write_ != nullptr) {
94-
WriteWrap* w = current_write_;
95-
current_write_ = nullptr;
94+
WriteWrap* w = current_write_.release();
9695
w->Done(status, error_str);
9796
}
9897

@@ -617,7 +616,7 @@ void TLSWrap::ClearError() {
617616

618617

619618
// Called by StreamBase::Write() to request async write of clear text into SSL.
620-
int TLSWrap::DoWrite(WriteWrap* w,
619+
int TLSWrap::DoWrite(std::unique_ptr<WriteWrap>& w,
621620
uv_buf_t* bufs,
622621
size_t count,
623622
uv_stream_t* send_handle) {
@@ -651,7 +650,7 @@ int TLSWrap::DoWrite(WriteWrap* w,
651650
if (BIO_pending(enc_out_) == 0) {
652651
Debug(this, "No pending encrypted output, writing to underlying stream");
653652
CHECK_NULL(current_empty_write_);
654-
current_empty_write_ = w;
653+
current_empty_write_ = w.get();
655654
StreamWriteResult res =
656655
underlying_stream()->Write(bufs, count, send_handle);
657656
if (!res.async) {
@@ -666,7 +665,7 @@ int TLSWrap::DoWrite(WriteWrap* w,
666665

667666
// Store the current write wrap
668667
CHECK_NULL(current_write_);
669-
current_write_ = w;
668+
current_write_ = std::move(w);
670669

671670
// Write encrypted data to underlying stream and call Done().
672671
if (length == 0) {
@@ -705,7 +704,7 @@ int TLSWrap::DoWrite(WriteWrap* w,
705704
// If we stopped writing because of an error, it's fatal, discard the data.
706705
if (!arg.IsEmpty()) {
707706
Debug(this, "Got SSL error (%d), returning UV_EPROTO", err);
708-
current_write_ = nullptr;
707+
current_write_.release();
709708
return UV_EPROTO;
710709
}
711710

@@ -718,6 +717,8 @@ int TLSWrap::DoWrite(WriteWrap* w,
718717
// Write any encrypted/handshake output that may be ready.
719718
EncOut();
720719

720+
w.reset(current_write_.get());
721+
721722
return 0;
722723
}
723724

‎src/tls_wrap.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class TLSWrap : public AsyncWrap,
6767
ShutdownWrap* CreateShutdownWrap(
6868
v8::Local<v8::Object> req_wrap_object) override;
6969
int DoShutdown(ShutdownWrap* req_wrap) override;
70-
int DoWrite(WriteWrap* w,
70+
int DoWrite(std::unique_ptr<WriteWrap>& w,
7171
uv_buf_t* bufs,
7272
size_t count,
7373
uv_stream_t* send_handle) override;
@@ -170,7 +170,7 @@ class TLSWrap : public AsyncWrap,
170170
// Waiting for ClearIn() to pass to SSL_write().
171171
std::vector<char> pending_cleartext_input_;
172172
size_t write_size_ = 0;
173-
WriteWrap* current_write_ = nullptr;
173+
std::unique_ptr<WriteWrap> current_write_ = nullptr;
174174
WriteWrap* current_empty_write_ = nullptr;
175175
bool write_callback_scheduled_ = false;
176176
bool started_ = false;

0 commit comments

Comments
 (0)
Please sign in to comment.