|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Unified decompression-limits policy: one bound set for every decoder. More...
Go to the source code of this file.
Data Structures | |
| struct | ra8_decomp_limits_t |
| One decompression policy: the five resource bounds decoders enforce. More... | |
| struct | ra8_decomp_budget_t |
| Running consumption tracker charged by a decoder against its policy. More... | |
Typedefs | |
| typedef size_t(* | ra8_decomp_read_fn) (void *ctx, uint64_t offset, void *buf, size_t len) |
| Positioned reader used by bounded container preflights. | |
Enumerations | |
| enum | ra8_decomp_defaults_t : uint64_t { k_ra8_decomp_def_output_bytes = 64ULL * 1024ULL * 1024ULL , k_ra8_decomp_def_max_ratio = 1024U , k_ra8_decomp_def_ratio_grace = 64U * 1024U , k_ra8_decomp_def_max_entries = 4096U , k_ra8_decomp_def_max_iters = 1048576U , k_ra8_decomp_def_max_depth = 2U } |
| Owner-approved default values for ra8_decomp_limits_t. More... | |
Functions | |
| ra8_decomp_limits_t | ra8_decomp_limits_default (void) |
| The owner-approved default decompression policy. | |
| ra8_err_t | ra8_decomp_budget_init (ra8_decomp_budget_t *b, const ra8_decomp_limits_t *limits) |
| Bind a budget to a policy (or the default policy) and zero it. | |
| ra8_err_t | ra8_decomp_budget_charge_output (ra8_decomp_budget_t *b, uint64_t in_total, uint64_t out_delta) |
| Charge decompressed output against the cap and ratio bounds. | |
| ra8_err_t | ra8_decomp_budget_charge_entry (ra8_decomp_budget_t *b) |
| Charge one enumerated archive entry against the entry cap. | |
| ra8_err_t | ra8_decomp_budget_charge_iter (ra8_decomp_budget_t *b) |
| Charge one decode-loop turn against the iteration budget. | |
| ra8_err_t | ra8_decomp_budget_enter (ra8_decomp_budget_t *b) |
| Enter one stacked decode layer (nesting-depth guard). | |
| void | ra8_decomp_budget_leave (ra8_decomp_budget_t *b) |
| Leave one stacked decode layer (balances ra8_decomp_budget_enter). | |
| ra8_err_t | ra8_decomp_check_declared (const ra8_decomp_limits_t *limits, uint64_t comp_size, uint64_t out_size) |
| Header-level check of a member's declared sizes against a policy. | |
| ra8_err_t | ra8_decomp_zip_entry_preflight (ra8_decomp_read_fn read, void *ctx, uint64_t archive_size) |
| Reject an over-cap ZIP from its EOCD before directory allocation. | |
Unified decompression-limits policy: one bound set for every decoder.
Every archive / compressed-stream decoder in this firmware (ZIP-store and DEFLATE via miniz, RAR4/RAR5, gzip, XZ/LZMA2, tar, and the raw-DEFLATE buffer path in ra8_compress.h) consumes untrusted SD-card content and must be bounded and fail-closed on any hostile input. This header is the single enforcement seam they all share: one policy record (ra8_decomp_limits_t), one running-budget tracker (ra8_decomp_budget_t), and one header-level declared-size check (ra8_decomp_check_declared).
The threat model (owner-approved) is not remote code execution – it is a malicious or malformed archive crashing the reader or exhausting RAM/CPU. The policy therefore bounds the five resource axes a decompressor can be driven along:
| Axis | Field | Breach error |
|---|---|---|
| Total output bytes | max_output_bytes | k_ra8_err_decomp_output_cap |
| Compression ratio | max_ratio | k_ra8_err_decomp_ratio |
| Archive entry count | max_entries | k_ra8_err_decomp_entries |
| Container nesting | max_depth | k_ra8_err_decomp_depth |
| Decode-loop turns | max_iterations | k_ra8_err_decomp_iterations |
Header-declared sizes (a ZIP central-directory record, a RAR block header, a tar size field) are checked against the same policy before any decoding starts (ra8_decomp_check_declared) – a lying header is rejected as cheaply as an honest bomb.
Definition in file ra8_decomp_limits.h.
| typedef size_t(* ra8_decomp_read_fn) (void *ctx, uint64_t offset, void *buf, size_t len) |
Positioned reader used by bounded container preflights.
Reads from an immutable seekable container without requiring a resident blob.
| [in] | ctx | Opaque backing context. |
| [in] | offset | Absolute byte offset in the container. |
| [out] | buf | Destination for len bytes. |
| [in] | len | Requested byte count. |
buf. Definition at line 403 of file ra8_decomp_limits.h.
| enum ra8_decomp_defaults_t : uint64_t |
Owner-approved default values for ra8_decomp_limits_t.
One 64-bit-typed enum so every default is a named constant (no magic numbers) in a single place. ra8_decomp_limits_default() returns a policy built from exactly these values. Rationale per value:
Definition at line 97 of file ra8_decomp_limits.h.
|
nodiscard |
Charge one enumerated archive entry against the entry cap.
Walkers call this once per member they index (ZIP central directory record, RAR file block, tar header). The many-tiny-entries bomb is rejected the moment the count crosses max_entries.
| [in,out] | b | Initialised budget (non-NULL). |
| k_ra8_ok | Entry recorded within the cap. |
| k_ra8_err_null_ptr | b was NULL. |
| k_ra8_err_decomp_entries | The entry count now exceeds max_entries. |
b was initialised by ra8_decomp_budget_init. Definition at line 176 of file ra8_decomp_limits.c.
References k_ra8_err_decomp_entries, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag_decomp.
Referenced by internal_finish_member(), and priv_comic_cbr_open().
|
nodiscard |
Charge one decode-loop turn against the iteration budget.
The NASA P10 Rule 2 backstop for loops whose trip count depends on untrusted bytes: each pass through such a loop charges one turn, so a stream engineered to stall (no input consumed, no output produced) still terminates within max_iterations.
| [in,out] | b | Initialised budget (non-NULL). |
| k_ra8_ok | Turn recorded within the budget. |
| k_ra8_err_null_ptr | b was NULL. |
| k_ra8_err_decomp_iterations | The turn count now exceeds max_iterations. |
b was initialised by ra8_decomp_budget_init. Definition at line 186 of file ra8_decomp_limits.c.
References k_ra8_err_decomp_iterations, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag_decomp.
Referenced by internal_inflate_pass(), internal_unwrap_pass(), and unarch_tar_next().
|
nodiscard |
Charge decompressed output against the cap and ratio bounds.
Adds out_delta to the produced-bytes counter, records the input consumed so far, then enforces (1) the per-unit output cap and (2) the bomb bound out <= in * max_ratio + grace. Call it after every emitted chunk so a bomb is caught within one chunk of the bound, long before RAM or CPU is exhausted.
| [in,out] | b | Initialised budget (non-NULL). |
| [in] | in_total | Compressed bytes consumed so far (monotonic). |
| [in] | out_delta | Newly produced decompressed bytes (may be 0). |
| k_ra8_ok | Charge recorded; both bounds hold. |
| k_ra8_err_null_ptr | b was NULL. |
| k_ra8_err_decomp_output_cap | Output now exceeds max_output_bytes. |
| k_ra8_err_decomp_ratio | Output now exceeds the ratio bound. |
b was initialised by ra8_decomp_budget_init. in_total is non-decreasing across calls on the same budget. out_delta. Definition at line 158 of file ra8_decomp_limits.c.
References internal_ratio_bound(), k_ra8_err_decomp_output_cap, k_ra8_err_decomp_ratio, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag_decomp.
Referenced by internal_inflate_pass(), and internal_unwrap_pass().
|
nodiscard |
Enter one stacked decode layer (nesting-depth guard).
Charge before constructing an inner decoder over an outer one (e.g. the tar walker over a gzip stream view). The archive-in-archive bomb is rejected before the inner layer does any work.
| [in,out] | b | Initialised budget (non-NULL). |
| k_ra8_ok | Depth recorded within max_depth. |
| k_ra8_err_null_ptr | b was NULL. |
| k_ra8_err_decomp_depth | The depth now exceeds max_depth. |
b was initialised by ra8_decomp_budget_init. Definition at line 196 of file ra8_decomp_limits.c.
References k_ra8_err_decomp_depth, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag_decomp.
|
nodiscard |
Bind a budget to a policy (or the default policy) and zero it.
Copies limits (or the default when NULL) into b and clears every counter. Rejects a policy with any zero field: a zero cap is always a configuration bug, never a meaningful bound.
| [out] | b | Budget to initialise (non-NULL). |
| [in] | limits | Policy to enforce, or NULL for the default policy. |
| k_ra8_ok | Budget zeroed and bound to a valid policy. |
| k_ra8_err_null_ptr | b was NULL. |
| k_ra8_err_invalid_arg | limits has a zero field. |
b addresses a writable ra8_decomp_budget_t. limits, when non-NULL, has every field non-zero. b is left zeroed (unusable until re-initialised).Definition at line 142 of file ra8_decomp_limits.c.
References internal_limits_usable(), k_ra8_err_invalid_arg, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_decomp_limits_default(), and s_tag_decomp.
Referenced by unarch_gzip_unwrap(), unarch_tar_open(), and unarch_xz_unwrap().
| void ra8_decomp_budget_leave | ( | ra8_decomp_budget_t * | b | ) |
Leave one stacked decode layer (balances ra8_decomp_budget_enter).
Decrements the depth counter; a NULL budget or an already-zero depth is ignored (teardown paths call this unconditionally).
| [in,out] | b | Budget to unwind (may be NULL). |
b, when non-NULL, was initialised by ra8_decomp_budget_init. b or zero depth left everything unchanged.Definition at line 206 of file ra8_decomp_limits.c.
|
nodiscard |
Header-level check of a member's declared sizes against a policy.
Rejects a lying or hostile header before any decoding: the declared decompressed size must fit the per-unit output cap and the ratio bound relative to the declared compressed size. Used by every walker at index time (ZIP central directory, RAR block header, tar size field) so hostile members cost O(1).
| [in] | limits | Policy to check against (non-NULL, validated fields). |
| [in] | comp_size | Declared compressed (packed) size in bytes. |
| [in] | out_size | Declared decompressed (unpacked) size in bytes. |
| k_ra8_ok | Both declared sizes are within policy. |
| k_ra8_err_null_ptr | limits was NULL. |
| k_ra8_err_decomp_output_cap | out_size exceeds max_output_bytes. |
| k_ra8_err_decomp_ratio | out_size exceeds the ratio bound. |
limits has every field non-zero (policy from ra8_decomp_limits_default or validated by ra8_decomp_budget_init). Definition at line 218 of file ra8_decomp_limits.c.
References internal_ratio_bound(), k_ra8_err_decomp_output_cap, k_ra8_err_decomp_ratio, k_ra8_ok, ra8_decomp_limits_t::max_output_bytes, RA8_CHECK_NULL_PTR, and s_tag_decomp.
Referenced by internal_add_entry(), internal_add_member(), internal_finish_member(), internal_read_page(), internal_require_jof(), priv_epub_zip_guard_entry(), and priv_viewer_open_jof().
|
nodiscard |
The owner-approved default decompression policy.
Builds a ra8_decomp_limits_t from the ra8_decomp_defaults_t constants. This is the ONE policy every production decoder runs under; tests tighten copies of it to exercise breach paths with small fixtures.
| ra8_decomp_limits_t | Populated from ra8_decomp_defaults_t. |
Definition at line 60 of file ra8_decomp_limits.c.
References k_ra8_decomp_def_max_depth, k_ra8_decomp_def_max_entries, k_ra8_decomp_def_max_iters, k_ra8_decomp_def_max_ratio, k_ra8_decomp_def_output_bytes, k_ra8_decomp_def_ratio_grace, ra8_decomp_limits_t::max_depth, ra8_decomp_limits_t::max_entries, ra8_decomp_limits_t::max_iterations, ra8_decomp_limits_t::max_output_bytes, ra8_decomp_limits_t::max_ratio, and ra8_decomp_limits_t::ratio_grace_bytes.
Referenced by internal_add_entry(), internal_add_member(), internal_require_jof(), priv_comic_cbr_open(), priv_comic_cbz_open(), priv_epub_zip_guard_archive(), priv_epub_zip_guard_entry(), priv_viewer_open_jof(), ra8_decomp_budget_init(), and ra8_viewer_reader_bind().
|
nodiscard |
Reject an over-cap ZIP from its EOCD before directory allocation.
Scans only the bounded classic-ZIP comment window in fixed chunks. A valid EOCD whose total-entry field exceeds the shared policy is rejected before a bounded format allocator can obscure the cause with a generic allocation or validation failure.
| [in] | read | Seekable container callback. |
| [in] | ctx | Opaque callback context. |
| [in] | archive_size | Exact ZIP byte length. |
| k_ra8_ok | No valid over-cap EOCD was found; the ZIP decoder remains authoritative. |
| k_ra8_err_null_ptr | read was NULL. |
| k_ra8_err_decomp_entries | The EOCD declares more than 4096 entries. |
archive_size is the same size later supplied to the ZIP decoder. Definition at line 305 of file ra8_decomp_limits.c.
References internal_zip_scan_window_for_eocd(), k_priv_zip_comment_max, k_priv_zip_eocd_bytes, k_priv_zip_scan_chunk, k_priv_zip_sig_bytes, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag_decomp.
Referenced by epub_open(), epub_open_streamed(), and priv_comic_cbz_open().