Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'random-5.18-rc2-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/crng/random

Pull random number generator fixes from Jason Donenfeld:

- Another fixup to the fast_init/crng_init split, this time in how much
entropy is being credited, from Jan Varho.

- As discussed, we now opportunistically call try_to_generate_entropy()
in /dev/urandom reads, as a replacement for the reverted commit. I
opted to not do the more invasive wait_for_random_bytes() change at
least for now, preferring to do something smaller and more obvious
for the time being, but maybe that can be revisited as things evolve
later.

- Userspace can use FUSE or userfaultfd or simply move a process to
idle priority in order to make a read from the random device never
complete, which breaks forward secrecy, fixed by overwriting
sensitive bytes early on in the function.

- Jann Horn noticed that /dev/urandom reads were only checking for
pending signals if need_resched() was true, a bug going back to the
genesis commit, now fixed by always checking for signal_pending() and
calling cond_resched(). This explains various noticeable signal
delivery delays I've seen in programs over the years that do long
reads from /dev/urandom.

- In order to be more like other devices (e.g. /dev/zero) and to
mitigate the impact of fixing the above bug, which has been around
forever (users have never really needed to check the return value of
read() for medium-sized reads and so perhaps many didn't), we now
move signal checking to the bottom part of the loop, and do so every
PAGE_SIZE-bytes.

* tag 'random-5.18-rc2-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/crng/random:
random: check for signals every PAGE_SIZE chunk of /dev/[u]random
random: check for signal_pending() outside of need_resched() check
random: do not allow user to keep crng key around on stack
random: opportunistically initialize on /dev/urandom reads
random: do not split fast init input in add_hwgenerator_randomness()

+39 -35
+39 -35
drivers/char/random.c
··· 437 437 * This shouldn't be set by functions like add_device_randomness(), 438 438 * where we can't trust the buffer passed to it is guaranteed to be 439 439 * unpredictable (so it might not have any entropy at all). 440 - * 441 - * Returns the number of bytes processed from input, which is bounded 442 - * by CRNG_INIT_CNT_THRESH if account is true. 443 440 */ 444 - static size_t crng_pre_init_inject(const void *input, size_t len, bool account) 441 + static void crng_pre_init_inject(const void *input, size_t len, bool account) 445 442 { 446 443 static int crng_init_cnt = 0; 447 444 struct blake2s_state hash; ··· 449 452 spin_lock_irqsave(&base_crng.lock, flags); 450 453 if (crng_init != 0) { 451 454 spin_unlock_irqrestore(&base_crng.lock, flags); 452 - return 0; 455 + return; 453 456 } 454 - 455 - if (account) 456 - len = min_t(size_t, len, CRNG_INIT_CNT_THRESH - crng_init_cnt); 457 457 458 458 blake2s_update(&hash, base_crng.key, sizeof(base_crng.key)); 459 459 blake2s_update(&hash, input, len); 460 460 blake2s_final(&hash, base_crng.key); 461 461 462 462 if (account) { 463 - crng_init_cnt += len; 463 + crng_init_cnt += min_t(size_t, len, CRNG_INIT_CNT_THRESH - crng_init_cnt); 464 464 if (crng_init_cnt >= CRNG_INIT_CNT_THRESH) { 465 465 ++base_crng.generation; 466 466 crng_init = 1; ··· 468 474 469 475 if (crng_init == 1) 470 476 pr_notice("fast init done\n"); 471 - 472 - return len; 473 477 } 474 478 475 479 static void _get_random_bytes(void *buf, size_t nbytes) ··· 523 531 524 532 static ssize_t get_random_bytes_user(void __user *buf, size_t nbytes) 525 533 { 526 - bool large_request = nbytes > 256; 527 534 ssize_t ret = 0; 528 535 size_t len; 529 536 u32 chacha_state[CHACHA_STATE_WORDS]; ··· 531 540 if (!nbytes) 532 541 return 0; 533 542 534 - len = min_t(size_t, 32, nbytes); 535 - crng_make_state(chacha_state, output, len); 543 + /* 544 + * Immediately overwrite the ChaCha key at index 4 with random 545 + * bytes, in case userspace causes copy_to_user() below to sleep 546 + * forever, so that we still retain forward secrecy in that case. 547 + */ 548 + crng_make_state(chacha_state, (u8 *)&chacha_state[4], CHACHA_KEY_SIZE); 549 + /* 550 + * However, if we're doing a read of len <= 32, we don't need to 551 + * use chacha_state after, so we can simply return those bytes to 552 + * the user directly. 553 + */ 554 + if (nbytes <= CHACHA_KEY_SIZE) { 555 + ret = copy_to_user(buf, &chacha_state[4], nbytes) ? -EFAULT : nbytes; 556 + goto out_zero_chacha; 557 + } 536 558 537 - if (copy_to_user(buf, output, len)) 538 - return -EFAULT; 539 - nbytes -= len; 540 - buf += len; 541 - ret += len; 542 - 543 - while (nbytes) { 544 - if (large_request && need_resched()) { 545 - if (signal_pending(current)) 546 - break; 547 - schedule(); 548 - } 549 - 559 + do { 550 560 chacha20_block(chacha_state, output); 551 561 if (unlikely(chacha_state[12] == 0)) 552 562 ++chacha_state[13]; ··· 561 569 nbytes -= len; 562 570 buf += len; 563 571 ret += len; 564 - } 565 572 566 - memzero_explicit(chacha_state, sizeof(chacha_state)); 573 + BUILD_BUG_ON(PAGE_SIZE % CHACHA_BLOCK_SIZE != 0); 574 + if (!(ret % PAGE_SIZE) && nbytes) { 575 + if (signal_pending(current)) 576 + break; 577 + cond_resched(); 578 + } 579 + } while (nbytes); 580 + 567 581 memzero_explicit(output, sizeof(output)); 582 + out_zero_chacha: 583 + memzero_explicit(chacha_state, sizeof(chacha_state)); 568 584 return ret; 569 585 } 570 586 ··· 1141 1141 size_t entropy) 1142 1142 { 1143 1143 if (unlikely(crng_init == 0 && entropy < POOL_MIN_BITS)) { 1144 - size_t ret = crng_pre_init_inject(buffer, count, true); 1145 - mix_pool_bytes(buffer, ret); 1146 - count -= ret; 1147 - buffer += ret; 1148 - if (!count || crng_init == 0) 1149 - return; 1144 + crng_pre_init_inject(buffer, count, true); 1145 + mix_pool_bytes(buffer, count); 1146 + return; 1150 1147 } 1151 1148 1152 1149 /* ··· 1541 1544 loff_t *ppos) 1542 1545 { 1543 1546 static int maxwarn = 10; 1547 + 1548 + /* 1549 + * Opportunistically attempt to initialize the RNG on platforms that 1550 + * have fast cycle counters, but don't (for now) require it to succeed. 1551 + */ 1552 + if (!crng_ready()) 1553 + try_to_generate_entropy(); 1544 1554 1545 1555 if (!crng_ready() && maxwarn > 0) { 1546 1556 maxwarn--;