Fonts: cap the total a suitcase fork can make the scan copy; no fork look-up off macOS

References can share data, so a damaged fork could make the scan copy one
large resource up to 256 times: cap the total copied like the fork itself.
Off macOS no file has a fork, so the scan doesn't look at each font file twice.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
bflatasticandClaude Opus 5.5 committed 2026-10-09 21:40:42 +07:00
1 parent d35db792dc
commit be9a879e51
2 files changed
+10 -4

No files matched your search

+8 -4
View File
@@ -35,6 +35,7 @@ fn collect<'a>(fork: &'a [u8], fonts: &mut Vec<&'a [u8]>) -> Option<()> {
let types = be16(map, 24)?;
// Counts are stored less one, so a list of none is 0xFFFF.
let n_types = (be16(map, types)? + 1) & 0xFFFF;
let mut total = 0usize;
for t in 0..n_types.min(MAX_TYPES) {
let at = types + 2 + t * 8;
if map.get(at..at + 4)? != b"sfnt" {
@@ -44,11 +45,13 @@ fn collect<'a>(fork: &'a [u8], fonts: &mut Vec<&'a [u8]>) -> Option<()> {
// Each reference: its data's offset is the low three bytes of the word 4 bytes in.
let refs = types + be16(map, at + 6)?;
for r in 0..count {
if fonts.len() >= MAX_FONTS {
return Some(());
}
let start = data.checked_add(be32(map, refs + r * 12 + 4)? & 0x00FF_FFFF)?;
let len = be32(fork, start)?;
// References can share data: cap the total too, as every font is copied out.
total = total.checked_add(len)?;
if fonts.len() >= MAX_FONTS || total as u64 > MAX_FORK {
return Some(());
}
fonts.push(fork.get(start + 4..start.checked_add(4)?.checked_add(len)?)?);
}
}
@@ -65,7 +68,8 @@ pub(crate) fn read_fonts(path: &Path) -> Vec<Vec<u8>> {
/// Whether the file at `path` is a suitcase font: nothing in its data fork and something in its
/// resource fork.
pub(crate) fn is_suitcase(path: &Path) -> bool {
std::fs::metadata(path).is_ok_and(|m| m.is_file() && m.len() == 0) && fork_len(path) > 0
// Off macOS no file has a fork: don't look at every font file twice.
cfg!(target_os = "macos") && std::fs::metadata(path).is_ok_and(|m| m.is_file() && m.len() == 0) && fork_len(path) > 0
}
#[cfg(target_os = "macos")]
+2
View File
@@ -274,6 +274,8 @@ fn a_resource_fork_gives_up_its_font_files() {
let _ = crate::suitcase::sfnt_resources(&fork[..cut]);
}
assert!(crate::suitcase::sfnt_resources(&[0xFF; 600]).is_empty());
// A fork can't make the scan read more than so many fonts.
assert_eq!(crate::suitcase::sfnt_resources(&crate::suitcase::fork_of(&vec![b"font".to_vec(); 300])).len(), 256);
}
/// Office's fonts: a file with nothing in it but a resource fork holding the fonts, named