linuxkm/lkcapi_sha_glue.c, wolfcrypt/src/random.c, wolfcrypt/src/rng_bank.c,

wolfcrypt/test/test.c, wolfssl/wolfcrypt/random.h: fixes for a second batch
  of static-analysis findings.

* vmgenid fallback poller: search the ACPI IDs the kernel vmgenid driver
  matches -- "VMGENCTR" and "VM_GEN_COUNTER" -- rather than the spec's
  mixed-case spellings.  ACPICA upcases _HID/_CID strings when building
  the namespace and acpi_get_devices() matches by strcmp, so the old walk
  found QEMU only by its _HID and missed CID-only devices (Hyper-V, VMware).

* wc_linuxkm_drbg_generate(): in non-vector builds, drop local_bh_disable()
  around the blockable CAN_WAIT reseed and reinit operations and retake it
  after, mirroring the vector arm's release/reacquire bracket; the
  checkout's migrate_disable() persists across the sleep, preserving CPU
  pinning preemptibly.

* entropy daemon and sysfs stats dumps: gate the next-stir format fragments
  and arguments on WC_RNG_HAVE_NEXT_SEED.

* new WC_LKM_BANK_RBGC_FLAG (WC_RNG_BANK_FLAG_RBGC when WC_RNG_HAVE_RBGC,
  else WC_RNG_BANK_FLAG_NONE): keep LKCAPI functional without RBGC support
  compiled in.

* wc_rng_bank_init_nonce(): use (size_t)(-1) rather than SIZE_MAX in the
  allocation overflow check (C90 and NO_STDINT_H builds).

* wc_rng_bank_fini(): pre-scan all instances for WC_RNG_LOCK_HELD before any
  mutation, returning BUSY_E (retryable) with refcount untouched, free hook
  unfired, and root intact.

* random.h: #error on WC_RNG_DEBUG_STATS without the RNG lock facility.

* wc_RNG_DRBG_Stir_Nonce(): reject nonce == NULL with nonzero nonceSz
  (BAD_FUNC_ARG), matching the other nonce-bearing APIs.

* random_bank_test(): hoist held_inst to function scope and check it in
  from the shared teardown path, closing a leak on failing assertions.

* wc_RNG_DRBG_NextSeedGenerate_local(): pointer declaration style cleanup.
pull/11435/head
Daniel Pouzzner 2026-09-16 17:55:36 -05:00
parent 5ba5b5cbe1
commit 60f220abfd
5 changed files with 90 additions and 20 deletions

View File

@ -2182,6 +2182,12 @@ static int linuxkm_affinity_unlock(void *arg) {
#define WC_LINUXKM_ENTROPY_DAEMON_MAGIC 0x6f77666c
#ifdef WC_RNG_HAVE_RBGC
#define WC_LKM_BANK_RBGC_FLAG WC_RNG_BANK_FLAG_RBGC
#else
#define WC_LKM_BANK_RBGC_FLAG WC_RNG_BANK_FLAG_NONE
#endif
#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \
defined(WC_RNG_HAVE_FREE_HOOK) && defined(WC_RNG_HAVE_LOCK)
@ -2336,7 +2342,7 @@ static int wc_linuxkm_rng_state_invalidate(void) {
obj->bank, 0, -1,
(byte *)&uncredited_nonce, (word32)sizeof uncredited_nonce,
WC_LINUXKM_INITRNG_TIMEOUT_SEC,
WC_RNG_BANK_FLAG_CAN_WAIT | WC_RNG_BANK_FLAG_RBGC);
WC_RNG_BANK_FLAG_CAN_WAIT | WC_LKM_BANK_RBGC_FLAG);
ForceZero(&uncredited_nonce, (word32)sizeof uncredited_nonce);
if ((this_ret != 0) && (ret == 0))
ret = this_ret;
@ -2592,15 +2598,18 @@ static void wc_linuxkm_vmgenid_poll(struct wc_linuxkm_vmgenid_poll_state *st,
WC_RNG *local_root)
{
if (st->state == 0) {
/* one-time discovery, in daemon task context. The device's _CID
* is "VM_Gen_Counter" per the Microsoft spec (QEMU adds _HID
* "QEMUVGID"); acpi_get_devices() matches against both HID and
* CID lists. */
/* one-time discovery, in daemon task context. ACPICA uppercases
* _HID/_CID strings when building the namespace, and
* acpi_get_devices() matches by strcmp, so the IDs here mirror
* the kernel vmgenid driver's own table verbatim: "VMGENCTR"
* (Microsoft spec _HID) and "VM_GEN_COUNTER" (the _CID as
* stored -- QEMU, Hyper-V, VMware all present it). */
void *found = NULL;
(void)acpi_get_devices("VM_Gen_Counter", wc_linuxkm_vmgenid_acpi_cb,
(void)acpi_get_devices("VMGENCTR", wc_linuxkm_vmgenid_acpi_cb,
st, &found);
if (found == NULL)
(void)acpi_get_devices("QEMUVGID", wc_linuxkm_vmgenid_acpi_cb,
(void)acpi_get_devices("VM_GEN_COUNTER",
wc_linuxkm_vmgenid_acpi_cb,
st, &found);
if (found != NULL) {
memcpy(st->last, st->map, 16);
@ -2845,7 +2854,7 @@ static int wc_linuxkm_entropy_daemon(void *arg)
continue;
}
ret = wc_rng_bank_recover_inst(bank, i, 0 /* timeout_secs */,
WC_RNG_BANK_FLAG_RBGC |
WC_LKM_BANK_RBGC_FLAG |
WC_RNG_BANK_FLAG_AUTO_RECOVER_AND_PROMOTE);
if (ret == 0) {
(void)wc_rng_bank_inst_flags_down(
@ -3060,16 +3069,23 @@ static int wc_linuxkm_entropy_daemon(void *arg)
" reseeds=" WC_RNG_STAT_FMT
" stirs=" WC_RNG_STAT_FMT
" seed_failures=" WC_RNG_STAT_FMT "\n"
#ifdef WC_RNG_HAVE_NEXT_SEED
" nextstirs_banked=" WC_RNG_STAT_FMT
" nextstirs_redeemed=" WC_RNG_STAT_FMT "\n",
" nextstirs_redeemed=" WC_RNG_STAT_FMT "\n"
#endif
,
s._stats_total_bytes_requested,
s._stats_total_bytes_produced,
s._stats_total_requests,
s._stats_reseeds,
s._stats_stirs,
s._stats_seed_failures,
s._stats_seed_failures
#ifdef WC_RNG_HAVE_NEXT_SEED
,
s._stats_nextstirs_banked,
s._stats_nextstirs_redeemed);
s._stats_nextstirs_redeemed
#endif
);
}
#endif /* WC_RNG_DEBUG_STATS */
#ifdef WC_LINUXKM_VMGENID_POLL
@ -3086,7 +3102,7 @@ static int wc_linuxkm_rng_bank_init(struct wc_rng_bank *ctx)
{
int ret;
word32 flags = WC_RNG_BANK_FLAG_CAN_WAIT | WC_RNG_BANK_FLAG_AUTO_RECOVER_AND_PROMOTE |
WC_RNG_BANK_FLAG_NO_CHECKOUT_REFCOUNTING | WC_RNG_BANK_FLAG_RBGC;
WC_RNG_BANK_FLAG_NO_CHECKOUT_REFCOUNTING | WC_LKM_BANK_RBGC_FLAG;
unsigned long uncredited_nonce = random_get_entropy();
if (wc_linuxkm_rng_initing_default_bank_flag && (default_bank != NULL)) {
@ -3240,16 +3256,23 @@ static void wc_linuxkm_rng_dump_stats(struct wc_rng_bank *ctx)
" reseeds=" WC_RNG_STAT_FMT
" stirs=" WC_RNG_STAT_FMT
" seed_failures=" WC_RNG_STAT_FMT "\n"
#ifdef WC_RNG_HAVE_NEXT_SEED
" stirs_banked=" WC_RNG_STAT_FMT
" stirs_redeemed=" WC_RNG_STAT_FMT "\n",
" stirs_redeemed=" WC_RNG_STAT_FMT "\n"
#endif
,
s._stats_total_bytes_requested,
s._stats_total_bytes_produced,
s._stats_total_requests,
s._stats_reseeds,
s._stats_stirs,
s._stats_seed_failures,
s._stats_seed_failures
#ifdef WC_RNG_HAVE_NEXT_SEED
,
s._stats_nextstirs_banked,
s._stats_nextstirs_redeemed);
s._stats_nextstirs_redeemed
#endif
);
}
}
@ -3653,6 +3676,16 @@ static int wc_linuxkm_drbg_generate(struct wc_rng_bank *ctx,
}
#endif
#ifndef WOLFSSL_USE_SAVE_VECTOR_REGISTERS
/* The non-vector checkout hold is migrate_disable() +
* local_bh_disable(). Only BH-off blocks sleeping; drop it for
* the blockable reseed and retake it after. The checkout's
* migrate_disable() legally persists across the sleep,
* preserving the CPU pinning preemptibly -- the same property
* the vector arm's migrate_disable() bracket provides. */
local_bh_enable();
#endif
/* Reseed synchronously. wc_RNG_DRBG_Reseed_Now() resets the reseed
* counter iff the reseed succeeds; on failure it leaves the counter
* unmodified (the WC_RESEED_INTERVAL backstop still governs) and
@ -3702,6 +3735,9 @@ static int wc_linuxkm_drbg_generate(struct wc_rng_bank *ctx,
#if defined(CONFIG_SMP) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0))
migrate_enable();
#endif
#else /* !WOLFSSL_USE_SAVE_VECTOR_REGISTERS */
/* retake the checkout's BH-off hold. */
local_bh_disable();
#endif
}
}
@ -3760,6 +3796,12 @@ static int wc_linuxkm_drbg_generate(struct wc_rng_bank *ctx,
if (lock_state & WC_RNG_BANK_INST_LOCK_AFFINITY_LOCKED)
RESTORE_VECTOR_REGISTERS_MAYBE_INHIBITED();
}
#else /* !WOLFSSL_USE_SAVE_VECTOR_REGISTERS */
/* The non-vector checkout hold is migrate_disable() +
* local_bh_disable(). Only BH-off blocks sleeping; drop it for
* the blockable reinit and retake it after (see the reseed leg
* above). */
local_bh_enable();
#endif
ret = wc_rng_bank_inst_reinit(NULL, drbg,
@ -3795,6 +3837,9 @@ static int wc_linuxkm_drbg_generate(struct wc_rng_bank *ctx,
#if defined(CONFIG_SMP) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0))
migrate_enable();
#endif
#else /* !WOLFSSL_USE_SAVE_VECTOR_REGISTERS */
/* retake the checkout's BH-off hold. */
local_bh_disable();
#endif
if (ret == 0) {

View File

@ -2304,6 +2304,8 @@ int wc_RNG_DRBG_Stir_Nonce(WC_RNG* rng,
{
if (rng == NULL || seed == NULL)
return BAD_FUNC_ARG;
if ((nonce == NULL) && (nonceSz != 0))
return BAD_FUNC_ARG;
if (rng->status != WC_DRBG_OK)
return RNG_FAILURE_E;
@ -4734,13 +4736,13 @@ static WARN_UNUSED_RESULT WC_INLINE int NextStirPtrs(WC_RNG* rng, byte** seed,
* test's error, leaving an empty bank for the next cycle. A gather failure
* leaves the partial bank intact for retry. */
static WARN_UNUSED_RESULT int wc_RNG_DRBG_NextSeedGenerate_local(
WC_RNG* rng, WC_RNG *root,
const byte *nonce, word32 n)
WC_RNG* rng, WC_RNG* root,
const byte* nonce, word32 n)
{
int claim_ret;
byte* seed = NULL;
wolfSSL_Atomic_Int* lenp = NULL;
int *nextSeedRBGCStratum_p = NULL;
int* nextSeedRBGCStratum_p = NULL;
WC_ATOMIC_INT_ARG cur;
word32 nextSeedSz = 0;
int ret;

View File

@ -105,7 +105,7 @@ WOLFSSL_API int wc_rng_bank_init_nonce(
/* the allocation below is sizeof(*ctx->rngs) * n_rngs; on targets where
* size_t is narrow enough for that product to wrap, the initialization
* loop would then run off the end of an undersized array. */
if ((size_t)n_rngs > (SIZE_MAX / sizeof(*ctx->rngs)))
if ((size_t)n_rngs > ((size_t)(-1) / sizeof(*ctx->rngs)))
return BAD_LENGTH_E;
XMEMSET(ctx, 0, sizeof(*ctx));
@ -354,6 +354,21 @@ WOLFSSL_API int wc_rng_bank_fini(struct wc_rng_bank *ctx) {
else if (wolfSSL_RefCur(ctx->refcount) < 1)
return BAD_STATE_E;
#ifndef WC_RNG_BANK_STATIC
if (ctx->rngs)
#endif
{
/* A held instance aborts finalization with the bank fully intact --
* refcount untouched, free hook unfired, root alive. BUSY_E: another
* actor holds a lease, definitively retryable. */
for (i = 0; i < ctx->n_rngs; ++i) {
WC_RNG_lock_arg_t pre_lock_state = 0;
(void)wc_rng_bank_inst_lock_read(&ctx->rngs[i], &pre_lock_state);
if (pre_lock_state & WC_RNG_LOCK_HELD)
return BUSY_E;
}
}
wolfSSL_RefDec_IfEquals(&ctx->refcount, 1, &new_refcount, &ret);
if (ret != 0) {
#ifdef WC_VERBOSE_RNG

View File

@ -28012,6 +28012,7 @@ static int rng_bank_affinity_unlock(void *arg) {
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void)
{
struct wc_rng_bank_inst *held_inst = NULL;
int ret;
WC_DECLARE_VAR(bank, struct wc_rng_bank, 1, HEAP_HINT);
struct wc_rng_bank_inst *rng_inst = NULL;
@ -28193,7 +28194,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
{
struct wc_rng_bank_inst *stale_inst = rng_inst;
struct wc_rng_bank_inst *held_inst = NULL;
/* held_inst hoisted to function scope (teardown checks in). */
ret = wc_rng_bank_checkout(bank, &held_inst, 2, 10,
WC_RNG_BANK_FLAG_NONE);
if (ret != 0)
@ -29126,6 +29127,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void)
out:
if (held_inst != NULL)
(void)wc_rng_bank_inst_checkin(&held_inst);
{
int cleanup_ret;

View File

@ -477,6 +477,10 @@ wc_static_assert(WC_RNG_RBGC_USER_SEED_STRATUM >= 256);
#define WC_RNG_DEBUG_STATS
#endif
#if defined(WC_RNG_DEBUG_STATS) && !defined(WC_RNG_HAVE_LOCK)
#error WC_RNG_DEBUG_STATS requires the RNG lock facility (WC_RNG_WANT_LOCK).
#endif
#ifdef WC_RNG_DEBUG_STATS
#ifdef WORD64_AVAILABLE
typedef word64 wc_rng_debug_counter_t;