From: Herbert Xu <[email protected]>

random: Add hook to override device reads and getrandom(2)

Upstream Status: RHEL only

Restore the changes to /dev/random which were reverted after 5.18.

This reverts commit 900f11e054896bae7b0146055698656e3d1e20a6.

This also brings the code up-to-date with respect to centos-stream
commit 9de3a7339793d3c516b9305a8854267156f90c53 so that changes that
were made after the kernel-ark revert have been brought in.

Signed-off-by: Herbert Xu <[email protected]>

diff --git a/drivers/char/random.c b/drivers/char/random.c
index blahblah..blahblah 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -51,6 +51,7 @@
 #include <linux/completion.h>
 #include <linux/uuid.h>
 #include <linux/uaccess.h>
+#include <linux/rcupdate.h>
 #include <linux/suspend.h>
 #include <linux/siphash.h>
 #include <linux/sched/isolation.h>
@@ -309,6 +310,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
@@ -739,6 +745,9 @@ static void __cold _credit_init_bits(size_t bits)
 }
 
 
+static const struct file_operations extrng_random_fops;
+static const struct file_operations extrng_urandom_fops;
+
 /**********************************************************************
  *
  * Entropy collection routines.
@@ -956,6 +965,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);
 
@@ -1366,6 +1388,7 @@ SYSCALL_DEFINE3(getrandom, char __user *, ubuf, size_t, 
len, unsigned int, flags
        struct iov_iter iter;
        struct iovec iov;
        int ret;
+       const struct random_extrng *rng;
 
        if (flags & ~(GRND_NONBLOCK | GRND_RANDOM | GRND_INSECURE))
                return -EINVAL;
@@ -1377,6 +1400,21 @@ 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 = import_single_range(ITER_DEST, ubuf, len, &iov, &iter);
+               if (unlikely(ret))
+                       return ret;
+               ret = rng->extrng_read_iter(&iter, !!(flags & GRND_RANDOM));
+               module_put(rng->owner);
+               return ret;
+       }
+
        if (!crng_ready() && !(flags & GRND_INSECURE)) {
                if (flags & GRND_NONBLOCK)
                        return -EAGAIN;
@@ -1397,6 +1435,12 @@ 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];
@@ -1538,7 +1582,58 @@ 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_iter(struct kiocb *kiocb, struct iov_iter *iter)
+{
+       return rcu_dereference_raw(extrng)->extrng_read_iter(iter, false);
+}
+
 const struct file_operations random_fops = {
+       .open  = random_open,
        .read_iter = random_read_iter,
        .write_iter = random_write_iter,
        .poll = random_poll,
@@ -1551,6 +1646,7 @@ const struct file_operations random_fops = {
 };
 
 const struct file_operations urandom_fops = {
+       .open  = urandom_open,
        .read_iter = urandom_read_iter,
        .write_iter = random_write_iter,
        .unlocked_ioctl = random_ioctl,
@@ -1561,6 +1657,32 @@ const struct file_operations urandom_fops = {
        .splice_write = iter_file_splice_write,
 };
 
+static const struct file_operations extrng_random_fops = {
+       .open  = random_open,
+       .read_iter  = extrng_read_iter,
+       .write_iter = random_write_iter,
+       .poll  = extrng_poll,
+       .unlocked_ioctl = random_ioctl,
+       .compat_ioctl = compat_ptr_ioctl,
+       .fasync = random_fasync,
+       .llseek = noop_llseek,
+       .release = extrng_release,
+       .splice_read = copy_splice_read,
+       .splice_write = iter_file_splice_write,
+};
+
+static const struct file_operations extrng_urandom_fops = {
+       .open  = urandom_open,
+       .read_iter  = extrng_read_iter,
+       .write_iter = random_write_iter,
+       .unlocked_ioctl = random_ioctl,
+       .compat_ioctl = compat_ptr_ioctl,
+       .fasync = random_fasync,
+       .llseek = noop_llseek,
+       .release = extrng_release,
+       .splice_read = copy_splice_read,
+       .splice_write = iter_file_splice_write,
+};
 
 /********************************************************************
  *
diff --git a/include/linux/random.h b/include/linux/random.h
index blahblah..blahblah 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -9,6 +9,13 @@
 
 #include <uapi/linux/random.h>
 
+struct iov_iter;
+
+struct random_extrng {
+       ssize_t (*extrng_read_iter)(struct iov_iter *iter, bool reseed);
+       struct module *owner;
+};
+
 struct notifier_block;
 
 void add_device_randomness(const void *buf, size_t len);
@@ -157,6 +164,9 @@ int random_prepare_cpu(unsigned int cpu);
 int random_online_cpu(unsigned int cpu);
 #endif
 
+void random_register_extrng(const struct random_extrng *rng);
+void random_unregister_extrng(void);
+
 #ifndef MODULE
 extern const struct file_operations random_fops, urandom_fops;
 #endif

--
https://gitlab.com/cki-project/kernel-ark/-/merge_requests/2757
_______________________________________________
kernel mailing list -- [email protected]
To unsubscribe send an email to [email protected]
Fedora Code of Conduct: 
https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedoraproject.org/archives/list/[email protected]
Do not reply to spam, report it: 
https://pagure.io/fedora-infrastructure/new_issue

Reply via email to