* [PATCH 0/4] hw_random: introduce rng_quality sysfs attribute
@ 2022-02-13 20:46 Dominik Brodowski
2022-02-13 20:46 ` [PATCH 1/4] hw_random: do not bother to order list of devices by quality Dominik Brodowski
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Dominik Brodowski @ 2022-02-13 20:46 UTC (permalink / raw)
To: Herbert Xu; +Cc: linux-kernel, linux-crypto, Jason A . Donenfeld
Currently, the hw_random core exposes a module parameter "current_quality".
However, that is fundamentally broken: If it is set at boot time, it is
overwritten once the first hw rng device is loaded. If it is set at
runtime, it is without effect if the hw rng device had its quality value
set to 0 (and no default_quality was set). If a new rng is selected, it
gets overwritten.
Therefore, let's mark it as obsolete, and replace it with a new sysfs
attribute named "rng_quality". This sets the quality setting of the
hw rng device currently loaded and active, and starts/stops the hwrng
kernel thread as required.
Dominik Brodowski (4):
hw_random: do not bother to order list of devices by quality
hw_random: start and stop in-kernel rngd in separate function
hw_random: use per-rng quality value instead of global setting
hw_random: introduce rng_quality sysfs attribute
drivers/char/hw_random/core.c | 145 +++++++++++++++++++++++++---------
1 file changed, 107 insertions(+), 38 deletions(-)
---
If preferred, the "current_quality" module parameter can be removed
altogether.
--
2.35.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/4] hw_random: do not bother to order list of devices by quality
2022-02-13 20:46 [PATCH 0/4] hw_random: introduce rng_quality sysfs attribute Dominik Brodowski
@ 2022-02-13 20:46 ` Dominik Brodowski
2022-02-13 20:46 ` [PATCH 2/4] hw_random: start and stop in-kernel rngd in separate function Dominik Brodowski
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Dominik Brodowski @ 2022-02-13 20:46 UTC (permalink / raw)
To: Herbert Xu; +Cc: linux-kernel, linux-crypto, Jason A . Donenfeld
There is no real reason why this list needs to be kept ordered by
the driver-provided quality value -- a value which is set only by
a handful of hw_random devices anyway.
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
---
drivers/char/hw_random/core.c | 36 ++++++++++++++++-------------------
1 file changed, 16 insertions(+), 20 deletions(-)
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index f327f7493585..6f09f4e5af20 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -31,7 +31,7 @@ static struct hwrng *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, sorted decending by quality */
+/* list of registered rngs */
static LIST_HEAD(rng_list);
/* Protects rng_list and current_rng */
static DEFINE_MUTEX(rng_mutex);
@@ -297,24 +297,28 @@ static struct miscdevice rng_miscdev = {
static int enable_best_rng(void)
{
+ struct hwrng *rng, *new_rng = NULL;
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;
- } else {
+ /* no rng to use? */
+ if (list_empty(&rng_list)) {
drop_current_rng();
cur_rng_set_by_user = 0;
- ret = 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;
+ }
+
+ ret = ((new_rng == current_rng) ? 0 : set_current_rng(new_rng));
+ if (!ret)
+ cur_rng_set_by_user = 0;
+
return ret;
}
@@ -475,7 +479,6 @@ int hwrng_register(struct hwrng *rng)
{
int err = -EINVAL;
struct hwrng *tmp;
- struct list_head *rng_list_ptr;
bool is_new_current = false;
if (!rng->name || (!rng->data_read && !rng->read))
@@ -489,18 +492,11 @@ int hwrng_register(struct hwrng *rng)
if (strcmp(tmp->name, rng->name) == 0)
goto out_unlock;
}
+ list_add_tail(&rng->list, &rng_list);
init_completion(&rng->cleanup_done);
complete(&rng->cleanup_done);
- /* rng_list is sorted by decreasing quality */
- list_for_each(rng_list_ptr, &rng_list) {
- tmp = list_entry(rng_list_ptr, struct hwrng, list);
- if (tmp->quality < rng->quality)
- break;
- }
- list_add_tail(&rng->list, rng_list_ptr);
-
if (!current_rng ||
(!cur_rng_set_by_user && rng->quality > current_rng->quality)) {
/*
--
2.35.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/4] hw_random: start and stop in-kernel rngd in separate function
2022-02-13 20:46 [PATCH 0/4] hw_random: introduce rng_quality sysfs attribute Dominik Brodowski
2022-02-13 20:46 ` [PATCH 1/4] hw_random: do not bother to order list of devices by quality Dominik Brodowski
@ 2022-02-13 20:46 ` Dominik Brodowski
2022-02-13 20:46 ` [PATCH 3/4] hw_random: use per-rng quality value instead of global setting Dominik Brodowski
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Dominik Brodowski @ 2022-02-13 20:46 UTC (permalink / raw)
To: Herbert Xu; +Cc: linux-kernel, linux-crypto, Jason A . Donenfeld
Extract the start/stop logic for the in-kernel rngd thread to
a separate function.
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
---
drivers/char/hw_random/core.c | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 6f09f4e5af20..29febf55b0d4 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -51,7 +51,7 @@ MODULE_PARM_DESC(default_quality,
static void drop_current_rng(void);
static int hwrng_init(struct hwrng *rng);
-static void start_khwrngd(void);
+static void hwrng_manage_rngd(void);
static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size,
int wait);
@@ -164,10 +164,7 @@ static int hwrng_init(struct hwrng *rng)
if (current_quality > 1024)
current_quality = 1024;
- if (current_quality == 0 && hwrng_fill)
- kthread_stop(hwrng_fill);
- if (current_quality > 0 && !hwrng_fill)
- start_khwrngd();
+ hwrng_manage_rngd();
return 0;
}
@@ -466,12 +463,19 @@ static int hwrng_fillfn(void *unused)
return 0;
}
-static void start_khwrngd(void)
+static void hwrng_manage_rngd(void)
{
- hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng");
- if (IS_ERR(hwrng_fill)) {
- pr_err("hwrng_fill thread creation failed\n");
- hwrng_fill = NULL;
+ if (WARN_ON(!mutex_is_locked(&rng_mutex)))
+ return;
+
+ if (current_quality == 0 && hwrng_fill)
+ kthread_stop(hwrng_fill);
+ if (current_quality > 0 && !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;
+ }
}
}
--
2.35.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 3/4] hw_random: use per-rng quality value instead of global setting
2022-02-13 20:46 [PATCH 0/4] hw_random: introduce rng_quality sysfs attribute Dominik Brodowski
2022-02-13 20:46 ` [PATCH 1/4] hw_random: do not bother to order list of devices by quality Dominik Brodowski
2022-02-13 20:46 ` [PATCH 2/4] hw_random: start and stop in-kernel rngd in separate function Dominik Brodowski
@ 2022-02-13 20:46 ` Dominik Brodowski
2022-02-13 20:46 ` [PATCH 4/4] hw_random: introduce rng_quality sysfs attribute Dominik Brodowski
2022-02-23 2:45 ` [PATCH 0/4] " Herbert Xu
4 siblings, 0 replies; 6+ messages in thread
From: Dominik Brodowski @ 2022-02-13 20:46 UTC (permalink / raw)
To: Herbert Xu; +Cc: linux-kernel, linux-crypto, Jason A . Donenfeld
The current_quality variable exposed as a module parameter is
fundamentally broken: If it is set at boot time, it is overwritten once
the first hw rng device is loaded; if it is set at runtime, it is
without effect if the hw rng device had its quality value set to 0 (and
no default_quality was set); and if a new rng is selected, it gets
overwritten. Therefore, mark it as obsolete, and replace it by the
per-rng quality setting.
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
---
drivers/char/hw_random/core.c | 33 ++++++++++++++++++++-------------
1 file changed, 20 insertions(+), 13 deletions(-)
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 29febf55b0d4..8df102b39b35 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -44,14 +44,14 @@ static unsigned short default_quality; /* = 0; default to "off" */
module_param(current_quality, ushort, 0644);
MODULE_PARM_DESC(current_quality,
- "current hwrng entropy estimation per 1024 bits of input");
+ "current hwrng entropy estimation per 1024 bits of input -- obsolete");
module_param(default_quality, ushort, 0644);
MODULE_PARM_DESC(default_quality,
"default entropy content of hwrng per 1024 bits of input");
static void drop_current_rng(void);
static int hwrng_init(struct hwrng *rng);
-static void hwrng_manage_rngd(void);
+static void hwrng_manage_rngd(struct hwrng *rng);
static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size,
int wait);
@@ -160,11 +160,13 @@ static int hwrng_init(struct hwrng *rng)
reinit_completion(&rng->cleanup_done);
skip_init:
- current_quality = rng->quality ? : default_quality;
- if (current_quality > 1024)
- current_quality = 1024;
+ if (!rng->quality)
+ rng->quality = default_quality;
+ if (rng->quality > 1024)
+ rng->quality = 1024;
+ current_quality = rng->quality; /* obsolete */
- hwrng_manage_rngd();
+ hwrng_manage_rngd(rng);
return 0;
}
@@ -429,19 +431,24 @@ static int hwrng_fillfn(void *unused)
long rc;
while (!kthread_should_stop()) {
+ unsigned short quality;
struct hwrng *rng;
- if (!current_quality)
- break;
-
rng = get_current_rng();
if (IS_ERR(rng) || !rng)
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);
put_rng(rng);
+
+ if (!quality)
+ break;
+
if (rc <= 0) {
pr_warn("hwrng: no data available\n");
msleep_interruptible(10000);
@@ -451,7 +458,7 @@ static int hwrng_fillfn(void *unused)
/* If we cannot credit at least one bit of entropy,
* keep track of the remainder for the next iteration
*/
- entropy = rc * current_quality * 8 + entropy_credit;
+ entropy = rc * quality * 8 + entropy_credit;
if ((entropy >> 10) == 0)
entropy_credit = entropy;
@@ -463,14 +470,14 @@ static int hwrng_fillfn(void *unused)
return 0;
}
-static void hwrng_manage_rngd(void)
+static void hwrng_manage_rngd(struct hwrng *rng)
{
if (WARN_ON(!mutex_is_locked(&rng_mutex)))
return;
- if (current_quality == 0 && hwrng_fill)
+ if (rng->quality == 0 && hwrng_fill)
kthread_stop(hwrng_fill);
- if (current_quality > 0 && !hwrng_fill) {
+ if (rng->quality > 0 && !hwrng_fill) {
hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng");
if (IS_ERR(hwrng_fill)) {
pr_err("hwrng_fill thread creation failed\n");
--
2.35.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 4/4] hw_random: introduce rng_quality sysfs attribute
2022-02-13 20:46 [PATCH 0/4] hw_random: introduce rng_quality sysfs attribute Dominik Brodowski
` (2 preceding siblings ...)
2022-02-13 20:46 ` [PATCH 3/4] hw_random: use per-rng quality value instead of global setting Dominik Brodowski
@ 2022-02-13 20:46 ` Dominik Brodowski
2022-02-23 2:45 ` [PATCH 0/4] " Herbert Xu
4 siblings, 0 replies; 6+ messages in thread
From: Dominik Brodowski @ 2022-02-13 20:46 UTC (permalink / raw)
To: Herbert Xu; +Cc: linux-kernel, linux-crypto, Jason A . Donenfeld
The rng_quality sysfs attribute returns the quality setting for the
currently active hw_random device, in entropy bits per 1024 bits of
input. Storing a value between 0 and 1024 to this file updates this
estimate accordingly.
Based on the updates to the quality setting, the rngd kernel thread
may be stopped (if no hw_random device is trusted to return entropy),
may be started (if the quality setting is increased from zero), or
may use a different hw_random source (if that has higher quality
output).
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
---
drivers/char/hw_random/core.c | 64 ++++++++++++++++++++++++++++++++++-
1 file changed, 63 insertions(+), 1 deletion(-)
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 8df102b39b35..71eafcc451e1 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -44,7 +44,7 @@ static unsigned short default_quality; /* = 0; default to "off" */
module_param(current_quality, ushort, 0644);
MODULE_PARM_DESC(current_quality,
- "current hwrng entropy estimation per 1024 bits of input -- obsolete");
+ "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 entropy content of hwrng per 1024 bits of input");
@@ -402,14 +402,76 @@ static ssize_t rng_selected_show(struct device *dev,
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 (IS_ERR(rng))
+ return PTR_ERR(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)
+{
+ 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;
+ }
+
+ if (!current_rng) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ current_rng->quality = quality;
+ current_quality = quality; /* obsolete */
+
+ /* the best available RNG may have changed */
+ ret = enable_best_rng();
+
+ /* start/stop rngd if necessary */
+ if (current_rng)
+ hwrng_manage_rngd(current_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
};
--
2.35.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 0/4] hw_random: introduce rng_quality sysfs attribute
2022-02-13 20:46 [PATCH 0/4] hw_random: introduce rng_quality sysfs attribute Dominik Brodowski
` (3 preceding siblings ...)
2022-02-13 20:46 ` [PATCH 4/4] hw_random: introduce rng_quality sysfs attribute Dominik Brodowski
@ 2022-02-23 2:45 ` Herbert Xu
4 siblings, 0 replies; 6+ messages in thread
From: Herbert Xu @ 2022-02-23 2:45 UTC (permalink / raw)
To: Dominik Brodowski; +Cc: linux-kernel, linux-crypto, Jason A . Donenfeld
On Sun, Feb 13, 2022 at 09:46:27PM +0100, Dominik Brodowski wrote:
> Currently, the hw_random core exposes a module parameter "current_quality".
> However, that is fundamentally broken: If it is set at boot time, it is
> overwritten once the first hw rng device is loaded. If it is set at
> runtime, it is without effect if the hw rng device had its quality value
> set to 0 (and no default_quality was set). If a new rng is selected, it
> gets overwritten.
>
> Therefore, let's mark it as obsolete, and replace it with a new sysfs
> attribute named "rng_quality". This sets the quality setting of the
> hw rng device currently loaded and active, and starts/stops the hwrng
> kernel thread as required.
>
> Dominik Brodowski (4):
> hw_random: do not bother to order list of devices by quality
> hw_random: start and stop in-kernel rngd in separate function
> hw_random: use per-rng quality value instead of global setting
> hw_random: introduce rng_quality sysfs attribute
>
> drivers/char/hw_random/core.c | 145 +++++++++++++++++++++++++---------
> 1 file changed, 107 insertions(+), 38 deletions(-)
All applied. Thanks.
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2022-02-23 2:47 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-13 20:46 [PATCH 0/4] hw_random: introduce rng_quality sysfs attribute Dominik Brodowski
2022-02-13 20:46 ` [PATCH 1/4] hw_random: do not bother to order list of devices by quality Dominik Brodowski
2022-02-13 20:46 ` [PATCH 2/4] hw_random: start and stop in-kernel rngd in separate function Dominik Brodowski
2022-02-13 20:46 ` [PATCH 3/4] hw_random: use per-rng quality value instead of global setting Dominik Brodowski
2022-02-13 20:46 ` [PATCH 4/4] hw_random: introduce rng_quality sysfs attribute Dominik Brodowski
2022-02-23 2:45 ` [PATCH 0/4] " Herbert Xu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®