All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jay Wang <wanjay@amazon.com>
To: <herbert@gondor.apana.org.au>, <davem@davemloft.net>
Cc: <linux-crypto@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<wanjay@amazon.com>
Subject: [PATCH v6.12 1/2] random: Add hook to override device reads and getrandom(2)
Date: Mon, 30 Jun 2025 18:03:11 +0000	[thread overview]
Message-ID: <20250630180312.24627-2-wanjay@amazon.com> (raw)
In-Reply-To: <20250630180312.24627-1-wanjay@amazon.com>

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


  reply	other threads:[~2025-06-30 18:03 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
2025-06-30 18:03 ` [PATCH v6.12 2/2] crypto: rng - Override drivers/char/random only after FIPS RNGs available Jay Wang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250630180312.24627-2-wanjay@amazon.com \
    --to=wanjay@amazon.com \
    --cc=davem@davemloft.net \
    --cc=herbert@gondor.apana.org.au \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.