* [PATCH v6.12 0/2] crypto: rng - FIPS 140-3 compliance for random number generation
@ 2025-06-30 18:03 Jay Wang
2025-06-30 18:03 ` [PATCH v6.12 1/2] random: Add hook to override device reads and getrandom(2) Jay Wang
2025-06-30 18:03 ` [PATCH v6.12 2/2] crypto: rng - Override drivers/char/random only after FIPS RNGs available Jay Wang
0 siblings, 2 replies; 3+ messages in thread
From: Jay Wang @ 2025-06-30 18:03 UTC (permalink / raw)
To: herbert, davem; +Cc: linux-crypto, linux-kernel, wanjay
This patch series implements FIPS 140-3 compliance requirements for random
number generation in the Linux kernel 6.12 stable. The changes ensure that
when the kernel is operating in FIPS mode, FIPS-compliant random number
generators from the Crypto API are used to override the default
/dev/random implementation.
The series consists of two patches:
1. "random: Add hook to override device reads and getrandom(2)" - This patch
introduces the infrastructure to allow external RNGs to override the
default random number generation. Originally authored by Herbert Xu, this has
been adapted for kernel 6.12.
2. "crypto: rng - Override drivers/char/random only after FIPS RNGs available" -
This patch implements the actual FIPS mode override using a workqueue-based
approach to ensure proper initialization timing. It addresses timing issues
in a previous commit "crypto: rng - Override drivers/char/random only after
FIPS RNGs available" where the crypto RNG would attempt to override before
dependencies were ready, preventing potential boot failures.
These patches are required for FIPS 140-3 certification and compliance in
government and enterprise environments where cryptographic standards must
be strictly enforced.
Herbert Xu (1):
random: Add hook to override device reads and getrandom(2)
Jay Wang (1):
crypto: rng - Override drivers/char/random only after FIPS RNGs
available
crypto/rng.c | 92 +++++++++++++++++++++++++++++++++
drivers/char/random.c | 114 +++++++++++++++++++++++++++++++++++++++++
include/linux/random.h | 7 +++
3 files changed, 213 insertions(+)
--
2.47.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v6.12 1/2] random: Add hook to override device reads and getrandom(2)
2025-06-30 18:03 [PATCH v6.12 0/2] crypto: rng - FIPS 140-3 compliance for random number generation Jay Wang
@ 2025-06-30 18:03 ` Jay Wang
2025-06-30 18:03 ` [PATCH v6.12 2/2] crypto: rng - Override drivers/char/random only after FIPS RNGs available Jay Wang
1 sibling, 0 replies; 3+ messages in thread
From: Jay Wang @ 2025-06-30 18:03 UTC (permalink / raw)
To: herbert, davem; +Cc: linux-crypto, linux-kernel, wanjay
From: Herbert Xu <herbert.xu@redhat.com>
This patch introduces a hook mechanism to drivers/char/random
to allow the reads on /dev/*random as well as getrandom(2) to
be overridden by an external RNG.
This will be used to override drivers/char/random with a FIPS
RNG in a subsequent patch.
Signed-off-by: Herbert Xu <herbert.xu@redhat.com>
Signed-off-by: Prarit Bhargava <prarit@redhat.com>
[6.1: Handle some context in getrandom() and random.h, and convert the
extrng_*_fops to use random_write_iter().]
Signed-off-by: Samuel Mendoza-Jonas <samjonas@amazon.com>
[6.12: Further resolve surrounding conflicts in getrandom() and random.h.]
Cc: stable@vger.kernel.org
Signed-off-by: Elena Avila <ellavila@amazon.com>
---
drivers/char/random.c | 114 +++++++++++++++++++++++++++++++++++++++++
include/linux/random.h | 7 +++
2 files changed, 121 insertions(+)
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 23ee76bbb4aa..032c5ffa814c 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -54,6 +54,7 @@
#include <linux/suspend.h>
#include <linux/siphash.h>
#include <linux/sched/isolation.h>
+#include <linux/rcupdate.h>
#include <crypto/chacha.h>
#include <crypto/blake2s.h>
#ifdef CONFIG_VDSO_GETRANDOM
@@ -330,6 +331,11 @@ static void crng_fast_key_erasure(u8 key[CHACHA_KEY_SIZE],
memzero_explicit(first_block, sizeof(first_block));
}
+/*
+ * Hook for external RNG.
+ */
+static const struct random_extrng __rcu *extrng;
+
/*
* This function returns a ChaCha state that you may use for generating
* random data. It also returns up to 32 bytes on its own of random data
@@ -610,6 +616,9 @@ int __cold random_prepare_cpu(unsigned int cpu)
#endif
+static const struct file_operations extrng_random_fops;
+static const struct file_operations extrng_urandom_fops;
+
/**********************************************************************
*
* Entropy accumulation and extraction routines.
@@ -980,6 +989,19 @@ void __init add_bootloader_randomness(const void *buf, size_t len)
credit_init_bits(len * 8);
}
+void random_register_extrng(const struct random_extrng *rng)
+{
+ rcu_assign_pointer(extrng, rng);
+}
+EXPORT_SYMBOL_GPL(random_register_extrng);
+
+void random_unregister_extrng(void)
+{
+ RCU_INIT_POINTER(extrng, NULL);
+ synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(random_unregister_extrng);
+
#if IS_ENABLED(CONFIG_VMGENID)
static BLOCKING_NOTIFIER_HEAD(vmfork_chain);
@@ -1387,6 +1409,7 @@ static void __cold try_to_generate_entropy(void)
SYSCALL_DEFINE3(getrandom, char __user *, ubuf, size_t, len, unsigned int, flags)
{
+ const struct random_extrng *rng;
struct iov_iter iter;
int ret;
@@ -1400,6 +1423,18 @@ SYSCALL_DEFINE3(getrandom, char __user *, ubuf, size_t, len, unsigned int, flags
if ((flags & (GRND_INSECURE | GRND_RANDOM)) == (GRND_INSECURE | GRND_RANDOM))
return -EINVAL;
+ rcu_read_lock();
+ rng = rcu_dereference(extrng);
+ if (rng && !try_module_get(rng->owner))
+ rng = NULL;
+ rcu_read_unlock();
+
+ if (rng) {
+ ret = rng->extrng_read(ubuf, len);
+ module_put(rng->owner);
+ return ret;
+ }
+
if (!crng_ready() && !(flags & GRND_INSECURE)) {
if (flags & GRND_NONBLOCK)
return -EAGAIN;
@@ -1420,6 +1455,13 @@ static __poll_t random_poll(struct file *file, poll_table *wait)
return crng_ready() ? EPOLLIN | EPOLLRDNORM : EPOLLOUT | EPOLLWRNORM;
}
+static __poll_t
+extrng_poll(struct file *file, poll_table * wait)
+{
+ /* extrng pool is always full, always read, no writes */
+ return EPOLLIN | EPOLLRDNORM;
+}
+
static ssize_t write_pool_user(struct iov_iter *iter)
{
u8 block[BLAKE2S_BLOCK_SIZE];
@@ -1560,9 +1602,60 @@ static int random_fasync(int fd, struct file *filp, int on)
return fasync_helper(fd, filp, on, &fasync);
}
+static int random_open(struct inode *inode, struct file *filp)
+{
+ const struct random_extrng *rng;
+
+ rcu_read_lock();
+ rng = rcu_dereference(extrng);
+ if (rng && !try_module_get(rng->owner))
+ rng = NULL;
+ rcu_read_unlock();
+
+ if (!rng)
+ return 0;
+
+ filp->f_op = &extrng_random_fops;
+ filp->private_data = rng->owner;
+
+ return 0;
+}
+
+static int urandom_open(struct inode *inode, struct file *filp)
+{
+ const struct random_extrng *rng;
+
+ rcu_read_lock();
+ rng = rcu_dereference(extrng);
+ if (rng && !try_module_get(rng->owner))
+ rng = NULL;
+ rcu_read_unlock();
+
+ if (!rng)
+ return 0;
+
+ filp->f_op = &extrng_urandom_fops;
+ filp->private_data = rng->owner;
+
+ return 0;
+}
+
+static int extrng_release(struct inode *inode, struct file *filp)
+{
+ module_put(filp->private_data);
+ return 0;
+}
+
+static ssize_t
+extrng_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+{
+ return rcu_dereference_raw(extrng)->extrng_read(buf, nbytes);
+}
+
const struct file_operations random_fops = {
.read_iter = random_read_iter,
.write_iter = random_write_iter,
+ .open = random_open,
.poll = random_poll,
.unlocked_ioctl = random_ioctl,
.compat_ioctl = compat_ptr_ioctl,
@@ -1575,6 +1668,7 @@ const struct file_operations random_fops = {
const struct file_operations urandom_fops = {
.read_iter = urandom_read_iter,
.write_iter = random_write_iter,
+ .open = urandom_open,
.unlocked_ioctl = random_ioctl,
.compat_ioctl = compat_ptr_ioctl,
.fasync = random_fasync,
@@ -1583,6 +1677,26 @@ const struct file_operations urandom_fops = {
.splice_write = iter_file_splice_write,
};
+static const struct file_operations extrng_random_fops = {
+ .open = random_open,
+ .read = extrng_read,
+ .write_iter = random_write_iter,
+ .poll = extrng_poll,
+ .unlocked_ioctl = random_ioctl,
+ .fasync = random_fasync,
+ .llseek = noop_llseek,
+ .release = extrng_release,
+};
+
+static const struct file_operations extrng_urandom_fops = {
+ .open = urandom_open,
+ .read = extrng_read,
+ .write_iter = random_write_iter,
+ .unlocked_ioctl = random_ioctl,
+ .fasync = random_fasync,
+ .llseek = noop_llseek,
+ .release = extrng_release,
+};
/********************************************************************
*
diff --git a/include/linux/random.h b/include/linux/random.h
index b0a940af4fff..6cfb75741ade 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -9,6 +9,11 @@
#include <uapi/linux/random.h>
+struct random_extrng {
+ ssize_t (*extrng_read)(void __user *buf, size_t buflen);
+ struct module *owner;
+};
+
struct notifier_block;
void add_device_randomness(const void *buf, size_t len);
@@ -120,6 +125,8 @@ void __init random_init(void);
bool rng_is_initialized(void);
int wait_for_random_bytes(void);
int execute_with_initialized_rng(struct notifier_block *nb);
+void random_register_extrng(const struct random_extrng *rng);
+void random_unregister_extrng(void);
/* Calls wait_for_random_bytes() and then calls get_random_bytes(buf, nbytes).
* Returns the result of the call to wait_for_random_bytes. */
--
2.47.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH v6.12 2/2] crypto: rng - Override drivers/char/random only after FIPS RNGs available
2025-06-30 18:03 [PATCH v6.12 0/2] crypto: rng - FIPS 140-3 compliance for random number generation Jay Wang
2025-06-30 18:03 ` [PATCH v6.12 1/2] random: Add hook to override device reads and getrandom(2) Jay Wang
@ 2025-06-30 18:03 ` Jay Wang
1 sibling, 0 replies; 3+ messages in thread
From: Jay Wang @ 2025-06-30 18:03 UTC (permalink / raw)
To: herbert, davem; +Cc: linux-crypto, linux-kernel, wanjay
This commit overrides the drivers/char/random RNGs with the FIPS RNG
from Crypto API when FIPS mode is enabled. This commit is developed
based on a previous commit "crypto: rng - Override drivers/char/random
in FIPS mode", but it has a timing issue 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 compared to previous commit:
- 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 | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 92 insertions(+)
diff --git a/crypto/rng.c b/crypto/rng.c
index 9d8804e46422..250166d67fd0 100644
--- a/crypto/rng.c
+++ b/crypto/rng.c
@@ -12,13 +12,17 @@
#include <linux/atomic.h>
#include <linux/cryptouser.h>
#include <linux/err.h>
+#include <linux/fips.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/random.h>
#include <linux/seq_file.h>
+#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/workqueue.h>
#include <net/netlink.h>
#include "internal.h"
@@ -217,5 +221,93 @@ void crypto_unregister_rngs(struct rng_alg *algs, int count)
}
EXPORT_SYMBOL_GPL(crypto_unregister_rngs);
+static ssize_t crypto_devrandom_read(void __user *buf, size_t buflen)
+{
+ u8 tmp[256];
+ ssize_t ret;
+
+ if (!buflen)
+ return 0;
+
+ ret = crypto_get_default_rng();
+ if (ret)
+ return ret;
+
+ for (;;) {
+ int err;
+ int i;
+
+ i = min_t(int, buflen, sizeof(tmp));
+ err = crypto_rng_get_bytes(crypto_default_rng, tmp, i);
+ if (err) {
+ ret = err;
+ break;
+ }
+
+ if (copy_to_user(buf, tmp, i)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ buflen -= i;
+ buf += i;
+ ret += i;
+
+ if (!buflen)
+ break;
+
+ if (need_resched()) {
+ if (signal_pending(current))
+ break;
+ schedule();
+ }
+ }
+
+ crypto_put_default_rng();
+ memzero_explicit(tmp, sizeof(tmp));
+
+ return ret;
+}
+
+static const struct random_extrng crypto_devrandom_rng = {
+ .extrng_read = crypto_devrandom_read,
+ .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) {
+ 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();
+}
+
+late_initcall(crypto_rng_init);
+module_exit(crypto_rng_exit);
+
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Random Number Generator");
--
2.47.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-06-30 18:03 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-30 18:03 [PATCH v6.12 0/2] crypto: rng - FIPS 140-3 compliance for random number generation Jay Wang
2025-06-30 18:03 ` [PATCH v6.12 1/2] random: Add hook to override device reads and getrandom(2) Jay Wang
2025-06-30 18:03 ` [PATCH v6.12 2/2] crypto: rng - Override drivers/char/random only after FIPS RNGs available Jay Wang
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.