Skip to content

Commit a40b56c

Browse files
authored
Merge pull request #8964 from douzzer/20250703-linuxkm-fixes
20250703-linuxkm-fixes Note, final commit reviewed by @SparkiDev, and earlier commit reviewed by @philljj.
2 parents fb691fa + ef3a1a2 commit a40b56c

File tree

6 files changed

+136
-32
lines changed

6 files changed

+136
-32
lines changed

linuxkm/linuxkm_wc_port.h

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@
126126

127127
#if defined(__PIE__) && defined(CONFIG_ARM64)
128128
#define alt_cb_patch_nops my__alt_cb_patch_nops
129+
#define queued_spin_lock_slowpath my__queued_spin_lock_slowpath
129130
#endif
130131

131132
#include <linux/kernel.h>
@@ -705,20 +706,30 @@
705706

706707
#ifdef CONFIG_ARM64
707708
#ifdef __PIE__
708-
/* alt_cb_patch_nops defined early to allow shimming in system
709-
* headers, but now we need the native one.
709+
/* alt_cb_patch_nops and queued_spin_lock_slowpath are defined early
710+
* to allow shimming in system headers, but now we need the native
711+
* ones.
710712
*/
711713
#undef alt_cb_patch_nops
712714
typeof(my__alt_cb_patch_nops) *alt_cb_patch_nops;
715+
#undef queued_spin_lock_slowpath
716+
typeof(my__queued_spin_lock_slowpath) *queued_spin_lock_slowpath;
713717
#else
714718
typeof(alt_cb_patch_nops) *alt_cb_patch_nops;
719+
typeof(queued_spin_lock_slowpath) *queued_spin_lock_slowpath;
715720
#endif
716721
#endif
717722

718723
typeof(preempt_count) *preempt_count;
719-
typeof(_raw_spin_lock_irqsave) *_raw_spin_lock_irqsave;
720-
typeof(_raw_spin_trylock) *_raw_spin_trylock;
721-
typeof(_raw_spin_unlock_irqrestore) *_raw_spin_unlock_irqrestore;
724+
#ifndef _raw_spin_lock_irqsave
725+
typeof(_raw_spin_lock_irqsave) *_raw_spin_lock_irqsave;
726+
#endif
727+
#ifndef _raw_spin_trylock
728+
typeof(_raw_spin_trylock) *_raw_spin_trylock;
729+
#endif
730+
#ifndef _raw_spin_unlock_irqrestore
731+
typeof(_raw_spin_unlock_irqrestore) *_raw_spin_unlock_irqrestore;
732+
#endif
722733
typeof(_cond_resched) *_cond_resched;
723734

724735
const void *_last_slot;
@@ -885,9 +896,19 @@
885896

886897
#undef preempt_count /* just in case -- not a macro on x86. */
887898
#define preempt_count (wolfssl_linuxkm_get_pie_redirect_table()->preempt_count)
888-
#define _raw_spin_lock_irqsave (wolfssl_linuxkm_get_pie_redirect_table()->_raw_spin_lock_irqsave)
889-
#define _raw_spin_trylock (wolfssl_linuxkm_get_pie_redirect_table()->_raw_spin_trylock)
890-
#define _raw_spin_unlock_irqrestore (wolfssl_linuxkm_get_pie_redirect_table()->_raw_spin_unlock_irqrestore)
899+
900+
#ifndef WOLFSSL_LINUXKM_USE_MUTEXES
901+
#ifndef _raw_spin_lock_irqsave
902+
#define _raw_spin_lock_irqsave (wolfssl_linuxkm_get_pie_redirect_table()->_raw_spin_lock_irqsave)
903+
#endif
904+
#ifndef _raw_spin_trylock
905+
#define _raw_spin_trylock (wolfssl_linuxkm_get_pie_redirect_table()->_raw_spin_trylock)
906+
#endif
907+
#ifndef _raw_spin_unlock_irqrestore
908+
#define _raw_spin_unlock_irqrestore (wolfssl_linuxkm_get_pie_redirect_table()->_raw_spin_unlock_irqrestore)
909+
#endif
910+
#endif
911+
891912
#define _cond_resched (wolfssl_linuxkm_get_pie_redirect_table()->_cond_resched)
892913

893914
/* this is defined in linux/spinlock.h as an inline that calls the unshimmed
@@ -991,8 +1012,8 @@
9911012

9921013
static inline int wc_LockMutex(wolfSSL_Mutex* m)
9931014
{
994-
if (in_nmi() || in_hardirq() || in_softirq())
995-
return BAD_STATE_E;
1015+
if (in_nmi() || hardirq_count() || in_softirq())
1016+
return -1;
9961017
mutex_lock(m);
9971018
return 0;
9981019
}

linuxkm/lkcapi_sha_glue.c

Lines changed: 72 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,7 @@ struct wc_swallow_the_semicolon
940940
#include <wolfssl/wolfcrypt/random.h>
941941

942942
struct wc_linuxkm_drbg_ctx {
943+
size_t n_rngs;
943944
struct wc_rng_inst {
944945
wolfSSL_Atomic_Int lock;
945946
WC_RNG rng;
@@ -951,7 +952,7 @@ static inline void wc_linuxkm_drbg_ctx_clear(struct wc_linuxkm_drbg_ctx * ctx)
951952
unsigned int i;
952953

953954
if (ctx->rngs) {
954-
for (i = 0; i < nr_cpu_ids; ++i) {
955+
for (i = 0; i < ctx->n_rngs; ++i) {
955956
if (ctx->rngs[i].lock != 0) {
956957
/* better to leak than to crash. */
957958
pr_err("BUG: wc_linuxkm_drbg_ctx_clear called with DRBG #%d still locked.", i);
@@ -961,6 +962,7 @@ static inline void wc_linuxkm_drbg_ctx_clear(struct wc_linuxkm_drbg_ctx * ctx)
961962
}
962963
free(ctx->rngs);
963964
ctx->rngs = NULL;
965+
ctx->n_rngs = 0;
964966
}
965967

966968
return;
@@ -976,12 +978,15 @@ static int wc_linuxkm_drbg_init_tfm(struct crypto_tfm *tfm)
976978
int need_reenable_vec = 0;
977979
int can_sleep = (preempt_count() == 0);
978980

979-
ctx->rngs = (struct wc_rng_inst *)malloc(sizeof(*ctx->rngs) * nr_cpu_ids);
980-
if (! ctx->rngs)
981+
ctx->n_rngs = max(4, nr_cpu_ids);
982+
ctx->rngs = (struct wc_rng_inst *)malloc(sizeof(*ctx->rngs) * ctx->n_rngs);
983+
if (! ctx->rngs) {
984+
ctx->n_rngs = 0;
981985
return -ENOMEM;
982-
XMEMSET(ctx->rngs, 0, sizeof(*ctx->rngs) * nr_cpu_ids);
986+
}
987+
XMEMSET(ctx->rngs, 0, sizeof(*ctx->rngs) * ctx->n_rngs);
983988

984-
for (i = 0; i < nr_cpu_ids; ++i) {
989+
for (i = 0; i < ctx->n_rngs; ++i) {
985990
ctx->rngs[i].lock = 0;
986991
if (wc_linuxkm_drbg_init_tfm_disable_vector_registers)
987992
need_reenable_vec = (DISABLE_VECTOR_REGISTERS() == 0);
@@ -1015,10 +1020,29 @@ static void wc_linuxkm_drbg_exit_tfm(struct crypto_tfm *tfm)
10151020

10161021
static int wc_linuxkm_drbg_default_instance_registered = 0;
10171022

1023+
/* get_drbg() uses atomic operations to get exclusive ownership of a DRBG
1024+
* without delay. It expects to be called in uninterruptible context, though
1025+
* works fine in any context. It starts by trying the DRBG matching the current
1026+
* CPU ID, and if that doesn't immediately succeed, it iterates upward until one
1027+
* succeeds. The first attempt will always succeed, even under intense load,
1028+
* unless there is or has recently been a reseed or mix-in operation competing
1029+
* with generators.
1030+
*
1031+
* Note that wc_linuxkm_drbg_init_tfm() allocates at least 4 DRBGs, regardless
1032+
* of nominal core count, to avoid stalling generators on unicore targets.
1033+
*/
1034+
10181035
static inline struct wc_rng_inst *get_drbg(struct crypto_rng *tfm) {
10191036
struct wc_linuxkm_drbg_ctx *ctx = (struct wc_linuxkm_drbg_ctx *)crypto_rng_ctx(tfm);
10201037
int n, new_lock_value;
10211038

1039+
/* check for mismatched handler or missing instance array. */
1040+
if ((tfm->base.__crt_alg->cra_init != wc_linuxkm_drbg_init_tfm) ||
1041+
(ctx->rngs == NULL))
1042+
{
1043+
return NULL;
1044+
}
1045+
10221046
#if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_COUNT) && \
10231047
(LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0))
10241048
if (tfm == crypto_default_rng) {
@@ -1041,20 +1065,28 @@ static inline struct wc_rng_inst *get_drbg(struct crypto_rng *tfm) {
10411065
if (likely(__atomic_compare_exchange_n(&ctx->rngs[n].lock, &expected, new_lock_value, 0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE)))
10421066
return &ctx->rngs[n];
10431067
++n;
1044-
if (n >= (int)nr_cpu_ids)
1068+
if (n >= (int)ctx->n_rngs)
10451069
n = 0;
10461070
cpu_relax();
10471071
}
10481072

10491073
__builtin_unreachable();
10501074
}
10511075

1076+
/* get_drbg_n() is used by bulk seed, mix-in, and reseed operations. It expects
1077+
* the caller to be able to wait until the requested DRBG is available.
1078+
*/
10521079
static inline struct wc_rng_inst *get_drbg_n(struct wc_linuxkm_drbg_ctx *ctx, int n) {
1080+
int can_sleep = (preempt_count() == 0);
1081+
10531082
for (;;) {
10541083
int expected = 0;
10551084
if (likely(__atomic_compare_exchange_n(&ctx->rngs[n].lock, &expected, 1, 0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE)))
10561085
return &ctx->rngs[n];
1057-
cpu_relax();
1086+
if (can_sleep)
1087+
cond_resched();
1088+
else
1089+
cpu_relax();
10581090
}
10591091

10601092
__builtin_unreachable();
@@ -1078,17 +1110,18 @@ static int wc_linuxkm_drbg_generate(struct crypto_rng *tfm,
10781110
u8 *dst, unsigned int dlen)
10791111
{
10801112
int ret, retried = 0;
1081-
/* Note, core is not necessarily locked on entry, so the actual core ID may
1082-
* change while executing, hence the lock.
1083-
*
1084-
* The lock is also needed to coordinate with wc_linuxkm_drbg_seed(), which
1085-
* seeds all instances.
1086-
*/
1113+
int need_fpu_restore;
10871114
struct wc_rng_inst *drbg = get_drbg(tfm);
1115+
1116+
if (! drbg) {
1117+
pr_err_once("BUG: get_drbg() failed.");
1118+
return -EFAULT;
1119+
}
1120+
10881121
/* for the default RNG, make sure we don't cache an underlying SHA256
10891122
* method that uses vector insns (forbidden from irq handlers).
10901123
*/
1091-
int need_fpu_restore = (tfm == crypto_default_rng) ? (DISABLE_VECTOR_REGISTERS() == 0) : 0;
1124+
need_fpu_restore = (tfm == crypto_default_rng) ? (DISABLE_VECTOR_REGISTERS() == 0) : 0;
10921125

10931126
retry:
10941127

@@ -1138,6 +1171,13 @@ static int wc_linuxkm_drbg_seed(struct crypto_rng *tfm,
11381171
int ret;
11391172
int n;
11401173

1174+
if ((tfm->base.__crt_alg->cra_init != wc_linuxkm_drbg_init_tfm) ||
1175+
(ctx->rngs == NULL))
1176+
{
1177+
pr_err_once("BUG: mismatched tfm.");
1178+
return -EFAULT;
1179+
}
1180+
11411181
if (slen == 0)
11421182
return 0;
11431183

@@ -1146,7 +1186,10 @@ static int wc_linuxkm_drbg_seed(struct crypto_rng *tfm,
11461186
return -ENOMEM;
11471187
XMEMCPY(seed_copy + 2, seed, slen);
11481188

1149-
for (n = nr_cpu_ids - 1; n >= 0; --n) {
1189+
/* this iteration counts down, whereas the iteration in get_drbg() counts
1190+
* up, to assure they can't possibly phase-lock to each other.
1191+
*/
1192+
for (n = ctx->n_rngs - 1; n >= 0; --n) {
11501193
struct wc_rng_inst *drbg = get_drbg_n(ctx, n);
11511194

11521195
/* perturb the seed with the CPU ID, so that no DRBG has the exact same
@@ -1249,7 +1292,13 @@ static inline struct crypto_rng *get_crypto_default_rng(void) {
12491292

12501293
static inline struct wc_linuxkm_drbg_ctx *get_default_drbg_ctx(void) {
12511294
struct crypto_rng *current_crypto_default_rng = get_crypto_default_rng();
1252-
return current_crypto_default_rng ? (struct wc_linuxkm_drbg_ctx *)crypto_rng_ctx(current_crypto_default_rng) : NULL;
1295+
struct wc_linuxkm_drbg_ctx *ctx = (current_crypto_default_rng ? (struct wc_linuxkm_drbg_ctx *)crypto_rng_ctx(current_crypto_default_rng) : NULL);
1296+
if (ctx && (! ctx->rngs)) {
1297+
pr_err_once("BUG: get_default_drbg_ctx() found null ctx->rngs.");
1298+
return NULL;
1299+
}
1300+
else
1301+
return ctx;
12531302
}
12541303

12551304
static int wc__get_random_bytes(void *buf, size_t len)
@@ -1259,8 +1308,9 @@ static int wc__get_random_bytes(void *buf, size_t len)
12591308
return -EFAULT;
12601309
else {
12611310
int ret = crypto_rng_get_bytes(current_crypto_default_rng, buf, len);
1262-
if (ret)
1311+
if (ret) {
12631312
pr_warn("BUG: wc_get_random_bytes falling through to native get_random_bytes with wc_linuxkm_drbg_default_instance_registered, ret=%d.", ret);
1313+
}
12641314
return ret;
12651315
}
12661316
__builtin_unreachable();
@@ -1382,7 +1432,7 @@ static int wc_mix_pool_bytes(const void *buf, size_t len) {
13821432
if (! (ctx = get_default_drbg_ctx()))
13831433
return -EFAULT;
13841434

1385-
for (n = nr_cpu_ids - 1; n >= 0; --n) {
1435+
for (n = ctx->n_rngs - 1; n >= 0; --n) {
13861436
struct wc_rng_inst *drbg = get_drbg_n(ctx, n);
13871437
int V_offset = 0;
13881438

@@ -1406,7 +1456,7 @@ static int wc_crng_reseed(void) {
14061456
if (! ctx)
14071457
return -EFAULT;
14081458

1409-
for (n = nr_cpu_ids - 1; n >= 0; --n) {
1459+
for (n = ctx->n_rngs - 1; n >= 0; --n) {
14101460
struct wc_rng_inst *drbg = get_drbg_n(ctx, n);
14111461
((struct DRBG_internal *)drbg->rng.drbg)->reseedCtr = WC_RESEED_INTERVAL;
14121462
if (can_sleep) {
@@ -1786,6 +1836,7 @@ static int wc_linuxkm_drbg_startup(void)
17861836
}
17871837
else {
17881838
pr_err("ERROR: wolfssl_linuxkm_register_random_bytes_handlers() failed: %d\n", ret);
1839+
return ret;
17891840
}
17901841

17911842
#elif defined(WOLFSSL_LINUXKM_USE_GET_RANDOM_KPROBES)
@@ -1797,6 +1848,7 @@ static int wc_linuxkm_drbg_startup(void)
17971848
}
17981849
else {
17991850
pr_err("ERROR: wc_get_random_bytes_kprobe installation failed: %d\n", ret);
1851+
return ret;
18001852
}
18011853

18021854
#ifdef WOLFSSL_LINUXKM_USE_GET_RANDOM_USER_KRETPROBE
@@ -1807,6 +1859,7 @@ static int wc_linuxkm_drbg_startup(void)
18071859
}
18081860
else {
18091861
pr_err("ERROR: wc_get_random_bytes_user_kprobe installation failed: %d\n", ret);
1862+
return ret;
18101863
}
18111864
#endif /* WOLFSSL_LINUXKM_USE_GET_RANDOM_USER_KRETPROBE */
18121865

linuxkm/module_hooks.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,13 +658,20 @@ static int set_up_wolfssl_linuxkm_pie_redirect_table(void) {
658658
#endif
659659

660660
wolfssl_linuxkm_pie_redirect_table.preempt_count = my_preempt_count;
661+
#ifndef _raw_spin_lock_irqsave
661662
wolfssl_linuxkm_pie_redirect_table._raw_spin_lock_irqsave = _raw_spin_lock_irqsave;
663+
#endif
664+
#ifndef _raw_spin_trylock
662665
wolfssl_linuxkm_pie_redirect_table._raw_spin_trylock = _raw_spin_trylock;
666+
#endif
667+
#ifndef _raw_spin_unlock_irqrestore
663668
wolfssl_linuxkm_pie_redirect_table._raw_spin_unlock_irqrestore = _raw_spin_unlock_irqrestore;
669+
#endif
664670
wolfssl_linuxkm_pie_redirect_table._cond_resched = _cond_resched;
665671

666672
#ifdef CONFIG_ARM64
667673
wolfssl_linuxkm_pie_redirect_table.alt_cb_patch_nops = alt_cb_patch_nops;
674+
wolfssl_linuxkm_pie_redirect_table.queued_spin_lock_slowpath = queued_spin_lock_slowpath;
668675
#endif
669676

670677
/* runtime assert that the table has no null slots after initialization. */

linuxkm/patches/6.1.73/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-6v1v73.patch

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
--- ./drivers/char/random.c.dist 2024-01-19 16:25:03.754138321 -0600
2-
+++ ./drivers/char/random.c 2025-07-02 10:45:31.769041473 -0500
2+
+++ ./drivers/char/random.c 2025-07-03 15:51:24.282595676 -0500
33
@@ -60,6 +60,260 @@
44
#include <asm/irq_regs.h>
55
#include <asm/io.h>
@@ -426,7 +426,7 @@
426426
+ /* fall through to reseed native crng too. */
427427
+ if (call_crng_reseed_cb() == 0) {
428428
+ if (crng_ready())
429-
+ crng_reseed(NULL);
429+
+ crng_reseed();
430430
+ return 0;
431431
+ }
432432
+#endif

wolfcrypt/src/random.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1494,13 +1494,23 @@ static wolfSSL_Mutex entropy_mutex WOLFSSL_MUTEX_INITIALIZER_CLAUSE(entropy_mute
14941494
int wc_Entropy_Get(int bits, unsigned char* entropy, word32 len)
14951495
{
14961496
int ret = 0;
1497+
#ifdef WOLFSSL_SMALL_STACK
1498+
byte *noise = NULL;
1499+
#else
14971500
byte noise[MAX_NOISE_CNT];
1501+
#endif
14981502
/* Noise length is the number of 8 byte samples required to get the bits of
14991503
* entropy requested. */
15001504
int noise_len = (bits + ENTROPY_EXTRA) / ENTROPY_MIN;
15011505

1506+
#ifdef WOLFSSL_SMALL_STACK
1507+
noise = (byte *)XMALLOC(MAX_NOISE_CNT, NULL, DYNAMIC_TYPE_TMP_BUFFER);
1508+
if (noise == NULL)
1509+
return MEMORY_E;
1510+
#endif
1511+
15021512
/* Lock the mutex as collection uses globals. */
1503-
if (wc_LockMutex(&entropy_mutex) != 0) {
1513+
if ((ret == 0) && (wc_LockMutex(&entropy_mutex) != 0)) {
15041514
ret = BAD_MUTEX_E;
15051515
}
15061516

@@ -1558,6 +1568,10 @@ int wc_Entropy_Get(int bits, unsigned char* entropy, word32 len)
15581568
wc_UnLockMutex(&entropy_mutex);
15591569
}
15601570

1571+
#ifdef WOLFSSL_SMALL_STACK
1572+
XFREE(noise, NULL, DYNAMIC_TYPE_TMP_BUFFER);
1573+
#endif
1574+
15611575
return ret;
15621576
}
15631577

wolfcrypt/src/wc_port.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
#endif
2727

2828
#include <wolfssl/wolfcrypt/cpuid.h>
29+
#ifdef HAVE_ENTROPY_MEMUSE
30+
#include <wolfssl/wolfcrypt/random.h>
31+
#endif
2932
#ifdef HAVE_ECC
3033
#include <wolfssl/wolfcrypt/ecc.h>
3134
#endif
@@ -4628,4 +4631,10 @@ noinstr void my__alt_cb_patch_nops(struct alt_instr *alt, __le32 *origptr,
46284631
return (wolfssl_linuxkm_get_pie_redirect_table()->
46294632
alt_cb_patch_nops)(alt, origptr, updptr, nr_inst);
46304633
}
4634+
4635+
void my__queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
4636+
{
4637+
return (wolfssl_linuxkm_get_pie_redirect_table()->
4638+
queued_spin_lock_slowpath)(lock, val);
4639+
}
46314640
#endif

0 commit comments

Comments
 (0)