lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250630180312.24627-2-wanjay@amazon.com>
Date: Mon, 30 Jun 2025 18:03:11 +0000
From: Jay Wang <wanjay@...zon.com>
To: <herbert@...dor.apana.org.au>, <davem@...emloft.net>
CC: <linux-crypto@...r.kernel.org>, <linux-kernel@...r.kernel.org>,
	<wanjay@...zon.com>
Subject: [PATCH v6.12 1/2] random: Add hook to override device reads and getrandom(2)

From: Herbert Xu <herbert.xu@...hat.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@...hat.com>
Signed-off-by: Prarit Bhargava <prarit@...hat.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@...zon.com>
[6.12: Further resolve surrounding conflicts in getrandom() and random.h.]
Cc: stable@...r.kernel.org
Signed-off-by: Elena Avila <ellavila@...zon.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


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ