Skip to content

Commit 8a2f9ca

Browse files
committed
core::rt: Fix a use after free in uv 'write'
1 parent a292d51 commit 8a2f9ca

File tree

4 files changed

+21
-12
lines changed

4 files changed

+21
-12
lines changed

src/libcore/rt/uv/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,8 @@ struct WatcherData {
301301
write_cb: Option<ConnectionCallback>,
302302
connect_cb: Option<ConnectionCallback>,
303303
close_cb: Option<NullCallback>,
304-
alloc_cb: Option<AllocCallback>
304+
alloc_cb: Option<AllocCallback>,
305+
buf: Option<Buf>
305306
}
306307
307308
pub fn install_watcher_data<H, W: Watcher + NativeHandle<*H>>(watcher: &mut W) {
@@ -311,7 +312,8 @@ pub fn install_watcher_data<H, W: Watcher + NativeHandle<*H>>(watcher: &mut W) {
311312
write_cb: None,
312313
connect_cb: None,
313314
close_cb: None,
314-
alloc_cb: None
315+
alloc_cb: None,
316+
buf: None
315317
};
316318
let data = transmute::<~WatcherData, *c_void>(data);
317319
uvll::set_data_for_uv_handle(watcher.native_handle(), data);

src/libcore/rt/uv/net.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,21 +107,25 @@ pub impl StreamWatcher {
107107

108108
let req = WriteRequest::new();
109109
let buf = vec_to_uv_buf(msg);
110-
// XXX: Allocation
111-
let bufs = ~[buf];
110+
assert!(data.buf.is_none());
111+
data.buf = Some(buf);
112+
let bufs = [buf];
112113
unsafe {
113114
assert!(0 == uvll::write(req.native_handle(),
114115
self.native_handle(),
115-
&bufs, write_cb));
116+
bufs, write_cb));
116117
}
117-
// XXX: Freeing immediately after write. Is this ok?
118-
let _v = vec_from_uv_buf(buf);
119118

120119
extern fn write_cb(req: *uvll::uv_write_t, status: c_int) {
121120
let write_request: WriteRequest = NativeHandle::from_native_handle(req);
122121
let mut stream_watcher = write_request.stream();
123122
write_request.delete();
124-
let cb = get_watcher_data(&mut stream_watcher).write_cb.swap_unwrap();
123+
let cb = {
124+
let data = get_watcher_data(&mut stream_watcher);
125+
let _vec = vec_from_uv_buf(data.buf.swap_unwrap());
126+
let cb = data.write_cb.swap_unwrap();
127+
cb
128+
};
125129
let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status);
126130
cb(stream_watcher, status);
127131
}

src/libcore/rt/uvio.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ fn test_read_read_read() {
445445
let io = local_sched::unsafe_borrow_io();
446446
let mut listener = io.bind(addr).unwrap();
447447
let mut stream = listener.listen().unwrap();
448-
let mut buf = [0, .. 2048];
448+
let mut buf = [1, .. 2048];
449449
let mut total_bytes_written = 0;
450450
while total_bytes_written < MAX {
451451
stream.write(buf);
@@ -465,6 +465,9 @@ fn test_read_read_read() {
465465
let nread = stream.read(buf).unwrap();
466466
rtdebug!("read %u bytes", nread as uint);
467467
total_bytes_read += nread;
468+
for uint::range(0, nread) |i| {
469+
assert!(buf[i] == 1);
470+
}
468471
}
469472
rtdebug!("read %u bytes total", total_bytes_read as uint);
470473
stream.close();

src/libcore/rt/uvll.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,9 @@ pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int {
219219
return rust_uv_accept(server as *c_void, client as *c_void);
220220
}
221221

222-
pub unsafe fn write<T>(req: *uv_write_t, stream: *T, buf_in: *~[uv_buf_t], cb: *u8) -> c_int {
223-
let buf_ptr = vec::raw::to_ptr(*buf_in);
224-
let buf_cnt = vec::len(*buf_in) as i32;
222+
pub unsafe fn write<T>(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int {
223+
let buf_ptr = vec::raw::to_ptr(buf_in);
224+
let buf_cnt = vec::len(buf_in) as i32;
225225
return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb);
226226
}
227227
pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: *u8, on_read: *u8) -> c_int {

0 commit comments

Comments
 (0)