Skip to content

Commit

Permalink
fix: handle integer overflows
Browse files Browse the repository at this point in the history
Passing huge values might lead to integer overflows during calculations.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
  • Loading branch information
stoeckmann committed Feb 26, 2024
1 parent 61a813b commit 5ac7750
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 7 deletions.
8 changes: 5 additions & 3 deletions src/spooled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ impl Write for SpooledTempFile {
// roll over to file if necessary
if matches! {
&self.inner, SpooledData::InMemory(cursor)
if cursor.position() as usize + buf.len() > self.max_size
if cursor.position().saturating_add(buf.len() as u64) > self.max_size as u64
} {
self.roll()?;
}
Expand All @@ -173,8 +173,10 @@ impl Write for SpooledTempFile {
if matches! {
&self.inner, SpooledData::InMemory(cursor)
// Borrowed from the rust standard library.
if cursor.position() as usize + bufs.iter()
.fold(0usize, |a, b| a.saturating_add(b.len())) > self.max_size
if bufs
.iter()
.fold(cursor.position(), |a, b| a.saturating_add(b.len() as u64))
> self.max_size as u64
} {
self.roll()?;
}
Expand Down
13 changes: 9 additions & 4 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,20 @@ use std::{io, iter::repeat_with};

use crate::error::IoResultExt;

fn tmpname(prefix: &OsStr, suffix: &OsStr, rand_len: usize) -> OsString {
let mut buf = OsString::with_capacity(prefix.len() + suffix.len() + rand_len);
fn tmpname(prefix: &OsStr, suffix: &OsStr, rand_len: usize) -> io::Result<OsString> {
let capacity = prefix
.len()
.checked_add(suffix.len())
.and_then(|value| value.checked_add(rand_len))
.ok_or(io::Error::new(io::ErrorKind::InvalidInput, "name too long"))?;
let mut buf = OsString::with_capacity(capacity);
buf.push(prefix);
let mut char_buf = [0u8; 4];
for c in repeat_with(fastrand::alphanumeric).take(rand_len) {
buf.push(c.encode_utf8(&mut char_buf));
}
buf.push(suffix);
buf
Ok(buf)
}

pub fn create_helper<R>(
Expand All @@ -30,7 +35,7 @@ pub fn create_helper<R>(
};

for _ in 0..num_retries {
let path = base.join(tmpname(prefix, suffix, random_len));
let path = base.join(tmpname(prefix, suffix, random_len)?);
return match f(path, permissions) {
Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists && num_retries > 1 => continue,
// AddrInUse can happen if we're creating a UNIX domain socket and
Expand Down
10 changes: 10 additions & 0 deletions tests/namedtempfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@ fn test_customnamed() {
assert_eq!(name.len(), 18);
}

#[test]
fn test_customnamed_too_long() {
assert!(Builder::new()
.prefix("tmp")
.suffix(&".rs")
.rand_bytes(usize::MAX)
.tempfile()
.is_err());
}

#[test]
fn test_append() {
let mut tmpfile = Builder::new().append(true).tempfile().unwrap();
Expand Down
7 changes: 7 additions & 0 deletions tests/spooled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,13 @@ fn test_set_len_rollover() {
assert_eq!(buf.as_slice(), b"abcde\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
}

#[test]
fn test_write_overflow() {
let mut t = spooled_tempfile(10);
t.seek(SeekFrom::Start(u64::MAX)).unwrap();
assert!(t.write(b"abcde").is_err());
}

#[cfg(target_pointer_width = "32")]
#[test]
fn test_set_len_truncation() {
Expand Down

0 comments on commit 5ac7750

Please sign in to comment.