Skip to content

Commit 5ac7750

Browse files
committed
fix: handle integer overflows
Passing huge values might lead to integer overflows during calculations. Signed-off-by: Tobias Stoeckmann <[email protected]>
1 parent 61a813b commit 5ac7750

File tree

4 files changed

+31
-7
lines changed

4 files changed

+31
-7
lines changed

src/spooled.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ impl Write for SpooledTempFile {
157157
// roll over to file if necessary
158158
if matches! {
159159
&self.inner, SpooledData::InMemory(cursor)
160-
if cursor.position() as usize + buf.len() > self.max_size
160+
if cursor.position().saturating_add(buf.len() as u64) > self.max_size as u64
161161
} {
162162
self.roll()?;
163163
}
@@ -173,8 +173,10 @@ impl Write for SpooledTempFile {
173173
if matches! {
174174
&self.inner, SpooledData::InMemory(cursor)
175175
// Borrowed from the rust standard library.
176-
if cursor.position() as usize + bufs.iter()
177-
.fold(0usize, |a, b| a.saturating_add(b.len())) > self.max_size
176+
if bufs
177+
.iter()
178+
.fold(cursor.position(), |a, b| a.saturating_add(b.len() as u64))
179+
> self.max_size as u64
178180
} {
179181
self.roll()?;
180182
}

src/util.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@ use std::{io, iter::repeat_with};
44

55
use crate::error::IoResultExt;
66

7-
fn tmpname(prefix: &OsStr, suffix: &OsStr, rand_len: usize) -> OsString {
8-
let mut buf = OsString::with_capacity(prefix.len() + suffix.len() + rand_len);
7+
fn tmpname(prefix: &OsStr, suffix: &OsStr, rand_len: usize) -> io::Result<OsString> {
8+
let capacity = prefix
9+
.len()
10+
.checked_add(suffix.len())
11+
.and_then(|value| value.checked_add(rand_len))
12+
.ok_or(io::Error::new(io::ErrorKind::InvalidInput, "name too long"))?;
13+
let mut buf = OsString::with_capacity(capacity);
914
buf.push(prefix);
1015
let mut char_buf = [0u8; 4];
1116
for c in repeat_with(fastrand::alphanumeric).take(rand_len) {
1217
buf.push(c.encode_utf8(&mut char_buf));
1318
}
1419
buf.push(suffix);
15-
buf
20+
Ok(buf)
1621
}
1722

1823
pub fn create_helper<R>(
@@ -30,7 +35,7 @@ pub fn create_helper<R>(
3035
};
3136

3237
for _ in 0..num_retries {
33-
let path = base.join(tmpname(prefix, suffix, random_len));
38+
let path = base.join(tmpname(prefix, suffix, random_len)?);
3439
return match f(path, permissions) {
3540
Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists && num_retries > 1 => continue,
3641
// AddrInUse can happen if we're creating a UNIX domain socket and

tests/namedtempfile.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,16 @@ fn test_customnamed() {
104104
assert_eq!(name.len(), 18);
105105
}
106106

107+
#[test]
108+
fn test_customnamed_too_long() {
109+
assert!(Builder::new()
110+
.prefix("tmp")
111+
.suffix(&".rs")
112+
.rand_bytes(usize::MAX)
113+
.tempfile()
114+
.is_err());
115+
}
116+
107117
#[test]
108118
fn test_append() {
109119
let mut tmpfile = Builder::new().append(true).tempfile().unwrap();

tests/spooled.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,13 @@ fn test_set_len_rollover() {
306306
assert_eq!(buf.as_slice(), b"abcde\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
307307
}
308308

309+
#[test]
310+
fn test_write_overflow() {
311+
let mut t = spooled_tempfile(10);
312+
t.seek(SeekFrom::Start(u64::MAX)).unwrap();
313+
assert!(t.write(b"abcde").is_err());
314+
}
315+
309316
#[cfg(target_pointer_width = "32")]
310317
#[test]
311318
fn test_set_len_truncation() {

0 commit comments

Comments
 (0)