Skip to main content

object_lang/
limits.rs

1//! Budgets that bound the work and memory a reader spends on untrusted input.
2
3/// Budgets for reading untrusted files.
4///
5/// Every reader checks its input against these before allocating for it. Section data,
6/// symbol records, and relocation records are also bounded by the input itself (a
7/// reader copies at most as many bytes of section data as the file holds, however its
8/// headers overlap), so the budgets that matter most are the ones on names: a hostile
9/// file can point many symbols at one long string, and only `max_name_bytes` stops that
10/// from multiplying.
11///
12/// The defaults sit far above what compilers produce and far below what would exhaust
13/// a machine. The struct is `#[non_exhaustive]`: start from [`Limits::default`] and
14/// change fields.
15///
16/// | Field | Default | Bounds |
17/// |---|---|---|
18/// | `max_sections` | 1,048,576 | section headers |
19/// | `max_symbols` | 16,777,216 | symbol table entries |
20/// | `max_relocations` | 67,108,864 | relocation records, all sections together |
21/// | `max_name_len` | 65,536 bytes | one section or symbol name |
22/// | `max_name_bytes` | 268,435,456 bytes (256 MiB) | all names together, as copied out |
23///
24/// # Examples
25///
26/// ```
27/// use object_lang::{Architecture, Limits, Object, ReadError, Section, SectionKind};
28///
29/// let mut obj = Object::relocatable(Architecture::X86_64);
30/// obj.add_section(Section::new(".text", SectionKind::Text));
31/// obj.add_section(Section::new(".data", SectionKind::Data));
32/// let bytes = object_lang::elf::write(&obj)?;
33///
34/// let mut limits = Limits::default();
35/// limits.max_sections = 3;
36/// assert_eq!(
37///     object_lang::elf::read_with_limits(&bytes, &limits),
38///     Err(ReadError::LimitExceeded { limit: "max_sections" }),
39/// );
40/// # Ok::<(), object_lang::WriteError>(())
41/// ```
42#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
43#[non_exhaustive]
44pub struct Limits {
45    /// The most section headers a file may have.
46    pub max_sections: u32,
47    /// The most entries a symbol table may have.
48    pub max_symbols: u32,
49    /// The most relocation records, over all sections.
50    pub max_relocations: u64,
51    /// The longest a single name may be, in bytes.
52    pub max_name_len: u32,
53    /// The most name bytes copied out of the file, over all names.
54    pub max_name_bytes: u64,
55}
56
57impl Limits {
58    /// The default budgets, as a constant.
59    ///
60    /// # Examples
61    ///
62    /// ```
63    /// use object_lang::Limits;
64    ///
65    /// assert_eq!(Limits::DEFAULT, Limits::default());
66    /// ```
67    pub const DEFAULT: Limits = Limits {
68        max_sections: 1 << 20,
69        max_symbols: 1 << 24,
70        max_relocations: 1 << 26,
71        max_name_len: 1 << 16,
72        max_name_bytes: 1 << 28,
73    };
74}
75
76impl Default for Limits {
77    fn default() -> Self {
78        Limits::DEFAULT
79    }
80}