|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
DFU anti-rollback (downgrade protection) policy + storage seam. More...
Go to the source code of this file.
Data Structures | |
| struct | ra8_rot_antirollback_store_t |
| Dependency-injection vtable for the non-volatile version counter. More... | |
Typedefs | |
| typedef ra8_err_t(* | ra8_rot_antirollback_read_fn_t) (uint32_t *out_min_version) |
| Read the stored highest-accepted image version (DI seam). | |
| typedef ra8_err_t(* | ra8_rot_antirollback_commit_fn_t) (uint32_t new_version) |
| Durably advance the stored highest-accepted image version (DI seam). | |
Functions | |
| ra8_err_t | ra8_rot_antirollback_check (uint32_t image_version, uint32_t stored_min_version) |
| Pure downgrade policy: accept iff the image is not older than stored. | |
| ra8_err_t | ra8_rot_antirollback_verify (const ra8_rot_antirollback_store_t *store, uint32_t image_version) |
| Read the stored minimum, apply the policy, and commit on accept. | |
| const ra8_rot_antirollback_store_t * | ra8_rot_antirollback_default_store (void) |
| Return the non-faking default store (reports "not provisioned"). | |
| bool | ra8_rot_antirollback_on_probe_fault (uint32_t *exc_frame) |
| Recover a fault-tolerant counter probe from the app fault handler. | |
DFU anti-rollback (downgrade protection) policy + storage seam.
Anti-rollback prevents an attacker re-flashing an OLDER but still correctly-signed image – one that may carry known, since-patched vulnerabilities. It is the second half of the copy-to-run trust gate: ra8_rot_verify_image (ra8_rot.h) proves an image is authentic; this module proves the authentic image is not a downgrade.
Each signed image's ra8_rot_trailer_t carries a monotonic img_version. The device keeps the highest version it has ever accepted in a non-volatile monotonic counter. The launch path:
Any failure – a null store, a failed read, or (per the default-deny contract) a failed commit – denies the launch.
The non-volatile counter is reached only through a ra8_rot_antirollback_store_t vtable (NASA Rule 9 deviation: function pointers enable Dependency Inversion and host mock injection). Host unit tests inject a mock counter; production wires the real backing once it exists. ra8_rot_antirollback_default_store returns a non-faking stub whose read/commit report "not provisioned" so that, until a real counter is wired, the gate DEFAULT-DENIES rather than silently passes.
Gated behind RA8_ENABLE_ROOT_OF_TRUST (default OFF), the same flag as the root of trust. With the flag OFF the implementation in ra8_dfu_antirollback.c compiles to nothing (an empty translation unit, mirroring ra8_rot.c) and the launch path does not check versions, so existing apps are byte-for-byte unchanged. The declarations below are always visible and reference no external symbol, so a flag-off translation unit gains no link dependency.
Definition in file ra8_dfu_antirollback.h.
| typedef ra8_err_t(* ra8_rot_antirollback_commit_fn_t) (uint32_t new_version) |
Durably advance the stored highest-accepted image version (DI seam).
Writes new_version to the device's non-volatile monotonic anti-rollback counter after an image has been accepted, so future downgrades below this version are rejected. The production implementation programs an OTP / data-flash counter; the host test implementation records a mock variable.
| [in] | new_version | The just-accepted image version to persist. |
| k_ra8_ok | Counter advanced (or already at/above new_version). |
| other | Backing-store program fault (verifier default-denies). |
Definition at line 123 of file ra8_dfu_antirollback.h.
| typedef ra8_err_t(* ra8_rot_antirollback_read_fn_t) (uint32_t *out_min_version) |
Read the stored highest-accepted image version (DI seam).
Reads the device's non-volatile monotonic anti-rollback counter – the highest image version ever accepted. The production implementation reads an OTP / data-flash counter; the host test implementation reads a mock variable. Returning any non-k_ra8_ok code causes the verifier to DEFAULT-DENY.
| [out] | out_min_version | Receives the stored minimum version; non-NULL. |
| k_ra8_ok | *out_min_version holds the stored counter. |
| k_ra8_err_null_ptr | out_min_version is NULL. |
| other | Backing-store read fault (verifier default-denies). |
Definition at line 101 of file ra8_dfu_antirollback.h.
|
nodiscard |
Pure downgrade policy: accept iff the image is not older than stored.
The side-effect-free core of anti-rollback. An image is accepted when its version is greater than or equal to the stored minimum (equal allows a same-version re-flash); a strictly lower version is a downgrade and is rejected. No storage is touched – callers read the stored minimum first (see ra8_rot_antirollback_verify) and default-deny on any read failure before reaching this comparison.
| [in] | image_version | Version recorded in the candidate image trailer. |
| [in] | stored_min_version | Highest version the device has ever accepted. |
| k_ra8_ok | image_version >= stored_min_version (newer or equal – launch permitted). |
| k_ra8_err_validation_failed | image_version < stored_min_version (downgrade – launch refused). |
| const ra8_rot_antirollback_store_t * ra8_rot_antirollback_default_store | ( | void | ) |
Return the non-faking default store (reports "not provisioned").
The real OTP / data-flash monotonic counter is not yet wired (see the TODO in ra8_dfu_antirollback.c). Rather than fake a passing counter, this default store's read and commit both report a "not provisioned" status, so ra8_rot_antirollback_verify DEFAULT-DENIES until a real backing is wired. The returned pointer is to storage with static lifetime; the caller must not free it.
| non-NULL | The default (not-provisioned) store. |
| bool ra8_rot_antirollback_on_probe_fault | ( | uint32_t * | exc_frame | ) |
Recover a fault-tolerant counter probe from the app fault handler.
The default store reads the durable counter (extra-MRAM at k_ra8_flash_extra_start) under a transient fault-catch, because a never-written (blank) ECC-protected extra-MRAM word bus-faults on read and the RA8D2 has no MRAM BlankCheck command (#194). The app's BusFault/HardFault handler must call this first with a pointer to the exception stack frame ([R0 R1 R2 R3 R12 LR PC xPSR]): when a probe is in progress it records the fault, advances the stacked PC past the faulting load, clears the sticky fault status, and returns true so the handler does a plain exception return (the read then maps the blank word to version 0). Outside a probe it returns false and the handler proceeds with its normal fault reporting. No-op under RA8_OFF_TARGET.
| [in,out] | exc_frame | Exception stack frame captured at handler entry (MSP or PSP per EXC_RETURN); its stacked PC (index 6) is advanced. |
| true | Probe fault recovered (handler should exception-return). |
| false | Not a probe fault (or exc_frame is NULL) – handle as real. |
Referenced by blc_fault_dispatch().
|
nodiscard |
Read the stored minimum, apply the policy, and commit on accept.
The full anti-rollback gate used by the copy-to-run launch path. Reads the stored highest-accepted version through store, runs ra8_rot_antirollback_check, and – only on accept – advances the stored counter to image_version. Enforces DEFAULT-DENY: a NULL store, a NULL accessor, a failed read, a downgrade verdict, or a failed commit all return a non-k_ra8_ok code and the caller must NOT launch.
| [in] | store | Storage DI vtable; non-NULL with non-NULL members. |
| [in] | image_version | Version from the authenticated image trailer. |
| k_ra8_ok | Accepted and the counter was advanced. |
| k_ra8_err_null_ptr | store (or a member) is NULL. |
| k_ra8_err_validation_failed | The image is a downgrade. |
| other | Store read or commit reported a fault. |