Skip to content

Potential Undefined Behavior in Buffer struct found #4

@lewismosciski

Description

@lewismosciski

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.

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.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions