1
0
mirror of https://github.com/wolfSSL/wolfssl.git synced 2026-10-24 04:09:07 +03:00

linuxkm/lkcapi_sha_glue.c, linuxkm/module_hooks.c:

Fixes for RNG invalidation handling, WC_RNG_BANK_HAVE_ROOT_RNG gating, and
CONFIG_PREEMPT_RT preemption balance:

* Pivot on WC_RNG_BANK_HAVE_ROOT_RNG for the entropy daemon's root_rng
  setup/teardown, the root stats dump, and the invalidation pre/post checks,
  replacing hand-spelled feature disjunctions -- glue now follows root_rng
  member existence exactly, including the WC_RNG_HAVE_LOCK-only configs the
  old spellings missed, and root-less configs now compile the affected
  functions cleanly.

* Wipe staged output on invalidation in the user-facing paths:
  wc_get_random_bytes_user() and wc_extract_crng_user() now ForceZero the
  staged block on EAGAIN before the post-check.  Bytes generated before an
  invalidation was noticed may be live in a forked VM; wc__get_random_bytes()
  already wiped, the user paths did not.

* Rework invalidation retry in wc__get_random_bytes(): retire the ad-hoc
  1-second jiffies window in favor of rng_invalidation_post_check() as the
  single bounding authority -- EAGAIN retries, anything else is terminal
  (-ETIMEDOUT/-EBUSY/-EINTR from the post-check) -- matching the user-facing
  paths.

* WC_DRBG_NEXT_STIR_LEN -> WC_RNG_NEXT_STIR_LEN ripple in
  wc_mix_pool_bytes(); root stats label "wc_entropyd root" -> "default bank
  root" (the stats are the bank's root's, daemon or no daemon).

* wc_lkm_LockMutex(): latch wc_linuxkm_can_block() once at entry (the
  caller's context is the disposition that matters, and the function itself
  toggles preemption), and on CONFIG_PREEMPT_RT kernels skip the
  post-trylock preempt_enable() -- RT spin_trylock() does not disable
  preemption, so re-enabling underflowed the preempt count.
This commit is contained in:
Daniel Pouzzner
2026-09-22 14:07:59 -05:00
parent 3ecfc6df16
commit 189e01e35e
2 changed files with 46 additions and 23 deletions

View File

@@ -2813,8 +2813,7 @@ static int wc_linuxkm_entropy_daemon(void *arg)
struct WC_RNG *root_rng;
int root_rng_reseed_countdown = 0;
#if defined(WC_RNG_HAVE_RBGC) || defined(WC_RNG_HAVE_NEXT_SEED) || \
defined(WC_RNG_HAVE_POOL)
#ifdef WC_RNG_BANK_HAVE_ROOT_RNG
root_rng = wc_rng_bank_root_rng_get(bank);
#else
root_rng = (struct WC_RNG *)malloc(sizeof(*root_rng));
@@ -2941,8 +2940,7 @@ static int wc_linuxkm_entropy_daemon(void *arg)
inv_ret = wc_FreeRng(root_rng);
if (inv_ret == 0) {
#if defined(WC_RNG_HAVE_RBGC) || defined(WC_RNG_HAVE_NEXT_SEED) || \
defined(WC_RNG_HAVE_POOL)
#ifdef WC_RNG_BANK_HAVE_ROOT_RNG
inv_ret = wc_rng_bank_root_rng_init(
bank,
(byte *)&uncredited_nonce, (word32)sizeof uncredited_nonce,
@@ -3252,8 +3250,7 @@ static int wc_linuxkm_entropy_daemon(void *arg)
#endif
}
#if !(defined(WC_RNG_HAVE_RBGC) || defined(WC_RNG_HAVE_NEXT_SEED) || \
defined(WC_RNG_HAVE_POOL))
#ifndef WC_RNG_BANK_HAVE_ROOT_RNG
if (root_rng != NULL) {
wc_FreeRng(root_rng);
free(root_rng);
@@ -3412,12 +3409,13 @@ static void wc_linuxkm_rng_dump_stats(struct wc_rng_bank *ctx)
{
struct wc_rng_debug_stats_snapshot s;
#ifdef WC_RNG_BANK_HAVE_ROOT_RNG
{
WC_RNG *root_rng = wc_rng_bank_root_rng_get(ctx);
if ((root_rng != NULL) &&
(wc_rng_debug_stats_snap(&s, root_rng) == 0))
{
pr_info("RNG INFO: wc_entropyd root total_bytes_requested=" WC_RNG_STAT_FMT "\n"
pr_info("RNG INFO: default bank root total_bytes_requested=" WC_RNG_STAT_FMT "\n"
" total_bytes_produced=" WC_RNG_STAT_FMT
" total_requests=" WC_RNG_STAT_FMT "\n"
" reseeds=" WC_RNG_STAT_FMT
@@ -3442,6 +3440,7 @@ static void wc_linuxkm_rng_dump_stats(struct wc_rng_bank *ctx)
);
}
}
#endif /* WC_RNG_BANK_HAVE_ROOT_RNG */
if (wc_rng_bank_debug_stats_snap(&s, ctx) == 0) {
pr_info("RNG INFO: default bank size=%d total_bytes_requested=" WC_RNG_STAT_FMT "\n"
@@ -4192,7 +4191,7 @@ static int wc__get_random_bytes(void *buf, size_t len)
}
else {
#ifdef WC_LINUXKM_HAVE_RNG_INVALIDATION
#if defined(WC_LINUXKM_HAVE_RNG_INVALIDATION) && defined(WC_RNG_BANK_HAVE_ROOT_RNG)
/* if in a recovery window, defer the request until done, if possible. */
try_again:
@@ -4202,21 +4201,22 @@ static int wc__get_random_bytes(void *buf, size_t len)
(void)wc_rng_bank_default_checkin(&current_default_wc_rng_bank);
return ret;
}
#endif /* WC_LINUXKM_HAVE_RNG_INVALIDATION */
#endif /* WC_LINUXKM_HAVE_RNG_INVALIDATION && WC_RNG_BANK_HAVE_ROOT_RNG */
ret = wc_linuxkm_drbg_generate(current_default_wc_rng_bank,
NULL, 0, buf, (unsigned int)len, 0 /* pr */);
#ifdef WC_LINUXKM_HAVE_RNG_INVALIDATION
if ((ret == -WC_NO_ERR_TRACE(EAGAIN)) &&
(jiffies_to_msecs(jiffies - last_invalidation_at) < 1000))
{
#if defined(WC_LINUXKM_HAVE_RNG_INVALIDATION) && defined(WC_RNG_BANK_HAVE_ROOT_RNG)
if (ret == -WC_NO_ERR_TRACE(EAGAIN)) {
/* An invalidation may be unique to this VM, leaving these bytes
* live in another VM -- wipe them here. */
ForceZero(buf, (word32)len);
goto try_again;
ret = rng_invalidation_post_check(__func__, ret);
if (ret == -WC_NO_ERR_TRACE(EAGAIN))
goto try_again;
/* else terminal: -ETIMEDOUT/-EBUSY/-EINTR from the post-check. */
}
#endif /* WC_LINUXKM_HAVE_RNG_INVALIDATION */
#endif /* WC_LINUXKM_HAVE_RNG_INVALIDATION && WC_RNG_BANK_HAVE_ROOT_RNG */
(void)wc_rng_bank_default_checkin(&current_default_wc_rng_bank);
if (ret != 0) {
@@ -4253,11 +4253,13 @@ static ssize_t wc_get_random_bytes_user(struct iov_iter *iter) {
return -EIO; /* no fallthrough to native randomness */
}
#if defined(WC_LINUXKM_HAVE_RNG_INVALIDATION) && defined(WC_RNG_BANK_HAVE_ROOT_RNG)
ret = rng_invalidation_pre_check(&current_default_wc_rng_bank->root_rng, iov_iter_count(iter));
if (ret != 0) {
(void)wc_rng_bank_default_checkin(&current_default_wc_rng_bank);
return ret;
}
#endif
{
size_t this_copied, total_copied = 0;
@@ -4280,9 +4282,14 @@ static ssize_t wc_get_random_bytes_user(struct iov_iter *iter) {
size_t n = min_t(size_t, iov_iter_count(iter), block_size);
ret = wc_linuxkm_drbg_generate(current_default_wc_rng_bank,
NULL, 0, block, n, 0 /* pr */);
ret = rng_invalidation_post_check(__func__, ret);
#if defined(WC_LINUXKM_HAVE_RNG_INVALIDATION) && defined(WC_RNG_BANK_HAVE_ROOT_RNG)
if (ret == -WC_NO_ERR_TRACE(EAGAIN))
ForceZero(block, n);
ret = rng_invalidation_post_check(__func__, ret);
if (ret == -WC_NO_ERR_TRACE(EAGAIN)) {
continue;
}
#endif
if (unlikely(ret != 0)) {
if (ret != -WC_NO_ERR_TRACE(EINTR)) {
pr_emerg_ratelimited(
@@ -4346,11 +4353,13 @@ static ssize_t wc_extract_crng_user(void __user *buf, size_t nbytes) {
return -EIO; /* no fallthrough to native randomness */
}
#if defined(WC_LINUXKM_HAVE_RNG_INVALIDATION) && defined(WC_RNG_BANK_HAVE_ROOT_RNG)
ret = rng_invalidation_pre_check(&current_default_wc_rng_bank->root_rng, nbytes);
if (ret != 0) {
(void)wc_rng_bank_default_checkin(&current_default_wc_rng_bank);
return ret;
}
#endif
{
size_t this_copied, total_copied = 0;
@@ -4373,9 +4382,13 @@ static ssize_t wc_extract_crng_user(void __user *buf, size_t nbytes) {
size_t n = min_t(size_t, nbytes - total_copied, block_size);
ret = wc_linuxkm_drbg_generate(current_default_wc_rng_bank,
NULL, 0, block, n, 0 /* pr */);
#if defined(WC_LINUXKM_HAVE_RNG_INVALIDATION) && defined(WC_RNG_BANK_HAVE_ROOT_RNG)
if (ret == -WC_NO_ERR_TRACE(EAGAIN))
ForceZero(block, n);
ret = rng_invalidation_post_check(__func__, ret);
if (ret == -WC_NO_ERR_TRACE(EAGAIN))
continue;
#endif
if (unlikely(ret != 0)) {
if (ret != -WC_NO_ERR_TRACE(EINTR)) {
pr_emerg_ratelimited(
@@ -4442,8 +4455,8 @@ static int wc_mix_pool_bytes(const void *buf, size_t len) {
if (! can_sleep) {
#ifdef WC_RNG_HAVE_NEXT_SEED
if (len > WC_DRBG_NEXT_STIR_LEN)
len = WC_DRBG_NEXT_STIR_LEN;
if (len > WC_RNG_NEXT_STIR_LEN)
len = WC_RNG_NEXT_STIR_LEN;
#else
if (len > 64)
len = 64;
@@ -4464,7 +4477,7 @@ static int wc_mix_pool_bytes(const void *buf, size_t len) {
WC_RNG *stir_root = wc_rng_bank_root_rng_get(ctx);
/* Small input, fast path: lock-free XMEMCPY/xorbuf. */
if (len <= WC_DRBG_NEXT_STIR_LEN) {
if (len <= WC_RNG_NEXT_STIR_LEN) {
static DEFINE_PER_CPU(int, stir_index) = -2;
int this_index = this_cpu_inc_return(stir_index);
/* at startup, stagger them across the bank, to get wider spread and
@@ -4490,13 +4503,13 @@ static int wc_mix_pool_bytes(const void *buf, size_t len) {
}
if (stir_root != NULL) {
/* note that input beyond WC_DRBG_NEXT_STIR_LEN is discarded. */
/* note that input beyond WC_RNG_NEXT_STIR_LEN is discarded. */
(void)wc_RNG_DRBG_NextStirStore(stir_root, (const byte *)buf,
(word32)len);
}
}
if (len > WC_DRBG_NEXT_STIR_LEN)
if (len > WC_RNG_NEXT_STIR_LEN)
#endif /* WC_RNG_HAVE_NEXT_SEED */
{
word32 flags =

View File

@@ -292,6 +292,8 @@ extern int wolfcrypt_benchmark_main(int argc, char** argv);
#ifndef WOLFSSL_LINUXKM_USE_MUTEXES
int wc_lkm_LockMutex(wolfSSL_Mutex* m)
{
int can_block = wc_linuxkm_can_block();
#ifdef WC_LINUXKM_SPIN_IN_ATOMIC
unsigned long irq_flags;
#endif
@@ -309,16 +311,20 @@ int wc_lkm_LockMutex(wolfSSL_Mutex* m)
}
#else
if (spin_trylock(&m->lock)) {
if (wc_linuxkm_can_block()) {
#if !IS_ENABLED(CONFIG_PREEMPT_RT)
/* On CONFIG_PREEMPT_RT kernels, spin_trylock() does not disable
* preemption, so don't re-enable it. */
if (can_block) {
preempt_enable();
m->preempt_reenabled = 1;
}
#endif
return 0;
}
#endif
if (in_nmi())
return BUSY_E;
if (! wc_linuxkm_can_block()) {
if (! can_block) {
#ifndef WC_LINUXKM_SPIN_IN_ATOMIC
/* RT spinlock_t is a sleeping rtmutex; an atomic caller has no legal
* wait -- the entry trylock was its one shot. */
@@ -365,8 +371,12 @@ int wc_lkm_LockMutex(wolfSSL_Mutex* m)
* otherwise deadlocks are inevitable.
*/
if (spin_trylock(&m->lock)) {
#if !IS_ENABLED(CONFIG_PREEMPT_RT)
/* On CONFIG_PREEMPT_RT kernels, spin_trylock() does not disable
* preemption, so don't re-enable it. */
preempt_enable();
m->preempt_reenabled = 1;
#endif
return 0;
}
#endif