From fe33bb9bd968b604b9b2e448a7f31c2a33cc3bf8 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Wed, 10 Dec 2025 20:33:48 -0600 Subject: [PATCH] linuxkm/lkcapi_sha_glue.c: * in get_drbg(), call local_bh_disable() for the crypto_default_rng, and in put_drbg(), call local_bh_enable() if needed. * re-gate migrate_disable() and migrate_enable() so they're called for any SMP kernel >= 5.7, regardless of CONFIG_PREEMPT_COUNT. * in get_drbg_n(), if the caller can't sleep, return immediately if the requested DRBG is busy, to avoid priority inversions and deadlocks. --- linuxkm/lkcapi_sha_glue.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/linuxkm/lkcapi_sha_glue.c b/linuxkm/lkcapi_sha_glue.c index 1819fad7a..ef14524a4 100644 --- a/linuxkm/lkcapi_sha_glue.c +++ b/linuxkm/lkcapi_sha_glue.c @@ -1073,17 +1073,17 @@ static inline struct wc_rng_inst *get_drbg(struct crypto_rng *tfm) { return NULL; } - #if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_COUNT) && \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) if (tfm == crypto_default_rng) { + #if defined(CONFIG_SMP) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) migrate_disable(); /* this actually makes irq_count() nonzero, so that * DISABLE_VECTOR_REGISTERS() is superfluous, but * don't depend on that. */ + #endif + local_bh_disable(); new_lock_value = 2; } else - #endif { new_lock_value = 1; } @@ -1104,7 +1104,9 @@ static inline struct wc_rng_inst *get_drbg(struct crypto_rng *tfm) { } /* get_drbg_n() is used by bulk seed, mix-in, and reseed operations. It expects - * the caller to be able to wait until the requested DRBG is available. + * the caller to be able to wait until the requested DRBG is available. If the + * caller can't sleep and the requested DRBG is busy, it returns immediately -- + * this avoids priority inversions and deadlocks. */ static inline struct wc_rng_inst *get_drbg_n(struct wc_linuxkm_drbg_ctx *ctx, int n) { int can_sleep = (preempt_count() == 0); @@ -1119,23 +1121,22 @@ static inline struct wc_rng_inst *get_drbg_n(struct wc_linuxkm_drbg_ctx *ctx, in cond_resched(); } else - cpu_relax(); + return NULL; } __builtin_unreachable(); } static inline void put_drbg(struct wc_rng_inst *drbg) { - #if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_COUNT) && \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) int migration_disabled = (drbg->lock == 2); - #endif __atomic_store_n(&(drbg->lock),0,__ATOMIC_RELEASE); - #if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_COUNT) && \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) - if (migration_disabled) + + if (migration_disabled) { + local_bh_enable(); + #if defined(CONFIG_SMP) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) migrate_enable(); - #endif + #endif + } } static int wc_linuxkm_drbg_generate(struct crypto_rng *tfm,