Skip to content
This repository
Browse code

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.
  • Loading branch information...
commit b1ffbdc975d58b31e3b13749c29fdc07049ea1d9 1 parent 0844e23
Ben Noordhuis bnoordhuis authored

Showing 2 changed files with 30 additions and 15 deletions. Show diff stats Hide diff stats

  1. +27 7 src/node_stat_watcher.cc
  2. +3 8 src/node_stat_watcher.h
34 src/node_stat_watcher.cc
@@ -49,19 +49,39 @@ void StatWatcher::Initialize(Handle<Object> target) {
49 49 }
50 50
51 51
  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 +
52 72 void StatWatcher::Callback(uv_fs_poll_t* handle,
53 73 int status,
54 74 const uv_statbuf_t* prev,
55 75 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);
58 78 HandleScope scope;
59 79 Local<Value> argv[3];
60 80 argv[0] = BuildStatsObject(curr);
61 81 argv[1] = BuildStatsObject(prev);
62 82 argv[2] = Integer::New(status);
63 83 if (status == -1) {
64   - SetErrno(uv_last_error(wrap->watcher_.loop));
  84 + SetErrno(uv_last_error(wrap->watcher_->loop));
65 85 }
66 86 if (onchange_sym.IsEmpty()) {
67 87 onchange_sym = NODE_PSYMBOL("onchange");
@@ -88,8 +108,8 @@ Handle<Value> StatWatcher::Start(const Arguments& args) {
88 108 const bool persistent = args[1]->BooleanValue();
89 109 const uint32_t interval = args[2]->Uint32Value();
90 110
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);
93 113 wrap->Ref();
94 114
95 115 return Undefined();
@@ -109,8 +129,8 @@ Handle<Value> StatWatcher::Stop(const Arguments& args) {
109 129
110 130
111 131 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_);
114 134 Unref();
115 135 }
116 136
11 src/node_stat_watcher.h
@@ -34,13 +34,8 @@ class StatWatcher : ObjectWrap {
34 34 protected:
35 35 static v8::Persistent<v8::FunctionTemplate> constructor_template;
36 36
37   - StatWatcher() : ObjectWrap() {
38   - uv_fs_poll_init(uv_default_loop(), &watcher_);
39   - }
40   -
41   - ~StatWatcher() {
42   - Stop();
43   - }
  37 + StatWatcher();
  38 + virtual ~StatWatcher();
44 39
45 40 static v8::Handle<v8::Value> New(const v8::Arguments& args);
46 41 static v8::Handle<v8::Value> Start(const v8::Arguments& args);
@@ -53,7 +48,7 @@ class StatWatcher : ObjectWrap {
53 48 const uv_statbuf_t* curr);
54 49 void Stop();
55 50
56   - uv_fs_poll_t watcher_;
  51 + uv_fs_poll_t* watcher_;
57 52 };
58 53
59 54 } // namespace node

0 comments on commit b1ffbdc

Please sign in to comment.
Something went wrong with that request. Please try again.