| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739 |
- /*
- * hw_random/core.c: HWRNG core API
- *
- * Copyright 2006 Michael Buesch <m@bues.ch>
- * Copyright 2005 (c) MontaVista Software, Inc.
- *
- * Please read Documentation/admin-guide/hw_random.rst for details on use.
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
- #include <linux/delay.h>
- #include <linux/device.h>
- #include <linux/err.h>
- #include <linux/fs.h>
- #include <linux/hw_random.h>
- #include <linux/kernel.h>
- #include <linux/kthread.h>
- #include <linux/miscdevice.h>
- #include <linux/module.h>
- #include <linux/random.h>
- #include <linux/rcupdate.h>
- #include <linux/sched.h>
- #include <linux/sched/signal.h>
- #include <linux/slab.h>
- #include <linux/string.h>
- #include <linux/uaccess.h>
- #include <linux/workqueue.h>
- #define RNG_MODULE_NAME "hw_random"
- #define RNG_BUFFER_SIZE (SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES)
- static struct hwrng __rcu *current_rng;
- /* the current rng has been explicitly chosen by user via sysfs */
- static int cur_rng_set_by_user;
- static struct task_struct *hwrng_fill;
- /* list of registered rngs */
- static LIST_HEAD(rng_list);
- /* Protects rng_list, hwrng_fill and updating on current_rng */
- static DEFINE_MUTEX(rng_mutex);
- /* Protects rng read functions, data_avail, rng_buffer and rng_fillbuf */
- static DEFINE_MUTEX(reading_mutex);
- static int data_avail;
- static u8 *rng_buffer, *rng_fillbuf;
- static unsigned short current_quality;
- static unsigned short default_quality = 1024; /* default to maximum */
- module_param(current_quality, ushort, 0644);
- MODULE_PARM_DESC(current_quality,
- "current hwrng entropy estimation per 1024 bits of input -- obsolete, use rng_quality instead");
- module_param(default_quality, ushort, 0644);
- MODULE_PARM_DESC(default_quality,
- "default maximum entropy content of hwrng per 1024 bits of input");
- static void drop_current_rng(void);
- static int hwrng_init(struct hwrng *rng);
- static int hwrng_fillfn(void *unused);
- static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size,
- int wait);
- static size_t rng_buffer_size(void)
- {
- return RNG_BUFFER_SIZE;
- }
- static void cleanup_rng_work(struct work_struct *work)
- {
- struct hwrng *rng = container_of(work, struct hwrng, cleanup_work);
- /*
- * Hold rng_mutex here so we serialize in case they set_current_rng
- * on rng again immediately.
- */
- mutex_lock(&rng_mutex);
- /* Skip if rng has been reinitialized. */
- if (kref_read(&rng->ref)) {
- mutex_unlock(&rng_mutex);
- return;
- }
- if (rng->cleanup)
- rng->cleanup(rng);
- complete(&rng->cleanup_done);
- mutex_unlock(&rng_mutex);
- }
- static inline void cleanup_rng(struct kref *kref)
- {
- struct hwrng *rng = container_of(kref, struct hwrng, ref);
- schedule_work(&rng->cleanup_work);
- }
- static int set_current_rng(struct hwrng *rng)
- {
- struct hwrng *old_rng;
- int err;
- BUG_ON(!mutex_is_locked(&rng_mutex));
- err = hwrng_init(rng);
- if (err)
- return err;
- old_rng = rcu_dereference_protected(current_rng,
- lockdep_is_held(&rng_mutex));
- rcu_assign_pointer(current_rng, rng);
- if (old_rng) {
- synchronize_rcu();
- kref_put(&old_rng->ref, cleanup_rng);
- }
- /* if necessary, start hwrng thread */
- if (!hwrng_fill) {
- hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng");
- if (IS_ERR(hwrng_fill)) {
- pr_err("hwrng_fill thread creation failed\n");
- hwrng_fill = NULL;
- }
- }
- return 0;
- }
- static void drop_current_rng(void)
- {
- struct hwrng *rng;
- rng = rcu_dereference_protected(current_rng,
- lockdep_is_held(&rng_mutex));
- if (!rng)
- return;
- RCU_INIT_POINTER(current_rng, NULL);
- synchronize_rcu();
- if (hwrng_fill) {
- kthread_stop(hwrng_fill);
- hwrng_fill = NULL;
- }
- /* decrease last reference for triggering the cleanup */
- kref_put(&rng->ref, cleanup_rng);
- }
- /* Returns NULL or refcounted hwrng */
- static struct hwrng *get_current_rng_nolock(void)
- {
- struct hwrng *rng;
- rng = rcu_dereference_protected(current_rng,
- lockdep_is_held(&rng_mutex));
- if (rng)
- kref_get(&rng->ref);
- return rng;
- }
- static struct hwrng *get_current_rng(void)
- {
- struct hwrng *rng;
- rcu_read_lock();
- rng = rcu_dereference(current_rng);
- if (rng)
- kref_get(&rng->ref);
- rcu_read_unlock();
- return rng;
- }
- static void put_rng(struct hwrng *rng)
- {
- if (rng)
- kref_put(&rng->ref, cleanup_rng);
- }
- static int hwrng_init(struct hwrng *rng)
- {
- if (kref_get_unless_zero(&rng->ref))
- goto skip_init;
- if (rng->init) {
- int ret;
- ret = rng->init(rng);
- if (ret)
- return ret;
- }
- kref_init(&rng->ref);
- reinit_completion(&rng->cleanup_done);
- skip_init:
- current_quality = rng->quality; /* obsolete */
- return 0;
- }
- static int rng_dev_open(struct inode *inode, struct file *filp)
- {
- /* enforce read-only access to this chrdev */
- if ((filp->f_mode & FMODE_READ) == 0)
- return -EINVAL;
- if (filp->f_mode & FMODE_WRITE)
- return -EINVAL;
- return 0;
- }
- static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size,
- int wait) {
- int present;
- BUG_ON(!mutex_is_locked(&reading_mutex));
- if (rng->read) {
- int err;
- err = rng->read(rng, buffer, size, wait);
- if (WARN_ON_ONCE(err > 0 && err > size))
- err = size;
- return err;
- }
- if (rng->data_present)
- present = rng->data_present(rng, wait);
- else
- present = 1;
- if (present)
- return rng->data_read(rng, (u32 *)buffer);
- return 0;
- }
- static ssize_t rng_dev_read(struct file *filp, char __user *buf,
- size_t size, loff_t *offp)
- {
- u8 buffer[RNG_BUFFER_SIZE];
- ssize_t ret = 0;
- int err = 0;
- int bytes_read, len;
- struct hwrng *rng;
- while (size) {
- rng = get_current_rng();
- if (!rng) {
- err = -ENODEV;
- goto out;
- }
- if (mutex_lock_interruptible(&reading_mutex)) {
- err = -ERESTARTSYS;
- goto out_put;
- }
- if (!data_avail) {
- bytes_read = rng_get_data(rng, rng_buffer,
- rng_buffer_size(),
- !(filp->f_flags & O_NONBLOCK));
- if (bytes_read < 0) {
- err = bytes_read;
- goto out_unlock_reading;
- } else if (bytes_read == 0 &&
- (filp->f_flags & O_NONBLOCK)) {
- err = -EAGAIN;
- goto out_unlock_reading;
- }
- data_avail = bytes_read;
- }
- len = data_avail;
- if (len) {
- if (len > size)
- len = size;
- data_avail -= len;
- memcpy(buffer, rng_buffer + data_avail, len);
- }
- mutex_unlock(&reading_mutex);
- put_rng(rng);
- if (len) {
- if (copy_to_user(buf + ret, buffer, len)) {
- err = -EFAULT;
- goto out;
- }
- size -= len;
- ret += len;
- }
- if (need_resched())
- schedule_timeout_interruptible(1);
- if (signal_pending(current)) {
- err = -ERESTARTSYS;
- goto out;
- }
- }
- out:
- memzero_explicit(buffer, sizeof(buffer));
- return ret ? : err;
- out_unlock_reading:
- mutex_unlock(&reading_mutex);
- out_put:
- put_rng(rng);
- goto out;
- }
- static const struct file_operations rng_chrdev_ops = {
- .owner = THIS_MODULE,
- .open = rng_dev_open,
- .read = rng_dev_read,
- .llseek = noop_llseek,
- };
- static const struct attribute_group *rng_dev_groups[];
- static struct miscdevice rng_miscdev = {
- .minor = HWRNG_MINOR,
- .name = RNG_MODULE_NAME,
- .nodename = "hwrng",
- .fops = &rng_chrdev_ops,
- .groups = rng_dev_groups,
- };
- static int enable_best_rng(void)
- {
- struct hwrng *rng, *cur_rng, *new_rng = NULL;
- int ret = -ENODEV;
- BUG_ON(!mutex_is_locked(&rng_mutex));
- /* no rng to use? */
- if (list_empty(&rng_list)) {
- drop_current_rng();
- cur_rng_set_by_user = 0;
- return 0;
- }
- /* use the rng which offers the best quality */
- list_for_each_entry(rng, &rng_list, list) {
- if (!new_rng || rng->quality > new_rng->quality)
- new_rng = rng;
- }
- cur_rng = rcu_dereference_protected(current_rng,
- lockdep_is_held(&rng_mutex));
- ret = ((new_rng == cur_rng) ? 0 : set_current_rng(new_rng));
- if (!ret)
- cur_rng_set_by_user = 0;
- return ret;
- }
- static ssize_t rng_current_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
- {
- int err;
- struct hwrng *rng, *new_rng;
- err = mutex_lock_interruptible(&rng_mutex);
- if (err)
- return -ERESTARTSYS;
- if (sysfs_streq(buf, "")) {
- err = enable_best_rng();
- } else if (sysfs_streq(buf, "none")) {
- cur_rng_set_by_user = 1;
- drop_current_rng();
- } else {
- list_for_each_entry(rng, &rng_list, list) {
- if (sysfs_streq(rng->name, buf)) {
- err = set_current_rng(rng);
- if (!err)
- cur_rng_set_by_user = 1;
- break;
- }
- }
- }
- new_rng = get_current_rng_nolock();
- mutex_unlock(&rng_mutex);
- if (new_rng)
- put_rng(new_rng);
- return err ? : len;
- }
- static ssize_t rng_current_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
- {
- ssize_t ret;
- struct hwrng *rng;
- rng = get_current_rng();
- ret = sysfs_emit(buf, "%s\n", rng ? rng->name : "none");
- put_rng(rng);
- return ret;
- }
- static ssize_t rng_available_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
- {
- int err;
- struct hwrng *rng;
- err = mutex_lock_interruptible(&rng_mutex);
- if (err)
- return -ERESTARTSYS;
- buf[0] = '\0';
- list_for_each_entry(rng, &rng_list, list) {
- strlcat(buf, rng->name, PAGE_SIZE);
- strlcat(buf, " ", PAGE_SIZE);
- }
- strlcat(buf, "none\n", PAGE_SIZE);
- mutex_unlock(&rng_mutex);
- return strlen(buf);
- }
- static ssize_t rng_selected_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
- {
- return sysfs_emit(buf, "%d\n", cur_rng_set_by_user);
- }
- static ssize_t rng_quality_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
- {
- ssize_t ret;
- struct hwrng *rng;
- rng = get_current_rng();
- if (!rng) /* no need to put_rng */
- return -ENODEV;
- ret = sysfs_emit(buf, "%hu\n", rng->quality);
- put_rng(rng);
- return ret;
- }
- static ssize_t rng_quality_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
- {
- struct hwrng *rng;
- u16 quality;
- int ret = -EINVAL;
- if (len < 2)
- return -EINVAL;
- ret = mutex_lock_interruptible(&rng_mutex);
- if (ret)
- return -ERESTARTSYS;
- ret = kstrtou16(buf, 0, &quality);
- if (ret || quality > 1024) {
- ret = -EINVAL;
- goto out;
- }
- rng = rcu_dereference_protected(current_rng, lockdep_is_held(&rng_mutex));
- if (!rng) {
- ret = -ENODEV;
- goto out;
- }
- rng->quality = quality;
- current_quality = quality; /* obsolete */
- /* the best available RNG may have changed */
- ret = enable_best_rng();
- out:
- mutex_unlock(&rng_mutex);
- return ret ? ret : len;
- }
- static DEVICE_ATTR_RW(rng_current);
- static DEVICE_ATTR_RO(rng_available);
- static DEVICE_ATTR_RO(rng_selected);
- static DEVICE_ATTR_RW(rng_quality);
- static struct attribute *rng_dev_attrs[] = {
- &dev_attr_rng_current.attr,
- &dev_attr_rng_available.attr,
- &dev_attr_rng_selected.attr,
- &dev_attr_rng_quality.attr,
- NULL
- };
- ATTRIBUTE_GROUPS(rng_dev);
- static int hwrng_fillfn(void *unused)
- {
- size_t entropy, entropy_credit = 0; /* in 1/1024 of a bit */
- long rc;
- while (!kthread_should_stop()) {
- unsigned short quality;
- struct hwrng *rng;
- rng = get_current_rng();
- if (!rng) {
- /*
- * Keep the task_struct alive until kthread_stop()
- * is called to avoid UAF in drop_current_rng().
- */
- while (!kthread_should_stop()) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (!kthread_should_stop())
- schedule();
- }
- set_current_state(TASK_RUNNING);
- break;
- }
- mutex_lock(&reading_mutex);
- rc = rng_get_data(rng, rng_fillbuf,
- rng_buffer_size(), 1);
- if (current_quality != rng->quality)
- rng->quality = current_quality; /* obsolete */
- quality = rng->quality;
- mutex_unlock(&reading_mutex);
- if (rc <= 0)
- hwrng_msleep(rng, 10000);
- put_rng(rng);
- if (rc <= 0)
- continue;
- /* If we cannot credit at least one bit of entropy,
- * keep track of the remainder for the next iteration
- */
- entropy = rc * quality * 8 + entropy_credit;
- if ((entropy >> 10) == 0)
- entropy_credit = entropy;
- /* Outside lock, sure, but y'know: randomness. */
- add_hwgenerator_randomness((void *)rng_fillbuf, rc,
- entropy >> 10, true);
- }
- return 0;
- }
- int hwrng_register(struct hwrng *rng)
- {
- int err = -EINVAL;
- struct hwrng *cur_rng, *tmp;
- if (!rng->name || (!rng->data_read && !rng->read))
- goto out;
- mutex_lock(&rng_mutex);
- /* Must not register two RNGs with the same name. */
- err = -EEXIST;
- list_for_each_entry(tmp, &rng_list, list) {
- if (strcmp(tmp->name, rng->name) == 0)
- goto out_unlock;
- }
- list_add_tail(&rng->list, &rng_list);
- INIT_WORK(&rng->cleanup_work, cleanup_rng_work);
- init_completion(&rng->cleanup_done);
- complete(&rng->cleanup_done);
- init_completion(&rng->dying);
- /* Adjust quality field to always have a proper value */
- rng->quality = min3(default_quality, 1024, rng->quality ?: 1024);
- if (!cur_rng_set_by_user) {
- cur_rng = rcu_dereference_protected(current_rng,
- lockdep_is_held(&rng_mutex));
- if (!cur_rng || rng->quality > cur_rng->quality) {
- /*
- * Set new rng as current as the new rng source
- * provides better entropy quality and was not
- * chosen by userspace.
- */
- err = set_current_rng(rng);
- if (err)
- goto out_unlock;
- }
- }
- mutex_unlock(&rng_mutex);
- return 0;
- out_unlock:
- mutex_unlock(&rng_mutex);
- out:
- return err;
- }
- EXPORT_SYMBOL_GPL(hwrng_register);
- void hwrng_unregister(struct hwrng *rng)
- {
- struct hwrng *cur_rng;
- int err;
- mutex_lock(&rng_mutex);
- list_del(&rng->list);
- complete_all(&rng->dying);
- cur_rng = rcu_dereference_protected(current_rng,
- lockdep_is_held(&rng_mutex));
- if (cur_rng == rng) {
- err = enable_best_rng();
- if (err) {
- drop_current_rng();
- cur_rng_set_by_user = 0;
- }
- }
- mutex_unlock(&rng_mutex);
- wait_for_completion(&rng->cleanup_done);
- }
- EXPORT_SYMBOL_GPL(hwrng_unregister);
- static void devm_hwrng_release(struct device *dev, void *res)
- {
- hwrng_unregister(*(struct hwrng **)res);
- }
- static int devm_hwrng_match(struct device *dev, void *res, void *data)
- {
- struct hwrng **r = res;
- if (WARN_ON(!r || !*r))
- return 0;
- return *r == data;
- }
- int devm_hwrng_register(struct device *dev, struct hwrng *rng)
- {
- struct hwrng **ptr;
- int error;
- ptr = devres_alloc(devm_hwrng_release, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return -ENOMEM;
- error = hwrng_register(rng);
- if (error) {
- devres_free(ptr);
- return error;
- }
- *ptr = rng;
- devres_add(dev, ptr);
- return 0;
- }
- EXPORT_SYMBOL_GPL(devm_hwrng_register);
- void devm_hwrng_unregister(struct device *dev, struct hwrng *rng)
- {
- devres_release(dev, devm_hwrng_release, devm_hwrng_match, rng);
- }
- EXPORT_SYMBOL_GPL(devm_hwrng_unregister);
- long hwrng_msleep(struct hwrng *rng, unsigned int msecs)
- {
- unsigned long timeout = msecs_to_jiffies(msecs) + 1;
- return wait_for_completion_interruptible_timeout(&rng->dying, timeout);
- }
- EXPORT_SYMBOL_GPL(hwrng_msleep);
- long hwrng_yield(struct hwrng *rng)
- {
- return wait_for_completion_interruptible_timeout(&rng->dying, 1);
- }
- EXPORT_SYMBOL_GPL(hwrng_yield);
- static int __init hwrng_modinit(void)
- {
- int ret;
- /* kmalloc makes this safe for virt_to_page() in virtio_rng.c */
- rng_buffer = kmalloc(rng_buffer_size(), GFP_KERNEL);
- if (!rng_buffer)
- return -ENOMEM;
- rng_fillbuf = kmalloc(rng_buffer_size(), GFP_KERNEL);
- if (!rng_fillbuf) {
- kfree(rng_buffer);
- return -ENOMEM;
- }
- ret = misc_register(&rng_miscdev);
- if (ret) {
- kfree(rng_fillbuf);
- kfree(rng_buffer);
- }
- return ret;
- }
- static void __exit hwrng_modexit(void)
- {
- mutex_lock(&rng_mutex);
- WARN_ON(rcu_access_pointer(current_rng));
- kfree(rng_buffer);
- kfree(rng_fillbuf);
- mutex_unlock(&rng_mutex);
- misc_deregister(&rng_miscdev);
- }
- fs_initcall(hwrng_modinit); /* depends on misc_register() */
- module_exit(hwrng_modexit);
- MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
- MODULE_LICENSE("GPL");
|