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

Untrusted-byte parsers for the tar walker: numerics, checksum, pax. More...

#include <string.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "unarch_tar_internal.h"
Include dependency graph for unarch_tar_fields.c:

Go to the source code of this file.

Enumerations

enum  tar_field_const_t : uint32_t {
  k_tar_octal_base = 8U ,
  k_tar_decimal_base = 10U ,
  k_tar_b256_flag = 0x80U ,
  k_tar_b256_negative = 0x40U ,
  k_tar_b256_payload = 0x7FU ,
  k_tar_b256_fit = 8U ,
  k_tar_shift_byte = 8U ,
  k_tar_pax_len_max = 7U ,
  k_tar_chksum_space = (uint32_t)' '
}
 Grammar constants for the numeric and pax record parsers. More...

Functions

static ra8_err_t internal_octal (const uint8_t *field, size_t len, uint64_t *out)
 Decode an octal ASCII field (leading spaces, NUL/space terminated).
static ra8_err_t internal_base256 (const uint8_t *field, size_t len, uint64_t *out)
 Decode a GNU base-256 (big-endian binary) numeric field.
ra8_err_t priv_unarch_tar_num (const uint8_t *field, size_t len, uint64_t *out)
 Decode a tar numeric field (octal ASCII or GNU base-256).
bool priv_unarch_tar_block_zero (const uint8_t *block)
 Whether a header block is all zero bytes (end-of-archive marker).
bool priv_unarch_tar_checksum_ok (const uint8_t *block)
 Verify a header block's checksum (unsigned byte sum).
bool priv_unarch_tar_magic_ok (const uint8_t *block)
 Whether a header block carries the ustar / GNU magic.
ra8_tar_type_t priv_unarch_tar_classify (uint8_t typeflag)
 Classify a header block's typeflag byte.
static ra8_err_t internal_pax_reclen (const uint8_t *data, size_t len, size_t *reclen, size_t *body)
 Decode one pax record's decimal length prefix.
static ra8_err_t internal_pax_size_value (const uint8_t *val, size_t len, uint64_t *out)
 Decimal-decode a pax size record value with overflow checks.
static ra8_err_t internal_pax_apply (const uint8_t *key, size_t key_len, const uint8_t *val, size_t val_len, char *name_buf, uint16_t name_cap, uint16_t *name_len, bool *have_path, uint64_t *size_ovr, bool *have_size)
 Apply one parsed pax record's key/value to the override outputs.
ra8_err_t priv_unarch_tar_pax_parse (const uint8_t *data, size_t len, char *name_buf, uint16_t name_cap, uint16_t *name_len, bool *have_path, uint64_t *size_ovr, bool *have_size)
 Parse pax extended-header records, extracting path / size.

Variables

static const char *const s_tag_tar_f = "unarch_tar"
 Log tag for tar field-parser diagnostics.

Detailed Description

Untrusted-byte parsers for the tar walker: numerics, checksum, pax.

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

Every function in this TU consumes raw hostile bytes and must be individually fail-closed; they are TU-external (declared in unarch_tar_internal.h) so the host tests drive each rejection branch directly. Grammar sources: the POSIX.1-2017 pax Interchange Format (header block layout, octal fields, d key=value\n records) and the documented GNU tar base-256 numeric extension. Clean-room: no code from GNU tar / libarchive / busybox.

Since
Version 0.1.0

Definition in file unarch_tar_fields.c.

Enumeration Type Documentation

◆ tar_field_const_t

enum tar_field_const_t : uint32_t

Grammar constants for the numeric and pax record parsers.

Since
Version 0.1.0
Enumerator
k_tar_octal_base 

Octal radix.

k_tar_decimal_base 

pax record-length / size radix.

k_tar_b256_flag 

Base-256 marker bit in byte 0.

k_tar_b256_negative 

Sign bit of a base-256 value.

k_tar_b256_payload 

Payload mask of base-256 byte 0.

k_tar_b256_fit 

Trailing bytes that fit in uint64.

k_tar_shift_byte 

Bits per base-256 byte.

k_tar_pax_len_max 

Max digits in a pax record length.

k_tar_chksum_space 

chksum bytes count as spaces.

Definition at line 42 of file unarch_tar_fields.c.

Function Documentation

◆ internal_base256()

ra8_err_t internal_base256 ( const uint8_t * field,
size_t len,
uint64_t * out )
static

Decode a GNU base-256 (big-endian binary) numeric field.

Byte 0 carries the 0x80 marker; the remaining bits are a big-endian two's-complement value. Negative values and values that cannot fit a uint64 are rejected fail-closed.

Parameters
[in]fieldField bytes (byte 0 has the marker set).
[in]lenField length in bytes.
[out]outReceives the value.
Returns
ra8_err_t status.
Return values
k_ra8_okDecoded.
k_ra8_err_validation_failedNegative or over 64 bits.
Precondition
field[0] & 0x80 is set (caller-routed).
field / out are non-NULL (caller-guarded).
Postcondition
On k_ra8_ok *out is exact; otherwise *out is 0.
No state outside out is modified.
Note
Thread-safe: pure read.
Since
Version 0.1.0

Definition at line 125 of file unarch_tar_fields.c.

References k_ra8_err_validation_failed, k_ra8_ok, k_tar_b256_fit, k_tar_b256_negative, k_tar_b256_payload, and k_tar_shift_byte.

Referenced by priv_unarch_tar_num().

◆ internal_octal()

ra8_err_t internal_octal ( const uint8_t * field,
size_t len,
uint64_t * out )
static

Decode an octal ASCII field (leading spaces, NUL/space terminated).

The POSIX numeric field shape. Rejects an empty digit run, a non-octal byte before the terminator, and 64-bit overflow.

Parameters
[in]fieldField bytes.
[in]lenField length in bytes.
[out]outReceives the value.
Returns
ra8_err_t status.
Return values
k_ra8_okDecoded.
k_ra8_err_validation_failedEmpty / malformed / overflowing.
Precondition
field holds len readable bytes (caller-guarded non-NULL).
out is non-NULL (caller-guarded).
Postcondition
On k_ra8_ok *out is exact; otherwise *out is 0.
No state outside out is modified.
Note
Thread-safe: pure read.
Since
Version 0.1.0

Definition at line 72 of file unarch_tar_fields.c.

References k_ra8_err_validation_failed, k_ra8_ok, and k_tar_octal_base.

Referenced by priv_unarch_tar_checksum_ok(), and priv_unarch_tar_num().

◆ internal_pax_apply()

ra8_err_t internal_pax_apply ( const uint8_t * key,
size_t key_len,
const uint8_t * val,
size_t val_len,
char * name_buf,
uint16_t name_cap,
uint16_t * name_len,
bool * have_path,
uint64_t * size_ovr,
bool * have_size )
static

Apply one parsed pax record's key/value to the override outputs.

path copies the value into the caller name buffer (clamped); size decimal-decodes it; every other key is ignored.

Parameters
[in]keyKey bytes.
[in]key_lenKey length.
[in]valValue bytes.
[in]val_lenValue length.
[out]name_bufCaller name buffer (may be NULL if cap 0).
[in]name_capName buffer capacity.
[out]name_lenReceives a copied path length.
[out]have_pathSet when a path was applied.
[out]size_ovrReceives a decoded size.
[out]have_sizeSet when a size was applied.
Returns
ra8_err_t status.
Return values
k_ra8_okRecord applied or ignored.
k_ra8_err_validation_failedA malformed size value.
Precondition
The key/value spans lie inside the caller's pax data.
The out-flags were initialised by the caller.
Postcondition
A path / size record updates exactly its own outputs.
Unknown keys change nothing.
Note
Thread-safe: writes only through its out-parameters.
Since
Version 0.1.0

Definition at line 348 of file unarch_tar_fields.c.

References internal_pax_size_value(), k_ra8_ok, and memcpy().

Referenced by priv_unarch_tar_pax_parse().

◆ internal_pax_reclen()

ra8_err_t internal_pax_reclen ( const uint8_t * data,
size_t len,
size_t * reclen,
size_t * body )
static

Decode one pax record's decimal length prefix.

Digits up to k_tar_pax_len_max, terminated by one space; the resulting length must cover at least the prefix itself.

Parameters
[in]dataRecord bytes.
[in]lenBytes available from the record start.
[out]reclenReceives the declared record length.
[out]bodyReceives the offset of the first byte after the space.
Returns
ra8_err_t status.
Return values
k_ra8_okLength decoded.
k_ra8_err_validation_failedMalformed / oversized prefix.
Precondition
data holds len readable bytes (caller-guarded non-NULL).
reclen / body are non-NULL (caller-owned locals).
Postcondition
On k_ra8_ok, *body <= *reclen <= len is NOT yet guaranteed – the caller still range-checks *reclen against len.
On any error the outputs are unspecified and unused.
Note
Thread-safe: pure read.
Since
Version 0.1.0

Definition at line 246 of file unarch_tar_fields.c.

References k_ra8_err_validation_failed, k_ra8_ok, k_tar_decimal_base, and k_tar_pax_len_max.

Referenced by priv_unarch_tar_pax_parse().

◆ internal_pax_size_value()

ra8_err_t internal_pax_size_value ( const uint8_t * val,
size_t len,
uint64_t * out )
static

Decimal-decode a pax size record value with overflow checks.

Plain non-negative decimal digits only (the pax size value grammar); an empty value, any non-digit byte, or a value that would overflow uint64 rejects the record fail-closed.

Parameters
[in]valValue bytes (between '=' and the newline).
[in]lenValue length in bytes.
[out]outReceives the size.
Returns
ra8_err_t status.
Return values
k_ra8_okDecoded.
k_ra8_err_validation_failedEmpty, non-decimal, or overflowing.
Precondition
val holds len readable bytes (caller-guarded non-NULL).
out is a caller-owned local (non-NULL).
Postcondition
On k_ra8_ok *out is exact.
On any error *out is unspecified and unused.
Note
Thread-safe: pure read.
Since
Version 0.1.0

Definition at line 299 of file unarch_tar_fields.c.

References k_ra8_err_validation_failed, k_ra8_ok, and k_tar_decimal_base.

Referenced by internal_pax_apply().

◆ priv_unarch_tar_block_zero()

bool priv_unarch_tar_block_zero ( const uint8_t * block)
nodiscard

Whether a header block is all zero bytes (end-of-archive marker).

tar terminates an archive with two zero blocks; this walker treats the first as a clean end (tolerant of single-block writers, harmless for hostile input – end is end).

Parameters
[in]blockOne k_unarch_tar_block byte block (non-NULL).
Returns
Whether every byte is zero.
Return values
trueEnd-of-archive marker.
falseAt least one non-zero byte.
Precondition
block holds a full block of readable bytes.
block is non-NULL (caller-guarded).
Postcondition
No state is modified (pure read).
The result depends only on the block bytes.
Note
Thread-safe: pure read.
MC/DC:
Promoted to TU-external linkage for direct test access (no compound decisions; the scan is a single-condition loop).
Since
Version 0.1.0

Definition at line 162 of file unarch_tar_fields.c.

References k_unarch_tar_block, and RA8_PRIV.

Referenced by unarch_tar_next().

◆ priv_unarch_tar_checksum_ok()

bool priv_unarch_tar_checksum_ok ( const uint8_t * block)
nodiscard

Verify a header block's checksum (unsigned byte sum).

Sums all block bytes with the chksum field replaced by spaces (per the tar specification) and compares against the octal value stored in the chksum field. A field that fails octal decode fails the check.

Parameters
[in]blockOne k_unarch_tar_block byte block (non-NULL).
Returns
Whether the stored checksum matches the computed sum.
Return values
trueChecksum holds.
falseMismatch or undecodable chksum field.
Precondition
block holds a full block of readable bytes.
block is non-NULL (caller-guarded).
Postcondition
No state is modified (pure read).
The result depends only on the block bytes.
Note
Thread-safe: pure read.
MC/DC:
Promoted to TU-external linkage so tests can drive the mismatch and undecodable-field arms directly.
Since
Version 0.1.0

Definition at line 172 of file unarch_tar_fields.c.

References internal_octal(), k_ra8_ok, k_ra8_tar_len_chksum, k_ra8_tar_off_chksum, k_tar_chksum_space, k_unarch_tar_block, and RA8_PRIV.

Referenced by internal_decode_header(), and unarch_tar_probe().

◆ priv_unarch_tar_classify()

ra8_tar_type_t priv_unarch_tar_classify ( uint8_t typeflag)
nodiscard

Classify a header block's typeflag byte.

Maps the tar typeflag onto ra8_tar_type_t: regular file ('0' / NUL), directory ('5'), pax extended header ('x'), skipped meta ('g' global, 'K' GNU longlink), GNU longname ('L'), and everything else as an enumerated-but-skipped member.

Parameters
[in]typeflagThe header's typeflag byte.
Returns
The normalised ra8_tar_type_t class.
Return values
k_ra8_tar_type_otherFor any flag this reader does not handle.
Precondition
None – every byte value maps to a class.
The caller applies the class, not the raw flag.
Postcondition
No state is modified (pure mapping).
The result depends only on typeflag.
Note
Thread-safe: pure mapping.
MC/DC:
Promoted to TU-external linkage for direct test access (single-condition comparisons only).
Since
Version 0.1.0

Definition at line 200 of file unarch_tar_fields.c.

References k_ra8_tar_type_dir, k_ra8_tar_type_file, k_ra8_tar_type_longname, k_ra8_tar_type_meta, k_ra8_tar_type_other, k_ra8_tar_type_pax, and RA8_PRIV.

Referenced by internal_decode_header().

◆ priv_unarch_tar_magic_ok()

bool priv_unarch_tar_magic_ok ( const uint8_t * block)
nodiscard

Whether a header block carries the ustar / GNU magic.

Requires "ustar" at the magic offset followed by NUL (POSIX) or space (old GNU). Pre-POSIX v7 headers carry no magic and are rejected – every modern tar writer emits ustar.

Parameters
[in]blockOne k_unarch_tar_block byte block (non-NULL).
Returns
Whether the magic matches either dialect.
Return values
truePOSIX ustar or old-GNU magic.
falseAnything else (including v7 headers).
Precondition
block holds a full block of readable bytes.
block is non-NULL (caller-guarded).
Postcondition
No state is modified (pure read).
The result depends only on the magic bytes.
Note
Thread-safe: pure read.
MC/DC:
Promoted to TU-external linkage so tests can drive the NUL-vs-space terminator compound directly.
Since
Version 0.1.0

Definition at line 188 of file unarch_tar_fields.c.

References k_ra8_tar_off_magic, k_ra8_tar_off_magic_term, and RA8_PRIV.

Referenced by internal_decode_header(), and unarch_tar_probe().

◆ priv_unarch_tar_num()

ra8_err_t priv_unarch_tar_num ( const uint8_t * field,
size_t len,
uint64_t * out )
nodiscard

Decode a tar numeric field (octal ASCII or GNU base-256).

Octal fields may carry leading spaces and are terminated by NUL or space; any other byte, an empty field, or 64-bit overflow is rejected. A field whose first byte has the top bit set is GNU base-256 (big-endian binary): negative values and values over 64 bits are rejected.

Parameters
[in]fieldField bytes (non-NULL).
[in]lenField length in bytes (> 0).
[out]outReceives the decoded value (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okValue decoded into out.
k_ra8_err_null_ptrfield or out was NULL.
k_ra8_err_validation_failedEmpty, malformed, negative, or overflowing field.
Precondition
field holds len readable bytes.
len is a real header-field length (bounded by the block size).
Postcondition
On k_ra8_ok, *out holds the exact field value.
On any error *out is 0.
Note
Thread-safe: pure read.
MC/DC:
Promoted to TU-external linkage so tests can drive the octal-digit range compounds and the base-256 fit checks with hostile field bytes.
Since
Version 0.1.0

Definition at line 148 of file unarch_tar_fields.c.

References internal_base256(), internal_octal(), k_ra8_err_validation_failed, k_tar_b256_flag, RA8_CHECK_NULL_PTR, RA8_PRIV, and s_tag_tar_f.

Referenced by internal_decode_header().

◆ priv_unarch_tar_pax_parse()

ra8_err_t priv_unarch_tar_pax_parse ( const uint8_t * data,
size_t len,
char * name_buf,
uint16_t name_cap,
uint16_t * name_len,
bool * have_path,
uint64_t * size_ovr,
bool * have_size )
nodiscard

Parse pax extended-header records, extracting path / size.

Walks the "%d key=value\n" record stream fail-closed: a record whose declared length is non-decimal, too small, overruns the data, or lacks the '=' / trailing newline rejects the whole header. A path record is copied into name_buf (clamped to name_cap) and a size record is decimal-decoded with overflow checks; every other key is skipped.

Parameters
[in]datapax data bytes (non-NULL).
[in]lenpax data length (<= k_unarch_tar_pax_max).
[out]name_bufBuffer for a path value (may be NULL if name_cap is 0).
[in]name_capCapacity of name_buf in bytes.
[out]name_lenReceives the copied path length (non-NULL).
[out]have_pathSet true when a path record was applied (non-NULL).
[out]size_ovrReceives a decoded size value (non-NULL).
[out]have_sizeSet true when a size record was applied (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okRecords parsed; overrides reported.
k_ra8_err_null_ptrA required pointer was NULL.
k_ra8_err_validation_failedA malformed record (bad length, missing '=', missing newline, bad size value).
Precondition
data holds len readable bytes.
The output flags are initialised by the caller (false / 0).
Postcondition
On k_ra8_ok the flags reflect exactly the records present.
On any error the walk must reject the member (fail-closed).
Note
Thread-safe: writes only through its out-parameters.
MC/DC:
Promoted to TU-external linkage so tests can drive every malformed record shape (length, delimiter, terminator, value) directly.
Since
Version 0.1.0

Definition at line 388 of file unarch_tar_fields.c.

References internal_pax_apply(), internal_pax_reclen(), k_ra8_err_validation_failed, k_ra8_ok, RA8_CHECK_NULL_PTR, RA8_PRIV, and s_tag_tar_f.

Referenced by internal_meta_consume().

Variable Documentation

◆ s_tag_tar_f

const char* const s_tag_tar_f = "unarch_tar"
static

Log tag for tar field-parser diagnostics.

Definition at line 29 of file unarch_tar_fields.c.

Referenced by priv_unarch_tar_num(), and priv_unarch_tar_pax_parse().