Unsound implementation in `write_as_bytes`
shinmao opened this issue · comments
Rafael commented
The source of unsoundness
Hi, we are the researchers from Sun Security Lab. When we run our internal bug detectors through the crates.io, we found that your crate might include an unsound implementation. Please see the following code:
Lines 11 to 18 in 5f3ea2e
At line 13, callers could pass arbitrary types and cast it to
u8
type. However, slice::from_raw_parts
requires callers to guarantee the pointer point to consecutive initialized memory. If users pass struct
with padding bytes into the function, then it would cause to undefined behavior.
Reproduce the bug in rust-playground
Even though the io module was private, we consider that safe function should still avoid undefined behavior in any situation. Here is the same code to be reproduced in rust-playground1.
use std::io::{Write, Result};
use std::fs::File;
fn write_as_bytes<T, B: Write>(elements: &[T], buffer: &mut B) -> Result<usize> {
let size = elements.len() * ::std::mem::size_of::<T>();
let data = unsafe { ::std::slice::from_raw_parts(elements.as_ptr() as *const u8, size) };
buffer.write_all(data)?;
Ok(size)
}
#[repr(align(64))]
#[derive(Copy, Clone, Debug)]
struct Padding {
a: u8,
b: u16,
c: u8,
}
fn main() -> std::io::Result<()> {
let mut buffer = File::create("foo.txt")?;
let pd = Padding { a: 10, b: 11, c: 12 };
let pd_arr: [Padding; 1] = [pd; 1];
println!("{:?}", write_as_bytes(&pd_arr, &mut buffer));
Ok(())
}
to run with miri,
error: Undefined Behavior: reading memory at alloc940[0x0..0x40], but memory is uninitialized at [0x4..0x40], and this operation requires initialized memory
--> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/fd.rs:252:13
|
252 | / libc::write(
253 | | self.as_raw_fd(),
254 | | buf.as_ptr() as *const libc::c_void,
255 | | cmp::min(buf.len(), READ_LIMIT),
256 | | )
| |_____________^ reading memory at alloc940[0x0..0x40], but memory is uninitialized at [0x4..0x40], and this operation requires initialized memory
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior