From 8a2f9cae213d38b31e9372b9d8a7fee1263f1363 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 22 Apr 2013 19:20:31 -0700 Subject: [PATCH] core::rt: Fix a use after free in uv 'write' --- src/libcore/rt/uv/mod.rs | 6 ++++-- src/libcore/rt/uv/net.rs | 16 ++++++++++------ src/libcore/rt/uvio.rs | 5 ++++- src/libcore/rt/uvll.rs | 6 +++--- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/libcore/rt/uv/mod.rs b/src/libcore/rt/uv/mod.rs index 32757d6376e..4c4b2e03d3d 100644 --- a/src/libcore/rt/uv/mod.rs +++ b/src/libcore/rt/uv/mod.rs @@ -301,7 +301,8 @@ struct WatcherData { write_cb: Option, connect_cb: Option, close_cb: Option, - alloc_cb: Option + alloc_cb: Option, + buf: Option } pub fn install_watcher_data>(watcher: &mut W) { @@ -311,7 +312,8 @@ pub fn install_watcher_data>(watcher: &mut W) { write_cb: None, connect_cb: None, close_cb: None, - alloc_cb: None + alloc_cb: None, + buf: None }; let data = transmute::<~WatcherData, *c_void>(data); uvll::set_data_for_uv_handle(watcher.native_handle(), data); diff --git a/src/libcore/rt/uv/net.rs b/src/libcore/rt/uv/net.rs index 860c988b9c9..04b9008b067 100644 --- a/src/libcore/rt/uv/net.rs +++ b/src/libcore/rt/uv/net.rs @@ -107,21 +107,25 @@ pub impl StreamWatcher { let req = WriteRequest::new(); let buf = vec_to_uv_buf(msg); - // XXX: Allocation - let bufs = ~[buf]; + assert!(data.buf.is_none()); + data.buf = Some(buf); + let bufs = [buf]; unsafe { assert!(0 == uvll::write(req.native_handle(), self.native_handle(), - &bufs, write_cb)); + bufs, write_cb)); } - // XXX: Freeing immediately after write. Is this ok? - let _v = vec_from_uv_buf(buf); extern fn write_cb(req: *uvll::uv_write_t, status: c_int) { let write_request: WriteRequest = NativeHandle::from_native_handle(req); let mut stream_watcher = write_request.stream(); write_request.delete(); - let cb = get_watcher_data(&mut stream_watcher).write_cb.swap_unwrap(); + let cb = { + let data = get_watcher_data(&mut stream_watcher); + let _vec = vec_from_uv_buf(data.buf.swap_unwrap()); + let cb = data.write_cb.swap_unwrap(); + cb + }; let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status); cb(stream_watcher, status); } diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs index 2e9d0afa52f..e7b2880b74b 100644 --- a/src/libcore/rt/uvio.rs +++ b/src/libcore/rt/uvio.rs @@ -445,7 +445,7 @@ fn test_read_read_read() { let io = local_sched::unsafe_borrow_io(); let mut listener = io.bind(addr).unwrap(); let mut stream = listener.listen().unwrap(); - let mut buf = [0, .. 2048]; + let mut buf = [1, .. 2048]; let mut total_bytes_written = 0; while total_bytes_written < MAX { stream.write(buf); @@ -465,6 +465,9 @@ fn test_read_read_read() { let nread = stream.read(buf).unwrap(); rtdebug!("read %u bytes", nread as uint); total_bytes_read += nread; + for uint::range(0, nread) |i| { + assert!(buf[i] == 1); + } } rtdebug!("read %u bytes total", total_bytes_read as uint); stream.close(); diff --git a/src/libcore/rt/uvll.rs b/src/libcore/rt/uvll.rs index 640a69743ba..0f75ebb6090 100644 --- a/src/libcore/rt/uvll.rs +++ b/src/libcore/rt/uvll.rs @@ -219,9 +219,9 @@ pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int { return rust_uv_accept(server as *c_void, client as *c_void); } -pub unsafe fn write(req: *uv_write_t, stream: *T, buf_in: *~[uv_buf_t], cb: *u8) -> c_int { - let buf_ptr = vec::raw::to_ptr(*buf_in); - let buf_cnt = vec::len(*buf_in) as i32; +pub unsafe fn write(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int { + let buf_ptr = vec::raw::to_ptr(buf_in); + let buf_cnt = vec::len(buf_in) as i32; return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb); } pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: *u8, on_read: *u8) -> c_int {