Safe Data API
CRC-protected (optionally redundant) data containers for Zephyr
v0.0-dev+gbb519af
Loading...
Searching...
No Matches
Type-Erased Core

Type-erased core operations; all integrity logic in one audited place. More...

Macros

#define SAFE_DATA_RECOVERED   (-EAGAIN)
 Return code for a fault that the redundant shadow copy covers.

Typedefs

typedef int(* safe_data_mutator_t) (void *payload, void *user)
 Mutator callback used by safe_data_update() / SAFE_UPDATE().

Functions

int safe_data_init (struct k_mutex *lock, void *payload, size_t len, uint32_t *crc, void *shadow)
 Initialise the lock and seal the current payload contents.
int safe_data_verify (const void *payload, size_t len, uint32_t crc, const void *shadow)
 Verify payload integrity. Pure: read-only and lock-free; it NEVER modifies the payload, so it is safe to call concurrently with writers (a transient mismatch may then be reported - callers needing atomicity should use the higher-level helpers).
int safe_data_verify_repair (void *payload, size_t len, uint32_t crc, void *shadow)
 Verify payload integrity and repair a recoverable fault in place.
int safe_data_read (struct k_mutex *lock, void *payload, size_t len, uint32_t *crc, void *shadow, void *out)
 Verify under lock and copy the payload out to out.
int safe_data_write (struct k_mutex *lock, void *payload, size_t len, uint32_t *crc, void *shadow, const void *in)
 Copy in into the payload under lock and reseal the integrity tag.
int safe_data_update (struct k_mutex *lock, void *payload, size_t len, uint32_t *crc, void *shadow, safe_data_mutator_t fn, void *user)
 Atomic read-modify-write: lock, verify, run fn, reseal on success.
int safe_data_commit (struct k_mutex *lock, void *payload, size_t len, uint32_t *crc, void *shadow)
 Reseal after an explicit external modification (advanced use). Lock, recompute the integrity tag, unlock.

Detailed Description

Type-erased core operations; all integrity logic in one audited place.

Application code should prefer the typed container layer (Containers and Typed Access) - the macros there only derive (&payload, sizeof(payload), &crc, &lock, shadow) from a typed container and forward to these functions.

Macro Definition Documentation

◆ SAFE_DATA_RECOVERED

#define SAFE_DATA_RECOVERED   (-EAGAIN)

Return code for a fault that the redundant shadow copy covers.

From safe_data_verify() (pure) it means the fault is recoverable: the payload was NOT modified. From safe_data_verify_repair() it means the payload has been repaired in place and is valid again once the tag is resealed.

Definition at line 83 of file safe_data.h.

Referenced by safe_data_read(), safe_data_selftest(), safe_data_update(), safe_data_verify_repair(), and verify_quiet().

Typedef Documentation

◆ safe_data_mutator_t

typedef int(* safe_data_mutator_t) (void *payload, void *user)

Mutator callback used by safe_data_update() / SAFE_UPDATE().

Invoked with the lock held and the payload already verified. Mutate payload in place. Return 0 to commit (the integrity tag is resealed) or a negative errno to abort (the payload is rolled back / left as-is and NOT resealed). A positive return value is a contract violation: it is clamped to -EINVAL, the transaction aborts, and the event is counted in the statistics.

Parameters
payloadPointer to the (verified) payload, cast to its real type.
userOpaque user context forwarded from the call site.
Returns
0 to commit, negative errno to abort the transaction.

Definition at line 98 of file safe_data.h.

Function Documentation

◆ safe_data_commit()

int safe_data_commit ( struct k_mutex * lock,
void * payload,
size_t len,
uint32_t * crc,
void * shadow )

Reseal after an explicit external modification (advanced use). Lock, recompute the integrity tag, unlock.

Warning
Re-tags the current memory contents with NO verification - this can seal corrupted data. Only available with CONFIG_SAFE_DATA_ALLOW_UNCHECKED_COMMIT (off at the Strict level).
Parameters
lockContainer mutex, or NULL to skip locking.
payloadPayload buffer whose current contents are sealed as-is.
lenPayload size in bytes (> 0).
crcIntegrity tag storage (recomputed).
shadowRedundant shadow buffer of len bytes (refreshed), or NULL if disabled.
Returns
0 on success, -EINVAL on bad args, -ETIMEDOUT if the lock bound expired.
Depends on
defined(CONFIG_SAFE_DATA_ALLOW_UNCHECKED_COMMIT)

Definition at line 454 of file safe_data.c.

References safe_data_fault_info::len, SAFE_DATA_FAULT_KIND_LOCK_TIMEOUT, and safe_event().

Satisfies requirements SD-REQ-002 (Argument validation), SD-REQ-014 (Bounded lock acquisition), SD-REQ-015 (No ISR-context locking), SD-REQ-016 (Serialised access — no torn snapshots), SD-REQ-020 (Reduced API surface at the Strict level), and SD-REQ-022 (Unchecked commit).

◆ safe_data_init()

int safe_data_init ( struct k_mutex * lock,
void * payload,
size_t len,
uint32_t * crc,
void * shadow )

Initialise the lock and seal the current payload contents.

Must be called once before any other operation. The payload should be fully written (no indeterminate padding) before sealing.

Parameters
lockContainer mutex (initialised here).
payloadPayload buffer.
lenPayload size in bytes (> 0).
crcIntegrity tag storage.
shadowRedundant shadow buffer of len bytes, or NULL if disabled.
Returns
0 on success, -EINVAL on bad arguments.

Definition at line 224 of file safe_data.c.

References safe_data_fault_info::len.

Satisfies requirements SD-REQ-001 (Sealing on initialisation), and SD-REQ-002 (Argument validation).

◆ safe_data_read()

int safe_data_read ( struct k_mutex * lock,
void * payload,
size_t len,
uint32_t * crc,
void * shadow,
void * out )

Verify under lock and copy the payload out to out.

A recoverable fault is repaired and resealed before copying, so a 0 return always means out holds a valid snapshot.

Parameters
lockContainer mutex, or NULL to skip locking.
payloadPayload buffer.
lenPayload size in bytes (> 0).
crcIntegrity tag storage (resealed after a repair).
shadowRedundant shadow buffer of len bytes, or NULL if disabled.
outDestination buffer of len bytes for the validated copy.
Returns
0 on success (incl. recovered), -EILSEQ if unrecoverable, -EINVAL on bad args, -ETIMEDOUT if the lock bound expired.

Definition at line 326 of file safe_data.c.

References safe_data_fault_info::len, SAFE_DATA_FAULT_KIND_LOCK_TIMEOUT, SAFE_DATA_RECOVERED, safe_data_verify_repair(), and safe_event().

Satisfies requirements SD-REQ-002 (Argument validation), SD-REQ-005 (Validated read), SD-REQ-014 (Bounded lock acquisition), SD-REQ-015 (No ISR-context locking), and SD-REQ-016 (Serialised access — no torn snapshots).

◆ safe_data_update()

int safe_data_update ( struct k_mutex * lock,
void * payload,
size_t len,
uint32_t * crc,
void * shadow,
safe_data_mutator_t fn,
void * user )

Atomic read-modify-write: lock, verify, run fn, reseal on success.

This is the correct "checkout": the lock is held for the entire transaction and the integrity tag is resealed automatically, so it can never go stale.

Parameters
lockContainer mutex, or NULL to skip locking.
payloadPayload buffer, verified before and resealed after fn.
lenPayload size in bytes (> 0).
crcIntegrity tag storage (resealed on commit).
shadowRedundant shadow buffer of len bytes, or NULL if disabled (without it an aborting mutator must not have modified the payload - there is no rollback buffer).
fnMutator invoked with the lock held and the payload verified.
userOpaque context forwarded to fn.
Returns
0 on success, the mutator's negative return value if it aborts (a positive mutator return is clamped to -EINVAL), -EILSEQ if the pre-check fails unrecoverably, -EINVAL on bad args, -ETIMEDOUT if the lock bound expired.

Definition at line 386 of file safe_data.c.

References safe_data_fault_info::len, SAFE_DATA_FAULT_KIND_LOCK_TIMEOUT, SAFE_DATA_FAULT_KIND_MUTATOR_CLAMPED, SAFE_DATA_RECOVERED, safe_data_verify_repair(), and safe_event().

Satisfies requirements SD-REQ-002 (Argument validation), SD-REQ-007 (Transactional read-modify-write), SD-REQ-008 (Mutator contract enforcement), SD-REQ-014 (Bounded lock acquisition), SD-REQ-015 (No ISR-context locking), and SD-REQ-016 (Serialised access — no torn snapshots).

◆ safe_data_verify()

int safe_data_verify ( const void * payload,
size_t len,
uint32_t crc,
const void * shadow )

Verify payload integrity. Pure: read-only and lock-free; it NEVER modifies the payload, so it is safe to call concurrently with writers (a transient mismatch may then be reported - callers needing atomicity should use the higher-level helpers).

Parameters
payloadPayload buffer to check.
lenPayload size in bytes (> 0).
crcStored integrity tag to check against.
shadowRedundant shadow buffer of len bytes, or NULL if disabled.
Returns
0 if valid, SAFE_DATA_RECOVERED (-EAGAIN) if corrupt but recoverable from the shadow copy (payload untouched), -EILSEQ if corrupt and unrecoverable, -EINVAL on bad args.

Definition at line 277 of file safe_data.c.

References safe_data_fault_info::len, SAFE_DATA_FAULT_KIND_UNRECOVERABLE, safe_event(), and verify_quiet().

Satisfies requirements SD-REQ-002 (Argument validation), SD-REQ-003 (Pure verification), and SD-REQ-011 (Configurable unrecoverable-fault reaction).

◆ safe_data_verify_repair()

int safe_data_verify_repair ( void * payload,
size_t len,
uint32_t crc,
void * shadow )

Verify payload integrity and repair a recoverable fault in place.

MUST be called with the container lock held (or with equivalent external mutual exclusion): the repair writes to the payload, and doing that concurrently with a writer would corrupt live data. The locked helpers (read/update/SAFE_SECTION) call this internally; after SAFE_DATA_RECOVERED the caller reseals the stored tag to make the repair durable.

Parameters
payloadPayload buffer to check and, if recoverable, repair in place.
lenPayload size in bytes (> 0).
crcStored integrity tag to check against.
shadowRedundant shadow buffer of len bytes, or NULL if disabled.
Returns
0 if valid, SAFE_DATA_RECOVERED (-EAGAIN) if the payload was repaired from the shadow copy (reseal required), -EILSEQ if corrupt and unrecoverable, -EINVAL on bad args.

Definition at line 290 of file safe_data.c.

References safe_data_fault_info::len, payload_matches_shadow(), SAFE_DATA_FAULT_KIND_RECOVERED_PAYLOAD, SAFE_DATA_FAULT_KIND_RECOVERED_TAG, SAFE_DATA_FAULT_KIND_UNRECOVERABLE, SAFE_DATA_RECOVERED, safe_event(), and verify_quiet().

Referenced by safe_data_read(), safe_data_selftest(), and safe_data_update().

Satisfies requirements SD-REQ-002 (Argument validation), SD-REQ-004 (In-place repair under mutual exclusion), SD-REQ-009 (Single-copy fault recovery), SD-REQ-010 (Double-fault detection), and SD-REQ-011 (Configurable unrecoverable-fault reaction).

◆ safe_data_write()

int safe_data_write ( struct k_mutex * lock,
void * payload,
size_t len,
uint32_t * crc,
void * shadow,
const void * in )

Copy in into the payload under lock and reseal the integrity tag.

With CONFIG_SAFE_DATA_WRITE_CHECKS_OLD the previous contents are verified first; a detected corruption is reported (stats + fault callback, kind OVERWRITTEN) but does not change the outcome of the write.

Parameters
lockContainer mutex, or NULL to skip locking.
payloadPayload buffer (overwritten).
lenPayload size in bytes (> 0).
crcIntegrity tag storage (resealed).
shadowRedundant shadow buffer of len bytes, or NULL if disabled.
inSource buffer of len bytes to copy into the payload.
Returns
0 on success, -EINVAL on bad args, -ETIMEDOUT if the lock bound expired.

Definition at line 354 of file safe_data.c.

References safe_data_fault_info::len, SAFE_DATA_FAULT_KIND_LOCK_TIMEOUT, SAFE_DATA_FAULT_KIND_OVERWRITTEN, safe_event(), and verify_quiet().

Satisfies requirements SD-REQ-002 (Argument validation), SD-REQ-006 (Atomic sealed write), SD-REQ-014 (Bounded lock acquisition), SD-REQ-015 (No ISR-context locking), SD-REQ-016 (Serialised access — no torn snapshots), and SD-REQ-018 (Write may not silently mask corruption).