vole_document/limits.rs
1//! Centralized resource bounds.
2//!
3//! Every decode and encode path takes a [`Limits`]. Untrusted descriptors must
4//! be rejected *before* catastrophic work is performed, so all arithmetic on
5//! declared lengths and offsets is checked against these bounds and uses
6//! checked integer operations.
7
8/// Hard upper bounds applied while parsing and materializing a descriptor.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub struct Limits {
11 /// Maximum accepted source/descriptor input size.
12 pub max_input_bytes: u64,
13 /// Maximum reconstructed output size for a single materialization.
14 pub max_output_bytes: u64,
15 /// Admission cap on the output of a single `DEFLATE_REPLAY`.
16 ///
17 /// This is a **VOLE replay-profile policy limit**, not an RFC 1951 maximum.
18 /// RFC 1951 permits arbitrarily many empty non-final stored blocks, so it
19 /// gives no finite `f(decompressed_size)` bound on `compressed_size`; a
20 /// bitstream that inflates to zero bytes may be arbitrarily large. VOLE
21 /// therefore declines to replay a descriptor whose declared output exceeds
22 /// this policy cap (see ADR-0016).
23 pub max_replay_bytes: u64,
24 /// Maximum length of a single record payload.
25 pub max_record_len: u32,
26 /// Maximum number of records in a container.
27 pub max_record_count: u32,
28 /// Maximum number of distinct byte objects (`OBJECT` records).
29 pub max_object_count: u32,
30 /// Maximum number of DRA instructions in a reconstruction graph.
31 pub max_graph_ops: u32,
32 /// Maximum repeat count for a single `REPEAT_LAST` instruction.
33 pub max_repeat_count: u64,
34 /// Maximum number of symbols in a single entropy channel.
35 pub max_channel_symbols: u64,
36 /// Maximum number of distinct entropy models (`MODEL` records).
37 pub max_model_count: u32,
38 /// Maximum number of entropy channels (`ENTROPY_CHANNEL` records).
39 pub max_channel_count: u32,
40 /// Maximum encoded size of a single entropy model payload.
41 pub max_entropy_model_bytes: u32,
42 /// Maximum number of lexical spans produced for a PDF input.
43 pub max_pdf_spans: u32,
44 /// Maximum number of selectors in a single `OBSERVATION_INDEX` record.
45 ///
46 /// Bounds the admissions of the optional partial-decode index (Phase 7.3)
47 /// before allocation: an index whose selector table would exceed this is
48 /// rejected at parse and declined by the index builder. It mirrors the
49 /// object/graph scale so the table cannot dwarf the document it describes.
50 pub max_index_selectors: u32,
51 /// Maximum accepted size of an optional `DIRECTORY` record payload.
52 ///
53 /// Bounds the seek directory (Phase 8) before allocation: a directory larger
54 /// than this is declined at decode rather than trusted. A directory is roughly
55 /// `13 * record_count` bytes, so this also caps the record count a directory
56 /// can describe.
57 pub max_directory_bytes: u32,
58}
59
60impl Limits {
61 /// The default archival limits: generous, but always finite.
62 pub const DEFAULT: Limits = Limits {
63 max_input_bytes: 1 << 40, // 1 TiB
64 max_output_bytes: 1 << 40, // 1 TiB
65 max_replay_bytes: 1 << 34, // 16 GiB
66 max_record_len: 1 << 31, // 2 GiB
67 max_record_count: 1 << 20, // ~1M records
68 max_object_count: 1 << 20,
69 max_graph_ops: 1 << 20,
70 max_repeat_count: 1 << 32,
71 max_channel_symbols: 1 << 40,
72 max_model_count: 1 << 16,
73 max_channel_count: 1 << 16,
74 max_entropy_model_bytes: 4096,
75 max_pdf_spans: 1 << 26,
76 max_index_selectors: 1 << 20,
77 max_directory_bytes: 1 << 20,
78 };
79
80 /// Tight limits for hostile-input testing and fuzzing.
81 pub const STRICT: Limits = Limits {
82 max_input_bytes: 1 << 26, // 64 MiB
83 max_output_bytes: 1 << 26, // 64 MiB
84 max_replay_bytes: 1 << 26, // 64 MiB
85 max_record_len: 1 << 24, // 16 MiB
86 max_record_count: 1 << 16, // 65536
87 max_object_count: 1 << 16,
88 max_graph_ops: 1 << 16,
89 max_repeat_count: 1 << 24,
90 max_channel_symbols: 1 << 26,
91 max_model_count: 1 << 12,
92 max_channel_count: 1 << 12,
93 max_entropy_model_bytes: 4096,
94 max_pdf_spans: 1 << 16,
95 max_index_selectors: 1 << 16,
96 max_directory_bytes: 1 << 18,
97 };
98}
99
100impl Default for Limits {
101 fn default() -> Self {
102 Limits::DEFAULT
103 }
104}