Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f6b013ee authored by Harald Freudenberger's avatar Harald Freudenberger Committed by Greg Kroah-Hartman
Browse files

hwrng: remember rng chosen by user



commit 10a515ddb5f19a1ff0b9882c430b4427843169f3 upstream.

When a user chooses a rng source via sysfs attribute
this rng should be sticky, even when other sources
with better quality to register. This patch introduces
a simple way to remember the user's choice. This is
reflected by a new sysfs attribute file 'rng_selected'
which shows if the current rng has been chosen by
userspace. The new attribute file shows '1' for user
selected rng and '0' otherwise.

Signed-off-by: default avatarHarald Freudenberger <freude@linux.vnet.ibm.com>
Reviewed-by: default avatarPrasannaKumar Muralidharan <prasannatsmkumar@gmail.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarJason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 42802952
Loading
Loading
Loading
Loading
+19 −2
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@
#define RNG_MODULE_NAME		"hw_random"

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 */
static LIST_HEAD(rng_list);
@@ -303,6 +305,7 @@ static ssize_t hwrng_attr_current_store(struct device *dev,
	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)
				err = set_current_rng(rng);
			break;
@@ -351,16 +354,27 @@ static ssize_t hwrng_attr_available_show(struct device *dev,
	return strlen(buf);
}

static ssize_t hwrng_attr_selected_show(struct device *dev,
					struct device_attribute *attr,
					char *buf)
{
	return snprintf(buf, PAGE_SIZE, "%d\n", cur_rng_set_by_user);
}

static DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR,
		   hwrng_attr_current_show,
		   hwrng_attr_current_store);
static DEVICE_ATTR(rng_available, S_IRUGO,
		   hwrng_attr_available_show,
		   NULL);
static DEVICE_ATTR(rng_selected, S_IRUGO,
		   hwrng_attr_selected_show,
		   NULL);

static struct attribute *rng_dev_attrs[] = {
	&dev_attr_rng_current.attr,
	&dev_attr_rng_available.attr,
	&dev_attr_rng_selected.attr,
	NULL
};

@@ -443,10 +457,12 @@ int hwrng_register(struct hwrng *rng)

	old_rng = current_rng;
	err = 0;
	if (!old_rng || (rng->quality > old_rng->quality)) {
	if (!old_rng ||
	    (!cur_rng_set_by_user && rng->quality > old_rng->quality)) {
		/*
		 * Set new rng as current as the new rng source
		 * provides better entropy quality.
		 * provides better entropy quality and was not
		 * chosen by userspace.
		 */
		err = set_current_rng(rng);
		if (err)
@@ -478,6 +494,7 @@ void hwrng_unregister(struct hwrng *rng)
	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;