Skip to main content

ScanBudget

Struct ScanBudget 

Source
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

Source

pub const PER_INPUT_BYTE: u64 = 2

Verdict bytes the scan may spend per byte of input.

Source

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.

Source

pub fn for_input(file_len: u64) -> Self

The budget for one scan of a file_len-byte input: 2 × file_len + 32 KiB.

Source

pub fn try_spend(&mut self, bytes: u64) -> bool

Charges bytes if they fit; false (charging nothing) if they would take the scan past its limit: the caller refuses the candidate without examining it.

Source

pub fn spent(&self) -> u64

Bytes charged so far.

Trait Implementations§

Source§

impl Debug for ScanBudget

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.