Repository navigation
Conversation
|
There was a problem hiding this comment.
🟡 Changes recommended
Non-atomic epoch transitions and unsynchronized callback registration can bypass RNG invalidation, duplicate publisher calls, and cause C data races.
4 open issues
What changed in this PR
This PR extends wolfCrypt’s RNG invalidation mechanism with auxiliary callbacks for publishing and receiving entropy events, while standardizing additional-input naming.
Changes:
- Introduces 64-bit entropy epochs and routes invalidation checks through external-event detection.
- Adds callback registration APIs and a function-pointer atomic comparison wrapper.
- Renames reseed APIs from
NoncetoAddIn, updates callers and documentation, and adds auxiliary-epoch tests.
| File | Description |
|---|---|
wolfssl/wolfcrypt/wc_port.h |
Adds the function-pointer atomic comparison wrapper. |
wolfssl/wolfcrypt/random.h |
Defines epoch types, helpers, callbacks, and renamed APIs. |
wolfcrypt/test/test.h |
Declares the auxiliary-epoch test. |
wolfcrypt/test/test.c |
Adds auxiliary-epoch coverage and updates API calls. |
wolfcrypt/src/wc_port.c |
Checks the wrapper’s pointer-size assumption. |
wolfcrypt/src/rng_bank.c |
Updates reseed and stir API names. |
wolfcrypt/src/random.c |
Implements auxiliary invalidation and integrates epoch checks. |
tests/unit-mcdc/test_random_whitebox.c |
Updates internal stir API calls. |
tests/unit-mcdc/test_random_fault_whitebox.c |
Updates stir calls and related comments. |
tests/api/test_random.c |
Updates tests to use renamed APIs. |
linuxkm/lkcapi_sha_glue.c |
Updates kernel reseed call sites. |
doc/dox_comments/header_files/random.h |
Documents auxiliary epochs and renamed APIs. |
.github/workflows/codespell.yml |
Adds addIn to the spelling allowlist. |
Review effort: Balanced
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #12050
Scan targets checked: linuxkm-src, linuxkm-bugs, wolfcrypt-src, wolfcrypt-bugs, wolfssl-src, wolfssl-bugs
Not reviewed (no scan target covers them): .github/workflows/codespell.yml, doc/dox_comments/header_files/random.h, wolfcrypt/test/test.h
Coverage: 7 of 10 in-scope changed file(s) opened by the reviewer; not opened: tests/api/test_random.c, tests/unit-mcdc/test_random_fault_whitebox.c, tests/unit-mcdc/test_random_whitebox.c
Findings: 1
1 finding(s) posted as inline comments (see file-level comments below)
This review was generated automatically by Fenrir. Reported findings require changes before merge.
Review tier: Max
| wc_RNG_entropy_epoch_t cur_extra_entropy_epoch_local = | ||
| wc_RNG_entropy_epoch_export(&extra_entropy_epoch_local); | ||
| if (cur_extra_entropy_epoch != cur_extra_entropy_epoch_local) { | ||
| wc_RNG_global_invalidate_entropy(); |
There was a problem hiding this comment.
Publisher runs before the local external epoch is updated, so a publisher that calls back into the RNG recurses without… · Logic errors
current_entropy_epoch() calls wc_RNG_global_invalidate_entropy(), which runs the registered publisher (line 459), before it updates extra_entropy_epoch_local (line 410). A publisher that calls any RNG API that reads the epoch sees the same external change again and recurses without bound. This happens only for events found through the getter.
Suggested fix: The fix needs a design decision, such as a reentrancy guard that keeps the invalidate-before-import ordering; consult the C11 memory model (ISO/IEC 9899:2011 §5.1.2.4).
There was a problem hiding this comment.
Works as designed; contract-covered. The mechanical observation is accurate,
and deliberate: invalidate-before-import is the pathway's lossless invariant.
Consumption of a detection strictly follows the invalidation it triggers, so a
thread dying anywhere in the window degrades to a duplicate advance, never a
lost one. Every reordering or claim-gating that would prevent the described
recursion reopens a lost-event window, and the loss function here is maximally
asymmetric: a duplicate costs one spurious reseed; a loss costs unbounded reuse
of fork-correlated DRBG state. We optimize the correct tail.
The recursion itself requires the handler to do the one thing its contract
forbids. The dox for wc_RNG_entropy_epoch_extra_inv_init() states the handler
must not call back into wolfCrypt, and the call site in
wc_RNG_global_invalidate_entropy() now carries the same sentence with the
reason ("any epoch read from inside it re-detects the same event and
recurses"). We don't spend runtime state defending against documented misuse;
we document it at both places a reader can arrive from.
Love, Mythos
…bank.c, linuxkm/lkcapi_sha_glue.c, wolfcrypt/test/test.c, doc/dox_comments/header_files/random.h: rename "nonce" to "addIn" in reseed APIs, for consistent naming of "additional" data as such.
tests/unit-mcdc/test_random_whitebox.c: rename "nonce" to "addIn" in reseed APIs.
…mic_Func_Ptr_CompareExchange() -- casting wrapper around wolfSSL_Atomic_Ptr_CompareExchange().
…r-side.
* add APIs wc_RNG_entropy_epoch_extra_inv_init() and wc_RNG_extra_entropy_epoch_init(), and associated callback types.
* add internal routine current_entropy_epoch() and associated internal state.
* refactor all ad hoc invalidation checks of global_entropy_epoch to use current_entropy_epoch().
* refactor entropy epochs as 64 bit width, with wc_RNG_entropy_epoch_t (word64).
* add struct wc_RNG_entropy_epoch_atomic and associated initializers.
* add inline helpers wc_RNG_entropy_epoch_export(), wc_RNG_entropy_epoch_import(), and wc_RNG_entropy_epoch_increment_atomic().
* refactor Hash_DRBG_Reseed() and its caller to pass cur_epoch only when defined(WC_RNG_HAVE_ENTROPY_EPOCH).
* update tests and documentation for 64 bit epochs.
* add test and documentation coverage of auxiliary epoch facility.
…ra_entropy_epoch_reset() and wc_RNG_entropy_epoch_extra_inv_reset() (test helpers). wolfcrypt/test/test.c and wolfcrypt/test/test.h: call rng_epoch_extra_test() from rng_epoch_test() rather than reporting its results separately; fix data race in rng_epoch_extra_getCb(); implement ext epoch save/restore in rng_epoch_extra_test().
6b5e3f0 to
2775dca
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The new RNG epoch tests can falsely report success because subtest failures are not propagated, and small-stack allocation failure can discard installed production handlers without restoring them.
2 open issues
4 resolved since last review
Review effort: Balanced
| } | ||
| #endif /* WC_RNG_SEED_CB && WC_RNG_HAVE_LOCK */ | ||
|
|
||
| api_ret = rng_epoch_extra_test(); |
| WOLFSSL_ENTER("rng_epoch_extra_test"); | ||
|
|
||
| WC_ALLOC_VAR_EX(rng, WC_RNG, 1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER, | ||
| ERROR_OUT(WC_TEST_RET_ENC_EC(MEMORY_E), out_l)); |
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #12050
Scan targets checked: linuxkm-src, linuxkm-bugs, wolfcrypt-src, wolfcrypt-bugs, wolfssl-src, wolfssl-bugs
Not reviewed (no scan target covers them): .github/workflows/codespell.yml, doc/dox_comments/header_files/random.h
Coverage: 3 of 10 in-scope changed file(s) opened by the reviewer; not opened: linuxkm/lkcapi_sha_glue.c, tests/api/test_random.c, tests/unit-mcdc/test_random_fault_whitebox.c, tests/unit-mcdc/test_random_whitebox.c, wolfcrypt/src/rng_bank.c, wolfcrypt/src/wc_port.c, wolfssl/wolfcrypt/random.h
Findings: 2
2 finding(s) posted as inline comments (see file-level comments below)
This review was generated automatically by Fenrir. Reported findings require changes before merge.
Review tier: Lite
| } | ||
| #endif /* WC_RNG_SEED_CB && WC_RNG_HAVE_LOCK */ | ||
|
|
||
| api_ret = rng_epoch_extra_test(); |
There was a problem hiding this comment.
rng_epoch_extra_test() result is discarded, so failures never fail rng_epoch_test · Weak or missing assertions
The return value of rng_epoch_extra_test() goes into api_ret, which is never checked. Control then falls into out_l, which returns ret (still 0). Any failure in the new auxiliary-epoch tests is silently ignored, so the new facility has no effective test coverage in CI.
Suggested fix: Assign the result to ret, or check api_ret and ERROR_OUT(api_ret, out_l) when it is nonzero, so a failing sub-test fails rng_epoch_test.
| (extra_entropy_epoch_get_arg != &invalid_arg_sentinel)) | ||
| { | ||
| wc_RNG_entropy_epoch_t cur_extra_entropy_epoch = | ||
| extra_entropy_epoch_get_handler(extra_entropy_epoch_get_arg); |
There was a problem hiding this comment.
Auxiliary epoch handler pointers are read twice without atomics, so a concurrent reset can cause a NULL function call · Race conditions
current_entropy_epoch() checks extra_entropy_epoch_get_handler != NULL and then reads the global again to make the call. The global is a plain non-atomic read, and wc_RNG_extra_entropy_epoch_reset() can CAS it to NULL in between, which makes the call jump to NULL. wc_RNG_global_invalidate_entropy() has the same check-then-call pattern on entropy_epoch_extra_inv_handler (lines 515/518).
Suggested fix: Load each handler and its arg once into locals with an atomic load, test the locals, and call through the local copy.
Basis: ISO C11 5.1.2.4p25: conflicting non-atomic accesses from different threads, at least one of them a write, are a data race and undefined behavior.


wolfcrypt/src/random.c,wolfssl/wolfcrypt/random.hwolfcrypt/src/rng_bank.c,linuxkm/lkcapi_sha_glue.c,wolfcrypt/test/test.c,doc/dox_comments/header_files/random.h: renamenoncetoaddInin reseedAPIs, for consistent naming of "additional" data as such.
tests/api/test_random.c,tests/unit-mcdc/test_random_fault_whitebox.c,tests/unit-mcdc/test_random_whitebox.c: renamenoncetoaddInin reseed APIs..github/workflows/codespell.yml: add "addIn" to ignore_words_list.wolfssl/wolfcrypt/wc_port.h,wolfcrypt/src/wc_port.c: addwolfSSL_Atomic_Func_Ptr_CompareExchange()-- casting wrapper aroundwolfSSL_Atomic_Ptr_CompareExchange().RNG: add auxiliary invalidation pathway, both sender-side and receiver-side.
wc_RNG_entropy_epoch_extra_inv_init()andwc_RNG_extra_entropy_epoch_init(), and associated callback types.current_entropy_epoch()and associated internal state.global_entropy_epochto usecurrent_entropy_epoch().wc_RNG_entropy_epoch_t(word64).struct wc_RNG_entropy_epoch_atomicand associated initializers.wc_RNG_entropy_epoch_export(),wc_RNG_entropy_epoch_import(), andwc_RNG_entropy_epoch_increment_atomic().Hash_DRBG_Reseed()and its callers to passcur_epochonly whendefined(WC_RNG_HAVE_ENTROPY_EPOCH).tested with