Skip to content

Unsound implementation of convert_primitive #174

@shinmao

Description

@shinmao

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.

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