Unsound `BufWriter` copy_to specialization with the unstable `read_buf` feature
paolobarbolini opened this issue · 4 comments
Code
#![feature(read_buf)]
use std::io::{self, BufWriter, Read, ReadBuf};
struct BadReader;
impl Read for BadReader {
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
unreachable!()
}
fn read_buf(&mut self, read_buf: &mut ReadBuf<'_>) -> io::Result<()> {
let vec = vec![0; 2048];
let mut buf = ReadBuf::new(vec.leak());
buf.append(&[123; 2048]);
*read_buf = buf;
Ok(())
}
}
fn main() {
let mut buf = Vec::new();
{
let mut buf_ = BufWriter::with_capacity(1024, &mut buf);
let mut input = BadReader.take(4096);
io::copy(&mut input, &mut buf_).unwrap();
}
// read the memory to trigger miri to realize that the memory is uninitialized
println!("buf[0]: {}", buf[0]);
}
Playground link: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=483f0b4f2f881519f459c3cd273a50f4 (run miri on it)
Unsound implementation
rust/library/std/src/io/copy.rs
Lines 80 to 122 in 92ed874
(we're basically tricking it into calling set_len
with a length higher than what has actually been filled)
Documentation
Should this be considered a possible footgun when implementing something that calls read_buf
? Should it be documented?
This was already mention in the PR that added ReadBuf #81156 (comment)
cc @drmeepster @joshtriplett
There's two possible solutions I see here.
- The easiest thing to do to fix this is just check if the
ReadBuf
points to the same buffer as before and return an error if it doesn't. This doesn't seem very "rusty" to me though, relying on a runtime check. - The other solution is to have a
ReadBufRef
type passed by value toread_buf
instead of&mut ReadBuf
. This solves the issue in general at compile time, but could make this api a lot more complicated to use.
I think another example of unsound code in std for a similar reason is in the read_buf
implementation for Take
.
I think another example of unsound code in std for a similar reason is in the
read_buf
implementation forTake
.
Yes it seems like a similar attack could be done against it
rust/library/std/src/io/mod.rs
Lines 2584 to 2601 in 18f32b7