ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
unarch_xz.h File Reference

Bounded, fail-closed XZ/LZMA2 decoding over the vendored xz-embedded. More...

#include <stddef.h>
#include <stdint.h>
#include "ra8_decomp_limits.h"
#include "ra8_err.h"
#include "unarch_io.h"
Include dependency graph for unarch_xz.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  unarch_xz_stream_t
 One multi-call XZ decode session (opaque decoder + liveness flag). More...

Enumerations

enum  unarch_xz_dims_t : uint32_t {
  k_unarch_xz_state_reserve = 64U * 1024U ,
  k_unarch_xz_sig_len = 6U
}
 Scratch sizing constants for the XZ decoder wrappers. More...

Functions

bool unarch_xz_magic (const uint8_t *sig, size_t sig_len)
 Whether sig begins with the XZ stream header magic.
ra8_err_t unarch_xz_stream_begin (unarch_xz_stream_t *xs, void *scratch, uint32_t scratch_len)
 Begin a multi-call XZ decode session over a caller scratch.
ra8_err_t unarch_xz_stream_run (unarch_xz_stream_t *xs, const uint8_t *in, size_t in_len, size_t *in_used, uint8_t *out, size_t out_cap, size_t *out_used, bool *end)
 Feed one input chunk through a live session, producing output.
void unarch_xz_stream_end (unarch_xz_stream_t *xs)
 End a session: free the decoder and release the allocation pool.
ra8_err_t unarch_xz_unwrap (unarch_read_fn read, void *ctx, uint64_t size, uint8_t *out, size_t out_cap, void *scratch, uint32_t scratch_len, const ra8_decomp_limits_t *limits, size_t *out_len)
 Decode one whole XZ stream from a read seam into a caller arena.

Detailed Description

Bounded, fail-closed XZ/LZMA2 decoding over the vendored xz-embedded.

Tag
[Ring 4 / Domain] {World: NS}

The XZ leg of the archive-hardening subsystem, wrapping the vendored SOUP decoder (apps/shared_libs/third_party/xz_embedded/, decode-only, 0BSD) behind two bounded shapes:

  • unarch_xz_stream_begin / _run / _end – a multi-call decode session in xz-embedded's XZ_PREALLOC mode. The decoder state and the LZMA2 dictionary are allocated once, up front, from the caller's scratch buffer through the zero-heap pool (unarch_xz_pool.h) and never grow: a stream whose declared dictionary exceeds the scratch is rejected fail-closed instead of allocating.
  • unarch_xz_unwrap – decode one whole .xz stream fetched through the shared seek+read seam (unarch_io.h) into a caller arena, charging every pass against the unified decompression-limits policy (ra8_decomp_limits.h): output cap, compression-ratio bound, and a per-loop iteration budget. This is the entry the wrapped comic/tar open paths use for .tar.xz content.

Integrity is verified by the decoder (CRC32 and the xz(1) default CRC64); a stream using an unsupported check or filter (SHA-256, BCJ, delta) is rejected cleanly, never mis-decoded. Trailing bytes after the stream footer are rejected (no multi-stream concatenation).

Note
Not thread-safe; the single-threaded reader loop serialises access (the XZ allocation pool is single-client by design).
See also
ra8_decomp_limits.h The policy every decode is charged against.
unarch_io.h The seek+read seam the unwrap consumes.
docs/SOUP/xz_embedded.md Qualification record for the vendored tree.
Since
Version 0.1.0

Definition in file unarch_xz.h.

Enumeration Type Documentation

◆ unarch_xz_dims_t

enum unarch_xz_dims_t : uint32_t

Scratch sizing constants for the XZ decoder wrappers.

k_unarch_xz_state_reserve is the slice of a streaming session's scratch reserved for xz-embedded's decoder state (struct xz_dec plus the LZMA2 state, ~30 KiB measured; reserved with margin); the remainder becomes the preallocated LZMA2 dictionary, so scratch_len - reserve is the largest dictionary a stream may declare. k_unarch_xz_sig_len is the length of the XZ stream header magic used for container detection.

Since
Version 0.1.0
Enumerator
k_unarch_xz_state_reserve 

Decoder-state slice of the scratch.

k_unarch_xz_sig_len 

XZ stream header magic length.

Definition at line 70 of file unarch_xz.h.

Function Documentation

◆ unarch_xz_magic()

bool unarch_xz_magic ( const uint8_t * sig,
size_t sig_len )
nodiscard

Whether sig begins with the XZ stream header magic.

Pure signature probe over the six magic bytes (FD 37 7A 58 5A 00) so open paths can route a wrapped archive without constructing a decoder.

Parameters
[in]sigLeading archive bytes (may be NULL).
[in]sig_lenReadable length of sig in bytes.
Returns
Whether the bytes begin an XZ stream.
Return values
trueThe six magic bytes match.
falsesig is NULL, too short, or not XZ.
Precondition
sig holds sig_len readable bytes when non-NULL.
sig_len is the true readable length (untrusted values are safe).
Postcondition
No state is modified (pure read).
The result depends only on the first six bytes.
Note
Thread-safe: pure read.
See also
unarch_xz_unwrap()
Since
Version 0.1.0

Definition at line 77 of file unarch_xz.c.

References k_unarch_xz_sig_len, k_xz_magic_b0, k_xz_magic_b1, k_xz_magic_b2, k_xz_magic_b3, k_xz_magic_b4, k_xz_magic_b5, and memeq.

Referenced by comic_open_wrapped(), and internal_open_unwrapped().

◆ unarch_xz_stream_begin()

ra8_err_t unarch_xz_stream_begin ( unarch_xz_stream_t * xs,
void * scratch,
uint32_t scratch_len )
nodiscard

Begin a multi-call XZ decode session over a caller scratch.

Installs scratch as the XZ allocation arena and creates an XZ_PREALLOC decoder whose dictionary budget is scratch_len - k_unarch_xz_state_reserve: the dictionary is allocated once at init and never grows, and a stream declaring a larger dictionary is rejected during _run (no growth, no fallback).

Parameters
[out]xsSession to bind (non-NULL).
[in]scratchScratch buffer (non-NULL, 8-byte aligned).
[in]scratch_lenScratch length, > k_unarch_xz_state_reserve.
Returns
ra8_err_t Error code.
Return values
k_ra8_okSession live; feed it via _run.
k_ra8_err_null_ptrxs or scratch was NULL.
k_ra8_err_invalid_sizeScratch too small or misaligned.
k_ra8_err_busyAnother XZ session is in flight.
k_ra8_err_no_memDecoder-state allocation failed.
Precondition
No other XZ session is live (single-client pool).
scratch out-lives the session.
Postcondition
On k_ra8_ok, xs->live is true until unarch_xz_stream_end.
On any error the pool is released and xs is dead.
Note
Not thread-safe.
See also
unarch_xz_stream_run()
Since
Version 0.1.0

Definition at line 96 of file unarch_xz.c.

References unarch_xz_stream_t::dec, k_ra8_err_invalid_size, k_ra8_err_no_mem, k_ra8_ok, k_unarch_xz_state_reserve, unarch_xz_stream_t::live, RA8_CHECK_NULL_PTR, s_tag_xz, unarch_xz_pool_install(), and unarch_xz_pool_reset().

Referenced by unarch_xz_unwrap().

◆ unarch_xz_stream_end()

void unarch_xz_stream_end ( unarch_xz_stream_t * xs)

End a session: free the decoder and release the allocation pool.

Safe on a NULL or never-begun session (teardown paths call it unconditionally). After this the caller's scratch is dead storage again and a new session may begin.

Parameters
[in,out]xsSession to end (may be NULL).
Precondition
xs, when live, owns the installed pool.
No further _run calls follow on xs.
Postcondition
xs->live is false and the pool is uninstalled.
A subsequent unarch_xz_stream_begin may reuse the scratch.
Note
Not thread-safe.
See also
unarch_xz_stream_begin()
Since
Version 0.1.0

Definition at line 212 of file unarch_xz.c.

References unarch_xz_stream_t::dec, unarch_xz_stream_t::live, and unarch_xz_pool_reset().

Referenced by unarch_xz_unwrap().

◆ unarch_xz_stream_run()

ra8_err_t unarch_xz_stream_run ( unarch_xz_stream_t * xs,
const uint8_t * in,
size_t in_len,
size_t * in_used,
uint8_t * out,
size_t out_cap,
size_t * out_used,
bool * end )
nodiscard

Feed one input chunk through a live session, producing output.

One xz_dec_run pass: consumes up to in_len input bytes and writes up to out_cap output bytes, reporting both counts and whether the stream ended. The caller loops – charging its own ra8_decomp_budget_t per pass – until *end or an error. Returning with zero consumed and zero produced is legal decoder behaviour on tiny buffers; the caller's iteration budget bounds the loop regardless (the decoder itself also reports a stuck stream as a validation failure).

Parameters
[in,out]xsLive session (non-NULL).
[in]inInput chunk (non-NULL when in_len > 0).
[in]in_lenInput bytes available.
[out]in_usedReceives input bytes consumed (non-NULL).
[out]outOutput chunk buffer (non-NULL).
[in]out_capOutput capacity in bytes.
[out]out_usedReceives output bytes produced (non-NULL).
[out]endReceives true when the stream verified and ended (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okPass completed; inspect the counts.
k_ra8_err_null_ptrA required pointer was NULL.
k_ra8_err_invalid_statexs is not live.
k_ra8_err_no_memDeclared dictionary exceeds the session's scratch budget.
k_ra8_err_not_supportedUnsupported format/check/filter.
k_ra8_err_validation_failedCorrupt / truncated stream, a failed integrity check, or a stuck stream.
Precondition
unarch_xz_stream_begin succeeded on xs.
out holds out_cap writable bytes.
Postcondition
On k_ra8_ok, out[0..*out_used) holds newly decoded bytes.
On any error the session must be ended (it is not recoverable).
Note
Not thread-safe.
See also
unarch_xz_stream_end()
Since
Version 0.1.0

Definition at line 168 of file unarch_xz.c.

References unarch_xz_stream_t::dec, internal_xz_map_err(), k_ra8_err_invalid_state, k_ra8_ok, unarch_xz_stream_t::live, RA8_CHECK_NULL_PTR, and s_tag_xz.

Referenced by internal_unwrap_pass().

◆ unarch_xz_unwrap()

ra8_err_t unarch_xz_unwrap ( unarch_read_fn read,
void * ctx,
uint64_t size,
uint8_t * out,
size_t out_cap,
void * scratch,
uint32_t scratch_len,
const ra8_decomp_limits_t * limits,
size_t * out_len )
nodiscard

Decode one whole XZ stream from a read seam into a caller arena.

Runs a full streaming session over [0, size) of the backing: input is fetched in small fixed chunks, each decode pass is charged against limits (iteration budget, output cap, ratio bound), and the stream's integrity check is verified before success. Fail-closed on everything else: truncation, corruption, an unsupported check/filter, a dictionary larger than the scratch budget, output overrun, and trailing bytes after the stream footer.

Parameters
[in]readByte reader over the XZ stream (non-NULL).
[in]ctxContext passed to read.
[in]sizeStream length in bytes (> 0).
[out]outDestination arena (non-NULL, out_cap bytes).
[in]out_capCapacity of out in bytes (> 0).
[in]scratchSession scratch (non-NULL, 8-byte aligned, > k_unarch_xz_state_reserve bytes).
[in]scratch_lenScratch length in bytes.
[in]limitsPolicy to enforce, or NULL for the default.
[out]out_lenReceives the decoded byte count (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okStream decoded and verified.
k_ra8_err_null_ptrA required pointer was NULL.
k_ra8_err_invalid_sizesize / out_cap is 0, or the scratch is undersized / misaligned.
k_ra8_err_invalid_arglimits has a zero field.
k_ra8_err_busyAnother XZ session is in flight.
k_ra8_err_no_memDecoder-state allocation failed, the declared dictionary exceeds the scratch budget, or out is too small for the stream.
k_ra8_err_not_supportedNot an XZ stream, or one using an unsupported check/filter.
k_ra8_err_validation_failedCorrupt / truncated / trailing-byte stream or a failed integrity check.
k_ra8_err_decomp_output_capOutput exceeds the policy cap.
k_ra8_err_decomp_ratioOutput breached the ratio bound.
k_ra8_err_decomp_iterationsThe decode loop budget ran out.
Precondition
No other XZ session is live (single-threaded reader loop).
read serves offsets [0, size) of the stream.
Postcondition
On k_ra8_ok, out[0..*out_len) holds the decoded bytes.
On any error *out_len == 0; the pool is released either way.
Note
Not thread-safe.
See also
unarch_xz_stream_run()
Since
Version 0.1.0

Definition at line 351 of file unarch_xz.c.

References xz_unwrap_state_t::budget, xz_unwrap_state_t::ctx, xz_unwrap_state_t::in_off, internal_unwrap_pass(), internal_unwrap_reject_null(), k_ra8_err_invalid_size, k_ra8_err_validation_failed, k_ra8_ok, xz_unwrap_state_t::out, xz_unwrap_state_t::out_cap, ra8_decomp_budget_init(), xz_unwrap_state_t::read, xz_unwrap_state_t::size, xz_unwrap_state_t::total_out, unarch_xz_stream_begin(), unarch_xz_stream_end(), and xz_unwrap_state_t::xs.

Referenced by internal_unwrap().