Rollup merge of #80895 - sfackler:read-to-end-ub, r=m-ou-se
Fix handling of malicious Readers in read_to_end
A malicious `Read` impl could return overly large values from `read`, which would result in the guard's drop impl setting the buffer's length to greater than its capacity! ~~To fix this, the drop impl now uses the safe `truncate` function instead of `set_len` which ensures that this will not happen. The result of calling the function will be nonsensical, but that's fine given the contract violation of the `Read` impl.~~
~~The `Guard` type is also used by `append_to_string` which does not pass untrusted values into the length field, so I've copied the guard type into each function and only modified the one used by `read_to_end`. We could just keep a single one and modify it, but it seems a bit cleaner to keep the guard code close to the functions and related specifically to them.~~
To fix this, we now assert that the returned length is not larger than the buffer passed to the method.
For reference, this bug has been present for ~2.5 years since 1.20: ecbb896b9e
.
Closes #80894.
This commit is contained in:
commit
ce48709405
@ -366,7 +366,6 @@ where
|
||||
{
|
||||
let start_len = buf.len();
|
||||
let mut g = Guard { len: buf.len(), buf };
|
||||
let ret;
|
||||
loop {
|
||||
if g.len == g.buf.len() {
|
||||
unsafe {
|
||||
@ -385,21 +384,20 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
match r.read(&mut g.buf[g.len..]) {
|
||||
Ok(0) => {
|
||||
ret = Ok(g.len - start_len);
|
||||
break;
|
||||
let buf = &mut g.buf[g.len..];
|
||||
match r.read(buf) {
|
||||
Ok(0) => return Ok(g.len - start_len),
|
||||
Ok(n) => {
|
||||
// We can't allow bogus values from read. If it is too large, the returned vec could have its length
|
||||
// set past its capacity, or if it overflows the vec could be shortened which could create an invalid
|
||||
// string if this is called via read_to_string.
|
||||
assert!(n <= buf.len());
|
||||
g.len += n;
|
||||
}
|
||||
Ok(n) => g.len += n,
|
||||
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
|
||||
Err(e) => {
|
||||
ret = Err(e);
|
||||
break;
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
pub(crate) fn default_read_vectored<F>(read: F, bufs: &mut [IoSliceMut<'_>]) -> Result<usize>
|
||||
|
Loading…
Reference in New Issue
Block a user