linuxkm/lkcapi_sha_glue.c:

* refactor to use new wc_rng_bank facility:
  * wc_linuxkm_drbg_init_tfm()
  * wc_linuxkm_drbg_exit_tfm()
  * get_drbg() (renamed to linuxkm_get_drbg())
  * put_drbg() (renamed to linuxkm_put_drbg())
  * wc_linuxkm_drbg_generate()
  * wc_linuxkm_drbg_seed()
  * wc_mix_pool_bytes()
  * wc_crng_reseed()
* add:
  * linuxkm_affinity_lock()
  * linuxkm_affinity_get_id()
  * linuxkm_affinity_unlock()
  * linuxkm_InitRng_DefaultRef()
* remove:
  * get_drbg_n()
  * drbg_init_from()
  * fork_default_rng()
  * LKCAPI_INITRNG_FOR_SELFTEST.
* when LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT, define LKCAPI_INITRNG to linuxkm_InitRng_DefaultRef, else define it to wc_InitRng().
This commit is contained in:
Daniel Pouzzner
2026-01-06 01:01:30 -06:00
parent 3c15be6610
commit 1c6ef8b621

View File

@@ -956,103 +956,76 @@ struct wc_swallow_the_semicolon
#endif
#include <wolfssl/wolfcrypt/random.h>
struct wc_linuxkm_drbg_ctx {
size_t n_rngs;
struct wc_rng_inst {
wolfSSL_Atomic_Int lock;
WC_RNG rng;
} *rngs; /* one per CPU ID */
};
static inline void wc_linuxkm_drbg_ctx_clear(struct wc_linuxkm_drbg_ctx * ctx)
{
unsigned int i;
if (ctx->rngs) {
for (i = 0; i < ctx->n_rngs; ++i) {
if (ctx->rngs[i].lock != 0) {
/* better to leak than to crash. */
pr_err("BUG: wc_linuxkm_drbg_ctx_clear called with DRBG #%d still locked.", i);
ctx->rngs = NULL;
ctx->n_rngs = 0;
return;
}
else
wc_FreeRng(&ctx->rngs[i].rng);
}
free(ctx->rngs);
ctx->rngs = NULL;
ctx->n_rngs = 0;
}
return;
}
static volatile int wc_linuxkm_drbg_init_tfm_disable_vector_registers = 0;
#ifndef WC_LINUXKM_INITRNG_TIMEOUT_SEC
#define WC_LINUXKM_INITRNG_TIMEOUT_SEC 30
#endif
static int linuxkm_affinity_lock(void *arg) {
(void)arg;
if (preempt_count() != 0)
return ALREADY_E;
#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();
return 0;
}
static int linuxkm_affinity_get_id(void *arg, int *id) {
(void)arg;
*id = raw_smp_processor_id();
return 0;
}
static int linuxkm_affinity_unlock(void *arg) {
(void)arg;
local_bh_enable();
#if defined(CONFIG_SMP) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0))
migrate_enable();
#endif
return 0;
}
static int wc_linuxkm_drbg_init_tfm(struct crypto_tfm *tfm)
{
struct wc_linuxkm_drbg_ctx *ctx = (struct wc_linuxkm_drbg_ctx *)crypto_tfm_ctx(tfm);
unsigned int i;
struct wc_rng_bank *ctx = (struct wc_rng_bank *)crypto_tfm_ctx(tfm);
int ret;
int need_reenable_vec = 0;
int can_sleep = (preempt_count() == 0);
enum wc_rng_bank_flags flags = WC_RNG_BANK_FLAG_CAN_WAIT;
ctx->n_rngs = nr_cpu_ids + 4;
ctx->rngs = (struct wc_rng_inst *)malloc(sizeof(*ctx->rngs) * ctx->n_rngs);
if (! ctx->rngs) {
ctx->n_rngs = 0;
return -ENOMEM;
}
XMEMSET(ctx->rngs, 0, sizeof(*ctx->rngs) * ctx->n_rngs);
if (wc_linuxkm_drbg_init_tfm_disable_vector_registers)
flags |= WC_RNG_BANK_FLAG_NO_VECTOR_OPS;
for (i = 0; i < ctx->n_rngs; ++i) {
int nretries = 0;
u64 ts1 = ktime_get_ns();
for (;;) {
u64 ts2;
if (wc_linuxkm_drbg_init_tfm_disable_vector_registers)
need_reenable_vec = (DISABLE_VECTOR_REGISTERS() == 0);
ret = wc_InitRng(&ctx->rngs[i].rng);
if (need_reenable_vec)
REENABLE_VECTOR_REGISTERS();
if (can_sleep) {
/* if we're allowed to sleep, relax the loop between each inner
* iteration even on success, assuring relaxation of the outer
* iterations.
*/
cond_resched();
}
if (ret == 0)
break;
if (can_sleep) {
/* Allow interrupt only if we're stuck spinning retries -- i.e.,
* don't allow an untimely user signal to derail an
* initialization that is proceeding expeditiously.
*/
if (WC_CHECK_FOR_INTR_SIGNALS() == WC_NO_ERR_TRACE(INTERRUPTED_E)) {
ret = -EINTR;
break;
}
}
ts2 = ktime_get_ns();
if (ts2 - ts1 > 1000000000L * WC_LINUXKM_INITRNG_TIMEOUT_SEC)
break;
++nretries;
}
ret = wc_rng_bank_init(ctx, nr_cpu_ids + 4, flags,
WC_LINUXKM_INITRNG_TIMEOUT_SEC, NULL /* heap */);
if (ret == 0) {
ret = wc_rng_bank_set_affinity_handlers(
ctx,
linuxkm_affinity_lock,
linuxkm_affinity_get_id,
linuxkm_affinity_unlock,
NULL);
if (ret != 0) {
pr_warn("WARNING: wc_InitRng returned %d after %d retries.\n", ret, nretries);
ret = -EINVAL;
break;
(void)wc_rng_bank_fini(ctx);
pr_err("ERROR: wc_rng_bank_set_affinity_handlers() in wc_linuxkm_drbg_init_tfm() returned err %d\n", ret);
WC_DUMP_BACKTRACE_NONDEBUG;
}
}
if (ret != 0) {
wc_linuxkm_drbg_ctx_clear(ctx);
else {
pr_err("ERROR: wc_rng_bank_init() in wc_linuxkm_drbg_init_tfm() returned err %d\n", ret);
if (ret == WC_NO_ERR_TRACE(MEMORY_E))
ret = -ENOMEM;
else if (ret == WC_NO_ERR_TRACE(WC_TIMEOUT_E))
ret = -ETIMEDOUT;
else if (ret == WC_NO_ERR_TRACE(INTERRUPTED_E))
ret = -EINTR;
else
ret = -EINVAL;
}
return ret;
@@ -1060,101 +1033,54 @@ static int wc_linuxkm_drbg_init_tfm(struct crypto_tfm *tfm)
static void wc_linuxkm_drbg_exit_tfm(struct crypto_tfm *tfm)
{
struct wc_linuxkm_drbg_ctx *ctx = (struct wc_linuxkm_drbg_ctx *)crypto_tfm_ctx(tfm);
struct wc_rng_bank *ctx = (struct wc_rng_bank *)crypto_tfm_ctx(tfm);
int ret = wc_rng_bank_fini(ctx);
wc_linuxkm_drbg_ctx_clear(ctx);
if (ret != 0)
pr_err("ERROR: wc_rng_bank_fini() in wc_linuxkm_drbg_exit_tfm() returned err %d\n", ret);
return;
}
static int wc_linuxkm_drbg_default_instance_registered = 0;
/* get_drbg() uses atomic operations to get exclusive ownership of a DRBG
* without delay. It expects to be called in uninterruptible context, though
* works fine in any context. It starts by trying the DRBG matching the current
* CPU ID, and if that doesn't immediately succeed, it iterates upward until one
* succeeds. The first attempt will always succeed, even under intense load,
* unless there is or has recently been a reseed or mix-in operation competing
* with generators.
*
* Note that wc_linuxkm_drbg_init_tfm() allocates at least 4 DRBGs, regardless
* of nominal core count, to avoid stalling generators on unicore targets.
*/
static struct wc_rng_bank_inst *linuxkm_get_drbg(struct crypto_rng *tfm) {
struct wc_rng_bank *ctx = (struct wc_rng_bank *)crypto_rng_ctx(tfm);
int err;
struct wc_rng_bank_inst *ret;
enum wc_rng_bank_flags flags =
WC_RNG_BANK_FLAG_CAN_FAIL_OVER_INST |
WC_RNG_BANK_FLAG_CAN_WAIT |
WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST;
static inline struct wc_rng_inst *get_drbg(struct crypto_rng *tfm) {
struct wc_linuxkm_drbg_ctx *ctx = (struct wc_linuxkm_drbg_ctx *)crypto_rng_ctx(tfm);
int n, new_lock_value;
/* check for mismatched handler or missing instance array. */
if ((tfm->base.__crt_alg->cra_init != wc_linuxkm_drbg_init_tfm) ||
(ctx->rngs == NULL))
{
/* check for mismatched handler. */
if (tfm->base.__crt_alg->cra_init != wc_linuxkm_drbg_init_tfm) {
pr_err("BUG: linuxkm_get_drbg() called on foreign tfm.\n");
return NULL;
}
if ((tfm == crypto_default_rng) && (preempt_count() == 0)) {
#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;
}
if (preempt_count() == 0)
flags |= WC_RNG_BANK_FLAG_AFFINITY_LOCK;
else
{
new_lock_value = 1;
flags |= WC_RNG_BANK_FLAG_NO_VECTOR_OPS;
err = wc_rng_bank_checkout(ctx, &ret, 0, WC_LINUXKM_INITRNG_TIMEOUT_SEC, flags);
if (err != 0) {
pr_err("ERROR: wc_rng_bank_checkout() in linuxkm_get_drbg() returned err %d.\n", err);
WC_DUMP_BACKTRACE_NONDEBUG;
return NULL;
}
n = raw_smp_processor_id();
for (;;) {
int expected = 0;
if (likely(__atomic_compare_exchange_n(&ctx->rngs[n].lock, &expected, new_lock_value, 0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE)))
return &ctx->rngs[n];
++n;
if (n >= (int)ctx->n_rngs)
n = 0;
cpu_relax();
}
__builtin_unreachable();
return ret;
}
/* 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. 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_spin) {
int can_sleep = (preempt_count() == 0);
for (;;) {
int expected = 0;
if (likely(__atomic_compare_exchange_n(&ctx->rngs[n].lock, &expected, 1, 0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE)))
return &ctx->rngs[n];
if (can_sleep && can_spin) {
if (signal_pending(current))
return NULL;
cond_resched();
}
else
return NULL;
}
__builtin_unreachable();
}
static inline void put_drbg(struct wc_rng_inst *drbg) {
int migration_disabled = (drbg->lock == 2);
__atomic_store_n(&(drbg->lock),0,__ATOMIC_RELEASE);
if (migration_disabled) {
local_bh_enable();
#if defined(CONFIG_SMP) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0))
migrate_enable();
#endif
static void linuxkm_put_drbg(struct crypto_rng *tfm, struct wc_rng_bank_inst *drbg) {
struct wc_rng_bank *ctx = (struct wc_rng_bank *)crypto_rng_ctx(tfm);
int ret = wc_rng_bank_checkin(ctx, drbg);
if (ret != 0) {
pr_err("ERROR: wc_rng_bank_checkin() in linuxkm_put_drbg() returned err %d.\n", ret);
WC_DUMP_BACKTRACE_NONDEBUG;
}
}
@@ -1188,194 +1114,37 @@ static inline struct crypto_rng *get_crypto_default_rng(void) {
return current_crypto_default_rng;
}
static int drbg_init_from(WC_RNG *source_rng, struct DRBG_internal* dest_drbg) {
WC_MAYBE_UNUSED static int linuxkm_InitRng_DefaultRef(WC_RNG* rng) {
int ret;
int need_vec_reenable;
XMEMSET(dest_drbg, 0, sizeof(struct DRBG_internal));
need_vec_reenable = (DISABLE_VECTOR_REGISTERS() == 0);
/* Don't copy out the low level DRBG itself -- it contains sensitive secret
* state. Instead, use it to generate fresh V and C values in a
* non-intrusive way.
*/
ret = wc_RNG_GenerateBlock(source_rng, dest_drbg->V, sizeof dest_drbg->V);
if (ret != 0) {
pr_err("drbg_init_from: wc_RNG_GenerateBlock for V returned %d\n", ret);
goto out;
}
ret = wc_RNG_GenerateBlock(source_rng, dest_drbg->C, sizeof dest_drbg->C);
if (ret != 0) {
pr_err("drbg_init_from: wc_RNG_GenerateBlock for C returned %d\n", ret);
goto out;
}
dest_drbg->heap = source_rng->heap;
#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB)
dest_drbg->devId = source_rng->devId;
#endif
ret = wc_InitSha256_ex(&dest_drbg->sha256, dest_drbg->heap,
#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB)
source_rng->dev_id
#else
INVALID_DEVID
#endif
);
if (ret != 0)
goto out;
dest_drbg->reseedCtr = 1;
ret = 0;
out:
if (need_vec_reenable)
REENABLE_VECTOR_REGISTERS();
return ret;
}
/* fork_default_rng() is a non-FIPS-compliant helper function to initialize an
* RNG for glue layer POSTs. Direct replacement for wc_InitRng(), and secure in
* principle, but not permissible to use as such in FIPS runtimes.
*/
static WC_MAYBE_UNUSED int fork_default_rng(WC_RNG *forked_rng) {
struct crypto_rng *current_crypto_default_rng;
struct wc_rng_inst *rng = NULL;
struct DRBG_internal *drbg = NULL;
struct DRBG_internal *drbg_scratch = NULL;
byte *health_check_scratch = NULL;
byte *newSeed_buf = NULL;
int ret;
if (forked_rng == NULL)
return BAD_FUNC_ARG;
XMEMSET(forked_rng, 0, sizeof *forked_rng);
health_check_scratch =
(byte *)XMALLOC(RNG_HEALTH_TEST_CHECK_SIZE, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (health_check_scratch == NULL) {
ret = MEMORY_E;
goto out;
}
newSeed_buf = (byte*)XMALLOC(WC_DRBG_SEED_SZ +
WC_DRBG_SEED_BLOCK_SZ,
NULL,
DYNAMIC_TYPE_SEED);
if (newSeed_buf == NULL) {
ret = MEMORY_E;
goto out;
}
drbg = (struct DRBG_internal *)XMALLOC(sizeof *drbg, NULL,
DYNAMIC_TYPE_RNG);
if (drbg == NULL) {
ret = MEMORY_E;
goto out;
}
drbg_scratch =
(struct DRBG_internal *)XMALLOC(sizeof *drbg_scratch, NULL,
DYNAMIC_TYPE_RNG);
if (drbg_scratch == NULL) {
ret = MEMORY_E;
goto out;
}
current_crypto_default_rng = get_crypto_default_rng();
struct crypto_rng *current_crypto_default_rng = get_crypto_default_rng();
if (current_crypto_default_rng == NULL) {
ret = BAD_STATE_E;
goto out;
pr_warn_once("WARNING: get_crypto_default_rng() failed in linuxkm_InitRng_DefaultRef(); falling through to wc_InitRng().\n");
return wc_InitRng(rng);
}
rng = get_drbg(current_crypto_default_rng);
if (rng == NULL) {
ret = BAD_STATE_E;
goto out;
}
if (rng->rng.status != WC_DRBG_OK) {
pr_err("fork_default_rng: rng->rng.status = %d\n", rng->rng.status);
ret = RNG_FAILURE_E;
goto out;
}
XMEMCPY(forked_rng, &rng->rng, sizeof *forked_rng);
forked_rng->drbg = (struct DRBG *)drbg;
forked_rng->drbg_scratch = drbg_scratch;
forked_rng->health_check_scratch = health_check_scratch;
forked_rng->newSeed_buf = newSeed_buf;
ret = drbg_init_from(&rng->rng, (struct DRBG_internal*)forked_rng->drbg);
if (ret != 0)
goto out;
ret = drbg_init_from(&rng->rng, (struct DRBG_internal*)forked_rng->drbg_scratch);
if (ret != 0)
goto out;
put_drbg(rng);
rng = NULL;
{
byte scratch[4];
ret = wc_RNG_GenerateBlock(forked_rng, scratch, sizeof scratch);
if (ret != 0)
goto out;
}
ret = 0;
out:
if (ret == 0)
return ret;
else {
if (rng)
put_drbg(rng);
XFREE(drbg, rng->rng.heap, DYNAMIC_TYPE_RNG);
XFREE(drbg_scratch, rng->rng.heap, DYNAMIC_TYPE_RNG);
XFREE(health_check_scratch, rng->rng.heap, DYNAMIC_TYPE_RNG);
XFREE(newSeed_buf, rng->rng.heap, DYNAMIC_TYPE_RNG);
pr_warn("WARNING: fork_default_rng: ret=%d; falling through to wc_InitRng()\n", ret);
return wc_InitRng(forked_rng);
struct wc_rng_bank *default_bank = (struct wc_rng_bank *)crypto_rng_ctx(current_crypto_default_rng);
ret = wc_InitRng_BankRef(default_bank, rng);
return ret;
}
__builtin_unreachable();
}
#define LKCAPI_INITRNG(rng) linuxkm_InitRng_DefaultRef(rng)
#define LKCAPI_INITRNG_FOR_SELFTEST(rng) fork_default_rng(rng)
#else /* !LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT || !HAVE_HASHDRBG */
#define LKCAPI_INITRNG_FOR_SELFTEST(rng) wc_InitRng(rng)
#endif /* !LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT || !HAVE_HASHDRBG */
#endif /* LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT && HAVE_HASHDRBG */
static int wc_linuxkm_drbg_generate(struct crypto_rng *tfm,
const u8 *src, unsigned int slen,
u8 *dst, unsigned int dlen)
{
int ret, retried = 0;
int need_fpu_restore;
struct wc_rng_inst *drbg = get_drbg(tfm);
struct wc_rng_bank_inst *drbg = linuxkm_get_drbg(tfm);
if (! drbg) {
pr_err_once("BUG: get_drbg() failed.");
pr_err_once("BUG: linuxkm_get_drbg() failed.");
return -EFAULT;
}
/* for the default RNG, make sure we don't cache an underlying SHA256
* method that uses vector insns (forbidden from irq handlers).
*/
need_fpu_restore = (tfm == crypto_default_rng) ? (DISABLE_VECTOR_REGISTERS() == 0) : 0;
retry:
if (slen > 0) {
ret = wc_RNG_DRBG_Reseed(&drbg->rng, src, slen);
if (ret != 0) {
@@ -1397,37 +1166,47 @@ retry:
#undef RNG_MAX_BLOCK_LEN_ROUNDED
else {
ret = wc_RNG_GenerateBlock(&drbg->rng, dst, dlen);
dlen -= dlen;
if (ret == 0)
dlen = 0;
}
if (dlen == 0)
break;
if (ret == 0)
continue;
if (unlikely(ret == WC_NO_ERR_TRACE(RNG_FAILURE_E)) && (! retried)) {
if (slen > 0)
break;
retried = 1;
wc_FreeRng(&drbg->rng);
ret = wc_InitRng(&drbg->rng);
ret = wc_rng_bank_inst_reinit((struct wc_rng_bank *)crypto_rng_ctx(tfm),
drbg,
WC_LINUXKM_INITRNG_TIMEOUT_SEC,
WC_RNG_BANK_FLAG_CAN_WAIT);
if (ret == 0) {
pr_warn("WARNING: reinitialized DRBG #%d after RNG_FAILURE_E.", raw_smp_processor_id());
goto retry;
pr_warn("WARNING: reinitialized DRBG #%d after RNG_FAILURE_E from wc_RNG_GenerateBlock().", raw_smp_processor_id());
continue;
}
else {
pr_warn_once("ERROR: reinitialization of DRBG #%d after RNG_FAILURE_E failed with ret %d.", raw_smp_processor_id(), ret);
ret = -EINVAL;
break;
}
}
else if (ret != 0) {
pr_warn_once("WARNING: wc_RNG_GenerateBlock returned %d\n",ret);
else {
pr_warn_once("ERROR: wc_linuxkm_drbg_generate() wc_RNG_GenerateBlock returned %d.\n",ret);
ret = -EINVAL;
break;
}
if (! dlen)
break;
}
out:
if (need_fpu_restore)
REENABLE_VECTOR_REGISTERS();
put_drbg(drbg);
linuxkm_put_drbg(tfm, drbg);
return ret;
}
@@ -1435,13 +1214,10 @@ out:
static int wc_linuxkm_drbg_seed(struct crypto_rng *tfm,
const u8 *seed, unsigned int slen)
{
struct wc_linuxkm_drbg_ctx *ctx = (struct wc_linuxkm_drbg_ctx *)crypto_rng_ctx(tfm);
u8 *seed_copy = NULL;
int ret = 0;
int n;
struct wc_rng_bank *ctx = (struct wc_rng_bank *)crypto_rng_ctx(tfm);
int ret;
if ((tfm->base.__crt_alg->cra_init != wc_linuxkm_drbg_init_tfm) ||
(ctx->rngs == NULL))
if (tfm->base.__crt_alg->cra_init != wc_linuxkm_drbg_init_tfm)
{
pr_err_once("BUG: mismatched tfm.");
return -EFAULT;
@@ -1450,51 +1226,12 @@ static int wc_linuxkm_drbg_seed(struct crypto_rng *tfm,
if (slen == 0)
return 0;
seed_copy = (u8 *)malloc(slen + 2);
if (! seed_copy)
return -ENOMEM;
XMEMCPY(seed_copy + 2, seed, slen);
/* this iteration counts down, whereas the iteration in get_drbg() counts
* up, to assure they can't possibly phase-lock to each other.
*/
for (n = ctx->n_rngs - 1; n >= 0; --n) {
struct wc_rng_inst *drbg = get_drbg_n(ctx, n, 1);
if (! drbg) {
ret = -EINTR;
break;
}
/* perturb the seed with the CPU ID, so that no DRBG has the exact same
* seed.
*/
seed_copy[0] = (u8)(n >> 8);
seed_copy[1] = (u8)n;
{
/* for the default RNG, make sure we don't cache an underlying SHA256
* method that uses vector insns (forbidden from irq handlers).
*/
int need_fpu_restore = (tfm == crypto_default_rng) ? (DISABLE_VECTOR_REGISTERS() == 0) : 0;
ret = wc_RNG_DRBG_Reseed(&drbg->rng, seed_copy, slen + 2);
if (need_fpu_restore)
REENABLE_VECTOR_REGISTERS();
}
if (ret != 0) {
pr_warn_once("WARNING: wc_RNG_DRBG_Reseed returned %d\n",ret);
ret = -EINVAL;
}
put_drbg(drbg);
if (ret != 0)
break;
ret = wc_rng_bank_seed(ctx, seed, slen, WC_LINUXKM_INITRNG_TIMEOUT_SEC, WC_RNG_BANK_FLAG_CAN_WAIT);
if (ret != 0) {
pr_err("wc_rng_bank_seed() in wc_linuxkm_drbg_seed() returned err %d.\n", ret);
ret = -EINVAL;
}
free(seed_copy);
return ret;
}
@@ -1506,7 +1243,7 @@ static struct rng_alg wc_linuxkm_drbg = {
.cra_name = WOLFKM_STDRNG_NAME,
.cra_driver_name = WOLFKM_STDRNG_DRIVER,
.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY,
.cra_ctxsize = sizeof(struct wc_linuxkm_drbg_ctx),
.cra_ctxsize = sizeof(struct wc_rng_bank),
.cra_init = wc_linuxkm_drbg_init_tfm,
.cra_exit = wc_linuxkm_drbg_exit_tfm,
.cra_module = THIS_MODULE
@@ -1549,9 +1286,9 @@ static int wc_linuxkm_drbg_loaded = 0;
#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS
static inline struct wc_linuxkm_drbg_ctx *get_default_drbg_ctx(void) {
static inline struct wc_rng_bank *get_default_drbg_ctx(void) {
struct crypto_rng *current_crypto_default_rng = get_crypto_default_rng();
struct wc_linuxkm_drbg_ctx *ctx = (current_crypto_default_rng ? (struct wc_linuxkm_drbg_ctx *)crypto_rng_ctx(current_crypto_default_rng) : NULL);
struct wc_rng_bank *ctx = (current_crypto_default_rng ? (struct wc_rng_bank *)crypto_rng_ctx(current_crypto_default_rng) : NULL);
if (ctx && (! ctx->rngs)) {
pr_err_once("BUG: get_default_drbg_ctx() found null ctx->rngs.");
return NULL;
@@ -1681,7 +1418,7 @@ static ssize_t wc_extract_crng_user(void __user *buf, size_t nbytes) {
}
static int wc_mix_pool_bytes(const void *buf, size_t len) {
struct wc_linuxkm_drbg_ctx *ctx;
struct wc_rng_bank *ctx;
size_t i;
int n;
int can_sleep = (preempt_count() == 0);
@@ -1693,10 +1430,11 @@ static int wc_mix_pool_bytes(const void *buf, size_t len) {
return -EFAULT;
for (n = ctx->n_rngs - 1; n >= 0; --n) {
struct wc_rng_inst *drbg = get_drbg_n(ctx, n, 0);
struct wc_rng_bank_inst *drbg;
int V_offset;
if (! drbg)
if (wc_rng_bank_checkout(ctx, &drbg, n, 0, WC_RNG_BANK_FLAG_NONE) != 0)
continue;
for (i = 0, V_offset = 0; i < len; ++i) {
@@ -1705,7 +1443,7 @@ static int wc_mix_pool_bytes(const void *buf, size_t len) {
V_offset = 0;
}
put_drbg(drbg);
wc_rng_bank_checkin(ctx, drbg);
if (can_sleep) {
if (signal_pending(current))
return -EINTR;
@@ -1717,40 +1455,23 @@ static int wc_mix_pool_bytes(const void *buf, size_t len) {
}
static int wc_crng_reseed(void) {
struct wc_linuxkm_drbg_ctx *ctx = get_default_drbg_ctx();
int n;
struct wc_rng_bank *ctx = get_default_drbg_ctx();
int can_sleep = (preempt_count() == 0);
int ret;
if (! ctx)
return -EFAULT;
for (n = ctx->n_rngs - 1; n >= 0; --n) {
struct wc_rng_inst *drbg = get_drbg_n(ctx, n, 1);
if (! drbg)
return -EINTR;
((struct DRBG_internal *)drbg->rng.drbg)->reseedCtr = WC_RESEED_INTERVAL;
if (can_sleep) {
byte scratch[4];
int need_reenable_vec = (DISABLE_VECTOR_REGISTERS() == 0);
int ret = wc_RNG_GenerateBlock(&drbg->rng, scratch, (word32)sizeof(scratch));
if (need_reenable_vec)
REENABLE_VECTOR_REGISTERS();
if (ret != 0)
pr_err("ERROR: wc_crng_reseed() wc_RNG_GenerateBlock() for DRBG #%d returned %d.", n, ret);
put_drbg(drbg);
if (signal_pending(current))
return -EINTR;
cond_resched();
}
else {
put_drbg(drbg);
}
ret = wc_rng_bank_reseed(ctx, WC_LINUXKM_INITRNG_TIMEOUT_SEC,
can_sleep
?
WC_RNG_BANK_FLAG_CAN_WAIT
:
WC_RNG_BANK_FLAG_NONE);
if (ret != 0) {
pr_err("ERROR: wc_rng_bank_reseed() returned err %d.\n", ret);
return -EINVAL;
}
else {
return 0;
}
return 0;
}
struct wolfssl_linuxkm_random_bytes_handlers random_bytes_handlers = {
@@ -2266,4 +1987,8 @@ static int wc_linuxkm_drbg_cleanup(void) {
#endif /* LINUXKM_LKCAPI_REGISTER_HASH_DRBG */
#ifndef LKCAPI_INITRNG
#define LKCAPI_INITRNG(rng) wc_InitRng(rng)
#endif
#endif /* !WC_SKIP_INCLUDED_C_FILES */