Skip to content

Commit b1ffbdc

Browse files
committed
fs: fix use after free in stat watcher
The uv_fs_poll_t handle was stopped but not closed, leaving libuv's internal handle queue in a corrupted state.
1 parent 0844e23 commit b1ffbdc

File tree

2 files changed

+30
-15
lines changed

2 files changed

+30
-15
lines changed

src/node_stat_watcher.cc

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,39 @@ void StatWatcher::Initialize(Handle<Object> target) {
4949
}
5050

5151

52+
static void Delete(uv_handle_t* handle) {
53+
delete reinterpret_cast<uv_fs_poll_t*>(handle);
54+
}
55+
56+
57+
StatWatcher::StatWatcher()
58+
: ObjectWrap()
59+
, watcher_(new uv_fs_poll_t)
60+
{
61+
uv_fs_poll_init(uv_default_loop(), watcher_);
62+
watcher_->data = static_cast<void*>(this);
63+
}
64+
65+
66+
StatWatcher::~StatWatcher() {
67+
Stop();
68+
uv_close(reinterpret_cast<uv_handle_t*>(watcher_), Delete);
69+
}
70+
71+
5272
void StatWatcher::Callback(uv_fs_poll_t* handle,
5373
int status,
5474
const uv_statbuf_t* prev,
5575
const uv_statbuf_t* curr) {
56-
StatWatcher* wrap = container_of(handle, StatWatcher, watcher_);
57-
assert(handle == &wrap->watcher_);
76+
StatWatcher* wrap = static_cast<StatWatcher*>(handle->data);
77+
assert(wrap->watcher_ == handle);
5878
HandleScope scope;
5979
Local<Value> argv[3];
6080
argv[0] = BuildStatsObject(curr);
6181
argv[1] = BuildStatsObject(prev);
6282
argv[2] = Integer::New(status);
6383
if (status == -1) {
64-
SetErrno(uv_last_error(wrap->watcher_.loop));
84+
SetErrno(uv_last_error(wrap->watcher_->loop));
6585
}
6686
if (onchange_sym.IsEmpty()) {
6787
onchange_sym = NODE_PSYMBOL("onchange");
@@ -88,8 +108,8 @@ Handle<Value> StatWatcher::Start(const Arguments& args) {
88108
const bool persistent = args[1]->BooleanValue();
89109
const uint32_t interval = args[2]->Uint32Value();
90110

91-
if (!persistent) uv_unref(reinterpret_cast<uv_handle_t*>(&wrap->watcher_));
92-
uv_fs_poll_start(&wrap->watcher_, Callback, *path, interval);
111+
if (!persistent) uv_unref(reinterpret_cast<uv_handle_t*>(wrap->watcher_));
112+
uv_fs_poll_start(wrap->watcher_, Callback, *path, interval);
93113
wrap->Ref();
94114

95115
return Undefined();
@@ -109,8 +129,8 @@ Handle<Value> StatWatcher::Stop(const Arguments& args) {
109129

110130

111131
void StatWatcher::Stop () {
112-
if (!uv_is_active(reinterpret_cast<uv_handle_t*>(&watcher_))) return;
113-
uv_fs_poll_stop(&watcher_);
132+
if (!uv_is_active(reinterpret_cast<uv_handle_t*>(watcher_))) return;
133+
uv_fs_poll_stop(watcher_);
114134
Unref();
115135
}
116136

src/node_stat_watcher.h

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,8 @@ class StatWatcher : ObjectWrap {
3434
protected:
3535
static v8::Persistent<v8::FunctionTemplate> constructor_template;
3636

37-
StatWatcher() : ObjectWrap() {
38-
uv_fs_poll_init(uv_default_loop(), &watcher_);
39-
}
40-
41-
~StatWatcher() {
42-
Stop();
43-
}
37+
StatWatcher();
38+
virtual ~StatWatcher();
4439

4540
static v8::Handle<v8::Value> New(const v8::Arguments& args);
4641
static v8::Handle<v8::Value> Start(const v8::Arguments& args);
@@ -53,7 +48,7 @@ class StatWatcher : ObjectWrap {
5348
const uv_statbuf_t* curr);
5449
void Stop();
5550

56-
uv_fs_poll_t watcher_;
51+
uv_fs_poll_t* watcher_;
5752
};
5853

5954
} // namespace node

0 commit comments

Comments
 (0)