This commit fixes a timing issue introduced in the previous commit "crypto: rng - Override drivers/char/random in FIPS mode" where the crypto RNG was attempting to override the drivers/char/random interface before the default RNG became available. The previous implementation would immediately register the external RNG during module initialization, which could fail if the default RNG wasn't ready.
Changes: - Introduce workqueue-based initialization for FIPS mode - Add crypto_rng_register_work_func() to wait for default RNG availability - Move random_register_extrng() call to the work function with proper error handling
This ensures the crypto ext RNG is properly registered only after all dependencies are satisfied, preventing potential boot failures in FIPS-enabled environments.
Cc: stable@vger.kernel.org Signed-off-by: Jay Wang wanjay@amazon.com --- crypto/rng.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/crypto/rng.c b/crypto/rng.c index cdba806846e2..250166d67fd0 100644 --- a/crypto/rng.c +++ b/crypto/rng.c @@ -22,6 +22,7 @@ #include <linux/sched/signal.h> #include <linux/slab.h> #include <linux/string.h> +#include <linux/workqueue.h> #include <net/netlink.h>
#include "internal.h" @@ -273,15 +274,35 @@ static const struct random_extrng crypto_devrandom_rng = { .owner = THIS_MODULE, };
+static struct work_struct crypto_rng_register_work; + +static void crypto_rng_register_work_func(struct work_struct *work) +{ + /* Wait until default rng becomes avaiable, then + Overwrite the extrng. + */ + int ret = crypto_get_default_rng(); + if (ret){ + printk(KERN_ERR "crypto_rng: Failed to get default RNG (error %d)\n", ret); + return; + } + printk(KERN_INFO "Overwrite extrng\n"); + random_register_extrng(&crypto_devrandom_rng); +} + static int __init crypto_rng_init(void) { - if (fips_enabled) - random_register_extrng(&crypto_devrandom_rng); + if (fips_enabled) { + INIT_WORK(&crypto_rng_register_work, crypto_rng_register_work_func); + schedule_work(&crypto_rng_register_work); + } + return 0; }
static void __exit crypto_rng_exit(void) { + cancel_work_sync(&crypto_rng_register_work); random_unregister_extrng(); }