pub struct ScanBudget { /* private fields */ }Expand description
The work one salvage scan may spend judging candidates beyond their
fixed headers: bytes a verdict consumes (a long name, a variable part, an
extension chain, the bytes a header CRC covers), counted whether they come
from the source or from a search window. A legitimate archive consumes
each verdict’s bytes once, at most file_len in total, so the limit of
2 × file_len + 32 KiB never trips on real input; forged candidates
that would spend past it are refused unexamined and reported as a
verdict-bounded sighting (SightingKind::VerdictBounded), and the
scan goes on.
Why the slack is only 32 KiB (Rulings T4b-2 and T4b-5). A
legitimate scan’s verdict bytes all lie inside the file, so they total
at most file_len — and where a scanner pays for a second read too
(cpio pays for a name in the scan and again when the header before it
corroborates its size), at most 2 × file_len. The per-byte term covers
real input on its own, and the slack only rounds. It was 1 MiB, which
let a fuzz-scale input of a few KiB spend about 1 MiB: an 8 KiB file of
overlapping zip names read 536,640 bytes, past
stuffr_core::testing::check_scan_is_linear’s 8 × file_len + 64 KiB.
At 32 KiB the same file reads 65,536 bytes, half that bound. 16 KiB
was tried first and changed the outcome of 27 fuzz-corpus ZOO inputs,
whose overlapping type-2 records each read most of the file; at 32 KiB,
with ZOO charging each variable part once, all 27 keep their outcome.
Why a scan needs one (0.10.3). A scanner resumes one byte past every candidate it refuses, and past every candidate whose payload runs off the end of the file, so candidates can overlap. Where a candidate’s verdict needs a field the format lets run to 64 KiB — a zip name, a ZOO type-2 variable part, an LHA extension chain — packing such candidates every few dozen bytes made the scan read that field once per candidate: measured at 495x, 962x and 957x the input. No verdict can be reached by reading less, so the WORK is bounded instead, across the whole scan: tar’s extension-read budget (Ruling T3-1), generalised.
One per scan, shared by every pass the scan makes. A refused candidate is
reported through Sighting::verdict_bounded, so a genuine header
starved by forgeries elsewhere is named, never lost silently.
Implementations§
Source§impl ScanBudget
impl ScanBudget
Sourcepub const PER_INPUT_BYTE: u64 = 2
pub const PER_INPUT_BYTE: u64 = 2
Verdict bytes the scan may spend per byte of input.
Sourcepub const SLACK: u64
pub const SLACK: u64
Verdict bytes the scan may spend on top of Self::PER_INPUT_BYTE:
rounding only, and small enough that it never dominates a small
input’s check_scan_is_linear bound — see the type’s doc.
Sourcepub fn for_input(file_len: u64) -> Self
pub fn for_input(file_len: u64) -> Self
The budget for one scan of a file_len-byte input:
2 × file_len + 32 KiB.