Skip to content

Commit 92edbe3

Browse files
committed
Merge tag 'random-5.18-rc3-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/crng/random
Pull random number generator fixes from Jason Donenfeld: - Per your suggestion, random reads now won't fail if there's a page fault after some non-zero amount of data has been read, which makes the behavior consistent with all other reads in the kernel. - Rather than an inconsistent mix of random_get_entropy() returning an unsigned long or a cycles_t, now it just returns an unsigned long. - A memcpy() was replaced with an memmove(), because the addresses are sometimes overlapping. In practice the destination is always before the source, so not really an issue, but better to be correct than not. * tag 'random-5.18-rc3-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/crng/random: random: use memmove instead of memcpy for remaining 32 bytes random: make random_get_entropy() return an unsigned long random: allow partial reads if later user copies fail
2 parents 90ea17a + 35a33ff commit 92edbe3

2 files changed

Lines changed: 21 additions & 25 deletions

File tree

drivers/char/random.c

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ static void crng_fast_key_erasure(u8 key[CHACHA_KEY_SIZE],
333333
chacha20_block(chacha_state, first_block);
334334

335335
memcpy(key, first_block, CHACHA_KEY_SIZE);
336-
memcpy(random_data, first_block + CHACHA_KEY_SIZE, random_data_len);
336+
memmove(random_data, first_block + CHACHA_KEY_SIZE, random_data_len);
337337
memzero_explicit(first_block, sizeof(first_block));
338338
}
339339

@@ -523,8 +523,7 @@ EXPORT_SYMBOL(get_random_bytes);
523523

524524
static ssize_t get_random_bytes_user(void __user *buf, size_t nbytes)
525525
{
526-
ssize_t ret = 0;
527-
size_t len;
526+
size_t len, left, ret = 0;
528527
u32 chacha_state[CHACHA_STATE_WORDS];
529528
u8 output[CHACHA_BLOCK_SIZE];
530529

@@ -543,37 +542,40 @@ static ssize_t get_random_bytes_user(void __user *buf, size_t nbytes)
543542
* the user directly.
544543
*/
545544
if (nbytes <= CHACHA_KEY_SIZE) {
546-
ret = copy_to_user(buf, &chacha_state[4], nbytes) ? -EFAULT : nbytes;
545+
ret = nbytes - copy_to_user(buf, &chacha_state[4], nbytes);
547546
goto out_zero_chacha;
548547
}
549548

550-
do {
549+
for (;;) {
551550
chacha20_block(chacha_state, output);
552551
if (unlikely(chacha_state[12] == 0))
553552
++chacha_state[13];
554553

555554
len = min_t(size_t, nbytes, CHACHA_BLOCK_SIZE);
556-
if (copy_to_user(buf, output, len)) {
557-
ret = -EFAULT;
555+
left = copy_to_user(buf, output, len);
556+
if (left) {
557+
ret += len - left;
558558
break;
559559
}
560560

561-
nbytes -= len;
562561
buf += len;
563562
ret += len;
563+
nbytes -= len;
564+
if (!nbytes)
565+
break;
564566

565567
BUILD_BUG_ON(PAGE_SIZE % CHACHA_BLOCK_SIZE != 0);
566-
if (!(ret % PAGE_SIZE) && nbytes) {
568+
if (ret % PAGE_SIZE == 0) {
567569
if (signal_pending(current))
568570
break;
569571
cond_resched();
570572
}
571-
} while (nbytes);
573+
}
572574

573575
memzero_explicit(output, sizeof(output));
574576
out_zero_chacha:
575577
memzero_explicit(chacha_state, sizeof(chacha_state));
576-
return ret;
578+
return ret ? ret : -EFAULT;
577579
}
578580

579581
/*
@@ -1016,7 +1018,7 @@ int __init rand_initialize(void)
10161018
*/
10171019
void add_device_randomness(const void *buf, size_t size)
10181020
{
1019-
cycles_t cycles = random_get_entropy();
1021+
unsigned long cycles = random_get_entropy();
10201022
unsigned long flags, now = jiffies;
10211023

10221024
if (crng_init == 0 && size)
@@ -1047,8 +1049,7 @@ struct timer_rand_state {
10471049
*/
10481050
static void add_timer_randomness(struct timer_rand_state *state, unsigned int num)
10491051
{
1050-
cycles_t cycles = random_get_entropy();
1051-
unsigned long flags, now = jiffies;
1052+
unsigned long cycles = random_get_entropy(), now = jiffies, flags;
10521053
long delta, delta2, delta3;
10531054

10541055
spin_lock_irqsave(&input_pool.lock, flags);
@@ -1337,8 +1338,7 @@ static void mix_interrupt_randomness(struct work_struct *work)
13371338
void add_interrupt_randomness(int irq)
13381339
{
13391340
enum { MIX_INFLIGHT = 1U << 31 };
1340-
cycles_t cycles = random_get_entropy();
1341-
unsigned long now = jiffies;
1341+
unsigned long cycles = random_get_entropy(), now = jiffies;
13421342
struct fast_pool *fast_pool = this_cpu_ptr(&irq_randomness);
13431343
struct pt_regs *regs = get_irq_regs();
13441344
unsigned int new_count;
@@ -1351,16 +1351,12 @@ void add_interrupt_randomness(int irq)
13511351
if (cycles == 0)
13521352
cycles = get_reg(fast_pool, regs);
13531353

1354-
if (sizeof(cycles) == 8)
1354+
if (sizeof(unsigned long) == 8) {
13551355
irq_data.u64[0] = cycles ^ rol64(now, 32) ^ irq;
1356-
else {
1356+
irq_data.u64[1] = regs ? instruction_pointer(regs) : _RET_IP_;
1357+
} else {
13571358
irq_data.u32[0] = cycles ^ irq;
13581359
irq_data.u32[1] = now;
1359-
}
1360-
1361-
if (sizeof(unsigned long) == 8)
1362-
irq_data.u64[1] = regs ? instruction_pointer(regs) : _RET_IP_;
1363-
else {
13641360
irq_data.u32[2] = regs ? instruction_pointer(regs) : _RET_IP_;
13651361
irq_data.u32[3] = get_reg(fast_pool, regs);
13661362
}
@@ -1407,7 +1403,7 @@ static void entropy_timer(struct timer_list *t)
14071403
static void try_to_generate_entropy(void)
14081404
{
14091405
struct {
1410-
cycles_t cycles;
1406+
unsigned long cycles;
14111407
struct timer_list timer;
14121408
} stack;
14131409

include/linux/timex.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
* By default we use get_cycles() for this purpose, but individual
7676
* architectures may override this in their asm/timex.h header file.
7777
*/
78-
#define random_get_entropy() get_cycles()
78+
#define random_get_entropy() ((unsigned long)get_cycles())
7979
#endif
8080

8181
/*

0 commit comments

Comments
 (0)