-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Hello,
We are currently developing a static analysis tool for Rust, and during our testing, we analyzed fcplug. We believe we have identified two instances of Undefined Behavior in the Buffer struct, which we were able to confirm using miri.
Double Free due to Buffer being Copy
The Buffer struct derives #[derive(Copy)]. However, Buffer::from_vec takes ownership of a Vec's memory. Because the Buffer is Copy, this unique ownership can be duplicated, leading to a double-free when the public free_buffer function is called on both copies.
Lines 25 to 27 in 04fd56a
| pub extern "C" fn free_buffer(buf: Buffer) { | |
| unsafe { buf.mem_free() } | |
| } |
POC:
fn main() {
let v = vec![1, 2, 3, 4, 5];
let b1 = Buffer::from_vec(v);
let b2 = b1;
println!("b1 ptr: {:?}", b1.ptr);
println!("b2 ptr: {:?}", b2.ptr);
free_buffer(b1);
free_buffer(b2);
}miri output:
b1 ptr: 0x20adf
b2 ptr: 0x20adf
error: Undefined Behavior: pointer not dereferenceable: alloc210 has been freed, so this pointer is dangling
--> /home/ccuu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:804:1
|
804 | pub unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
Use-After-Free due to unsound from_vec_mut
The Buffer::from_vec_mut function takes a &mut Vec but returns a Buffer that is not tied to the lifetime of the original Vec. This allows a Buffer to be created that outlives the Vec it borrows from. When the Vec is dropped, the Buffer is left holding a dangling pointer.
Lines 153 to 164 in 04fd56a
| pub fn from_vec_mut(v: &mut Vec<u8>) -> Self { | |
| if v.is_empty() { | |
| Self::null() | |
| } else { | |
| v.shrink_to_fit(); | |
| Self { | |
| len: v.len(), | |
| cap: v.capacity(), | |
| ptr: v.as_mut_ptr(), | |
| } | |
| } | |
| } |
POC:
fn main() {
let b: Buffer;
{
let mut v = vec![1, 2, 3, 4, 5];
b = Buffer::from_vec_mut(&mut v);
}
let _data = b.read();
}miri output:
error: Undefined Behavior: pointer not dereferenceable: alloc203 has been freed, so this pointer is dangling
--> /home/ccuu/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/fcplug-0.4.5/src/lib.rs:108:27
|
108 | unsafe { Some(std::slice::from_raw_parts(self.ptr, self.len)) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior