fix(engine): check the opened file, not the looked-up path, before reading it

read_capped checked the path's metadata (type and size) and then opened
the path again, so an entry swapped between the two steps was read without
those checks. The opened handle's metadata is checked as well; the path
check stays, so a pipe is still refused before it is opened.
This commit is contained in:
Dylan M. Taylor
2026-11-03 04:22:36 +00:00
parent 02c38a6d95
commit 970a3e6745
@@ -277,6 +277,14 @@ pub fn read_capped(path: impl AsRef<Path>, max: u64) -> Result<Vec<u8>> {
return Err(refuse(format!("is {}, more than the {} allowed here", size(meta.len()), size(max))));
}
let f = std::fs::File::open(p).map_err(io(path))?;
// What was opened, not what was looked at: the path could have been swapped in between.
let meta = f.metadata().map_err(io(path))?;
if !meta.is_file() {
return Err(refuse("isn't a regular file (a device or a pipe?), so it isn't read".into()));
}
if meta.len() > max {
return Err(refuse(format!("is {}, more than the {} allowed here", size(meta.len()), size(max))));
}
let mut bytes = Vec::with_capacity(usize::try_from(meta.len()).unwrap_or(0));
f.take(max.saturating_add(1)).read_to_end(&mut bytes).map_err(io(path))?;
// It grew after it was looked at.