summaryrefslogtreecommitdiffstats
path: root/drivers/char/hw_random/core.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-11-14 19:52:09 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2017-11-14 19:52:09 +0100
commit37dc79565c4b7e735f190eaa6ed5bb6eb3d3968a (patch)
tree4f20cc3c9240c5759f72bf560b596a809173ee29 /drivers/char/hw_random/core.c
parentMerge tag 'usb-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gre... (diff)
parentlib/mpi: call cond_resched() from mpi_powm() loop (diff)
downloadlinux-37dc79565c4b7e735f190eaa6ed5bb6eb3d3968a.tar.xz
linux-37dc79565c4b7e735f190eaa6ed5bb6eb3d3968a.zip
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
Pull crypto updates from Herbert Xu: "Here is the crypto update for 4.15: API: - Disambiguate EBUSY when queueing crypto request by adding ENOSPC. This change touches code outside the crypto API. - Reset settings when empty string is written to rng_current. Algorithms: - Add OSCCA SM3 secure hash. Drivers: - Remove old mv_cesa driver (replaced by marvell/cesa). - Enable rfc3686/ecb/cfb/ofb AES in crypto4xx. - Add ccm/gcm AES in crypto4xx. - Add support for BCM7278 in iproc-rng200. - Add hash support on Exynos in s5p-sss. - Fix fallback-induced error in vmx. - Fix output IV in atmel-aes. - Fix empty GCM hash in mediatek. Others: - Fix DoS potential in lib/mpi. - Fix potential out-of-order issues with padata" * 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (162 commits) lib/mpi: call cond_resched() from mpi_powm() loop crypto: stm32/hash - Fix return issue on update crypto: dh - Remove pointless checks for NULL 'p' and 'g' crypto: qat - Clean up error handling in qat_dh_set_secret() crypto: dh - Don't permit 'key' or 'g' size longer than 'p' crypto: dh - Don't permit 'p' to be 0 crypto: dh - Fix double free of ctx->p hwrng: iproc-rng200 - Add support for BCM7278 dt-bindings: rng: Document BCM7278 RNG200 compatible crypto: chcr - Replace _manual_ swap with swap macro crypto: marvell - Add a NULL entry at the end of mv_cesa_plat_id_table[] hwrng: virtio - Virtio RNG devices need to be re-registered after suspend/resume crypto: atmel - remove empty functions crypto: ecdh - remove empty exit() MAINTAINERS: update maintainer for qat crypto: caam - remove unused param of ctx_map_to_sec4_sg() crypto: caam - remove unneeded edesc zeroization crypto: atmel-aes - Reset the controller before each use crypto: atmel-aes - properly set IV after {en,de}crypt hwrng: core - Reset user selected rng by writing "" to rng_current ...
Diffstat (limited to 'drivers/char/hw_random/core.c')
-rw-r--r--drivers/char/hw_random/core.c53
1 files changed, 33 insertions, 20 deletions
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 9701ac7d8b47..657b8770b6b9 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -292,26 +292,48 @@ static struct miscdevice rng_miscdev = {
.groups = rng_dev_groups,
};
+static int enable_best_rng(void)
+{
+ int ret = -ENODEV;
+
+ BUG_ON(!mutex_is_locked(&rng_mutex));
+
+ /* rng_list is sorted by quality, use the best (=first) one */
+ if (!list_empty(&rng_list)) {
+ struct hwrng *new_rng;
+
+ new_rng = list_entry(rng_list.next, struct hwrng, list);
+ ret = ((new_rng == current_rng) ? 0 : set_current_rng(new_rng));
+ if (!ret)
+ cur_rng_set_by_user = 0;
+ }
+
+ return ret;
+}
+
static ssize_t hwrng_attr_current_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- int err;
+ int err = -ENODEV;
struct hwrng *rng;
err = mutex_lock_interruptible(&rng_mutex);
if (err)
return -ERESTARTSYS;
- err = -ENODEV;
- list_for_each_entry(rng, &rng_list, list) {
- if (sysfs_streq(rng->name, buf)) {
- err = 0;
- cur_rng_set_by_user = 1;
- if (rng != current_rng)
+
+ if (sysfs_streq(buf, "")) {
+ err = enable_best_rng();
+ } else {
+ list_for_each_entry(rng, &rng_list, list) {
+ if (sysfs_streq(rng->name, buf)) {
+ cur_rng_set_by_user = 1;
err = set_current_rng(rng);
- break;
+ break;
+ }
}
}
+
mutex_unlock(&rng_mutex);
return err ? : len;
@@ -423,7 +445,7 @@ static void start_khwrngd(void)
{
hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng");
if (IS_ERR(hwrng_fill)) {
- pr_err("hwrng_fill thread creation failed");
+ pr_err("hwrng_fill thread creation failed\n");
hwrng_fill = NULL;
}
}
@@ -493,17 +515,8 @@ void hwrng_unregister(struct hwrng *rng)
mutex_lock(&rng_mutex);
list_del(&rng->list);
- if (current_rng == rng) {
- drop_current_rng();
- cur_rng_set_by_user = 0;
- /* rng_list is sorted by quality, use the best (=first) one */
- if (!list_empty(&rng_list)) {
- struct hwrng *new_rng;
-
- new_rng = list_entry(rng_list.next, struct hwrng, list);
- set_current_rng(new_rng);
- }
- }
+ if (current_rng == rng)
+ enable_best_rng();
if (list_empty(&rng_list)) {
mutex_unlock(&rng_mutex);