* [PATCH v2 0/2] random: fix some data races
@ 2021-12-20 22:41 Eric Biggers
2021-12-20 22:41 ` [PATCH v2 1/2] random: fix data race on crng_node_pool Eric Biggers
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Eric Biggers @ 2021-12-20 22:41 UTC (permalink / raw)
To: Theodore Ts'o, Jason A . Donenfeld
Cc: linux-kernel, linux-crypto, Paul E . McKenney
This series fixes some data races in random.c.
Changed v1 => v2:
- Remove unneeded 'inline' keywords
- Use READ_ONCE() instead of smp_load_acquire()
- Updated commit message
- Added patch to fix data race on crng init time
Eric Biggers (2):
random: fix data race on crng_node_pool
random: fix data race on crng init time
drivers/char/random.c | 61 +++++++++++++++++++++++--------------------
1 file changed, 33 insertions(+), 28 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 1/2] random: fix data race on crng_node_pool
2021-12-20 22:41 [PATCH v2 0/2] random: fix some data races Eric Biggers
@ 2021-12-20 22:41 ` Eric Biggers
2021-12-20 22:41 ` [PATCH v2 2/2] random: fix data race on crng init time Eric Biggers
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Eric Biggers @ 2021-12-20 22:41 UTC (permalink / raw)
To: Theodore Ts'o, Jason A . Donenfeld
Cc: linux-kernel, linux-crypto, Paul E . McKenney, stable
From: Eric Biggers <ebiggers@google.com>
extract_crng() and crng_backtrack_protect() load crng_node_pool with a
plain load, which causes undefined behavior if do_numa_crng_init()
modifies it concurrently.
Fix this by using READ_ONCE(). Note: as per the previous discussion
https://lore.kernel.org/lkml/20211219025139.31085-1-ebiggers@kernel.org/T/#u,
READ_ONCE() is believed to be sufficient here, and it was requested that
it be used here instead of smp_load_acquire().
Also change do_numa_crng_init() to set crng_node_pool using
cmpxchg_release() instead of mb() + cmpxchg(), as the former is
sufficient here but is more lightweight.
Fixes: 1e7f583af67b ("random: make /dev/urandom scalable for silly userspace programs")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
drivers/char/random.c | 42 ++++++++++++++++++++++--------------------
1 file changed, 22 insertions(+), 20 deletions(-)
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 605969ed0f96..1294b4527cdd 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -843,8 +843,8 @@ static void do_numa_crng_init(struct work_struct *work)
crng_initialize_secondary(crng);
pool[i] = crng;
}
- mb();
- if (cmpxchg(&crng_node_pool, NULL, pool)) {
+ /* pairs with READ_ONCE() in select_crng() */
+ if (cmpxchg_release(&crng_node_pool, NULL, pool) != NULL) {
for_each_node(i)
kfree(pool[i]);
kfree(pool);
@@ -857,8 +857,26 @@ static void numa_crng_init(void)
{
schedule_work(&numa_crng_init_work);
}
+
+static struct crng_state *select_crng(void)
+{
+ struct crng_state **pool;
+ int nid = numa_node_id();
+
+ /* pairs with cmpxchg_release() in do_numa_crng_init() */
+ pool = READ_ONCE(crng_node_pool);
+ if (pool && pool[nid])
+ return pool[nid];
+
+ return &primary_crng;
+}
#else
static void numa_crng_init(void) {}
+
+static struct crng_state *select_crng(void)
+{
+ return &primary_crng;
+}
#endif
/*
@@ -1005,15 +1023,7 @@ static void _extract_crng(struct crng_state *crng,
static void extract_crng(__u8 out[CHACHA_BLOCK_SIZE])
{
- struct crng_state *crng = NULL;
-
-#ifdef CONFIG_NUMA
- if (crng_node_pool)
- crng = crng_node_pool[numa_node_id()];
- if (crng == NULL)
-#endif
- crng = &primary_crng;
- _extract_crng(crng, out);
+ _extract_crng(select_crng(), out);
}
/*
@@ -1042,15 +1052,7 @@ static void _crng_backtrack_protect(struct crng_state *crng,
static void crng_backtrack_protect(__u8 tmp[CHACHA_BLOCK_SIZE], int used)
{
- struct crng_state *crng = NULL;
-
-#ifdef CONFIG_NUMA
- if (crng_node_pool)
- crng = crng_node_pool[numa_node_id()];
- if (crng == NULL)
-#endif
- crng = &primary_crng;
- _crng_backtrack_protect(crng, tmp, used);
+ _crng_backtrack_protect(select_crng(), tmp, used);
}
static ssize_t extract_crng_user(void __user *buf, size_t nbytes)
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 2/2] random: fix data race on crng init time
2021-12-20 22:41 [PATCH v2 0/2] random: fix some data races Eric Biggers
2021-12-20 22:41 ` [PATCH v2 1/2] random: fix data race on crng_node_pool Eric Biggers
@ 2021-12-20 22:41 ` Eric Biggers
2021-12-20 23:40 ` [PATCH v2 0/2] random: fix some data races Paul E. McKenney
2021-12-21 12:15 ` Jason A. Donenfeld
3 siblings, 0 replies; 5+ messages in thread
From: Eric Biggers @ 2021-12-20 22:41 UTC (permalink / raw)
To: Theodore Ts'o, Jason A . Donenfeld
Cc: linux-kernel, linux-crypto, Paul E . McKenney, stable
From: Eric Biggers <ebiggers@google.com>
_extract_crng() does plain loads of crng->init_time and
crng_global_init_time, which causes undefined behavior if
crng_reseed() and RNDRESEEDCRNG modify these corrently.
Use READ_ONCE() and WRITE_ONCE() to make the behavior defined.
Don't fix the race on crng->init_time by protecting it with crng->lock,
since it's not a problem for duplicate reseedings to occur. I.e., the
lockless access with READ_ONCE() is fine.
Fixes: d848e5f8e1eb ("random: add new ioctl RNDRESEEDCRNG")
Fixes: e192be9d9a30 ("random: replace non-blocking pool with a Chacha20-based CRNG")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
drivers/char/random.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 1294b4527cdd..1a7bb66d6a58 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -980,7 +980,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
crng->state[i+4] ^= buf.key[i] ^ rv;
}
memzero_explicit(&buf, sizeof(buf));
- crng->init_time = jiffies;
+ WRITE_ONCE(crng->init_time, jiffies);
spin_unlock_irqrestore(&crng->lock, flags);
if (crng == &primary_crng && crng_init < 2) {
invalidate_batched_entropy();
@@ -1006,12 +1006,15 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
static void _extract_crng(struct crng_state *crng,
__u8 out[CHACHA_BLOCK_SIZE])
{
- unsigned long v, flags;
+ unsigned long v, flags, init_time;
- if (crng_ready() &&
- (time_after(crng_global_init_time, crng->init_time) ||
- time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL)))
- crng_reseed(crng, crng == &primary_crng ? &input_pool : NULL);
+ if (crng_ready()) {
+ init_time = READ_ONCE(crng->init_time);
+ if (time_after(READ_ONCE(crng_global_init_time), init_time) ||
+ time_after(jiffies, init_time + CRNG_RESEED_INTERVAL))
+ crng_reseed(crng, crng == &primary_crng ?
+ &input_pool : NULL);
+ }
spin_lock_irqsave(&crng->lock, flags);
if (arch_get_random_long(&v))
crng->state[14] ^= v;
@@ -1951,7 +1954,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
if (crng_init < 2)
return -ENODATA;
crng_reseed(&primary_crng, &input_pool);
- crng_global_init_time = jiffies - 1;
+ WRITE_ONCE(crng_global_init_time, jiffies - 1);
return 0;
default:
return -EINVAL;
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 0/2] random: fix some data races
2021-12-20 22:41 [PATCH v2 0/2] random: fix some data races Eric Biggers
2021-12-20 22:41 ` [PATCH v2 1/2] random: fix data race on crng_node_pool Eric Biggers
2021-12-20 22:41 ` [PATCH v2 2/2] random: fix data race on crng init time Eric Biggers
@ 2021-12-20 23:40 ` Paul E. McKenney
2021-12-21 12:15 ` Jason A. Donenfeld
3 siblings, 0 replies; 5+ messages in thread
From: Paul E. McKenney @ 2021-12-20 23:40 UTC (permalink / raw)
To: Eric Biggers
Cc: Theodore Ts'o, Jason A . Donenfeld , linux-kernel, linux-crypto
On Mon, Dec 20, 2021 at 04:41:55PM -0600, Eric Biggers wrote:
> This series fixes some data races in random.c.
>
> Changed v1 => v2:
> - Remove unneeded 'inline' keywords
> - Use READ_ONCE() instead of smp_load_acquire()
> - Updated commit message
> - Added patch to fix data race on crng init time
>
> Eric Biggers (2):
> random: fix data race on crng_node_pool
> random: fix data race on crng init time
From a memory-ordering viewpoint:
Acked-by: Paul E. McKenney <paulmck@kernel.org>
> drivers/char/random.c | 61 +++++++++++++++++++++++--------------------
> 1 file changed, 33 insertions(+), 28 deletions(-)
>
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2 0/2] random: fix some data races
2021-12-20 22:41 [PATCH v2 0/2] random: fix some data races Eric Biggers
` (2 preceding siblings ...)
2021-12-20 23:40 ` [PATCH v2 0/2] random: fix some data races Paul E. McKenney
@ 2021-12-21 12:15 ` Jason A. Donenfeld
3 siblings, 0 replies; 5+ messages in thread
From: Jason A. Donenfeld @ 2021-12-21 12:15 UTC (permalink / raw)
To: Eric Biggers
Cc: Theodore Ts'o, LKML, Linux Crypto Mailing List, Paul E . McKenney
All applied to crng/random.git. Thanks for the series.
Jason
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2021-12-21 12:16 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-20 22:41 [PATCH v2 0/2] random: fix some data races Eric Biggers
2021-12-20 22:41 ` [PATCH v2 1/2] random: fix data race on crng_node_pool Eric Biggers
2021-12-20 22:41 ` [PATCH v2 2/2] random: fix data race on crng init time Eric Biggers
2021-12-20 23:40 ` [PATCH v2 0/2] random: fix some data races Paul E. McKenney
2021-12-21 12:15 ` Jason A. Donenfeld
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).