Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unsound implementation of convert_primitive #174

Open
shinmao opened this issue Aug 18, 2023 · 1 comment
Open

Unsound implementation of convert_primitive #174

shinmao opened this issue Aug 18, 2023 · 1 comment

Comments

@shinmao
Copy link

shinmao commented Aug 18, 2023

The source of unsoundness

Hi, we are the researchers from Sun Security Lab. With our bug detector, we found that convert_primitive might have an unsound implementation.

fn convert_primitive<T>(buf: &[u8]) -> T
where
T: Copy,
{
unsafe { from_raw_parts(buf.as_ptr() as *const T, 1)[0] }
}

At line 285, buf is aligned to 1 byte, and it can be cast to other types with stricter alignment requirement. If misaligned pointer is passed to from_raw_parts, it could cause to undefined behavior in this safe function.

To reproduce the bug

use odbc::*;

fn main() {
    let a: [u8; 4] = [12; 4];
    let b = u32::convert(&a);
    println!("{:?}", b);
}

In this case, convert will call from_raw_parts(x.as_ptr() as *const u32, 1) which has a misaligned pointer.

fn main() {
    let a: [u8; 2] = [12; 2];
    let b = f64::convert(&a);
    println!("{:?}", b);
}

run with miri

error: Undefined Behavior: dereferencing pointer failed: alloc1303 has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds
   --> /${HOME}/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/raw.rs:100:9
    |
100 |         &*ptr::slice_from_raw_parts(data, len)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: alloc1303 has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds

In this case, the length of the buffer is only 2 bytes. However, from_raw_parts expects 8 bytes to be read.

@shinmao
Copy link
Author

shinmao commented Sep 6, 2023

[UPDATED]
There is another unsound implementation in convert:

fn convert(buffer: &'a [u8]) -> Self {
let buffer = unsafe { from_raw_parts(buffer.as_ptr() as *const u16, buffer.len() / 2) };
buffer.to_vec()
}

which also create a misaligned pointer and passed to from_raw_parts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant