@@ -532,19 +532,20 @@ static ssize_t get_random_bytes_user(void __user *buf, size_t nbytes)
if (!nbytes)
return 0;
- len = min_t(size_t, 32, nbytes);
- crng_make_state(chacha_state, output, len);
-
- if (copy_to_user(buf, output, len))
- return -EFAULT;
- nbytes -= len;
- buf += len;
- ret += len;
+ /*
+ * Immediately overwrite the ChaCha key at index 4, in case userspace
+ * causes copy_to_user() below to sleep forever, so that we still
+ * retain forward secrecy in that case.
+ */
+ crng_make_state(chacha_state, (u8 *)&chacha_state[4], CHACHA_KEY_SIZE);
- while (nbytes) {
+ do {
if (large_request && need_resched()) {
- if (signal_pending(current))
+ if (signal_pending(current)) {
+ if (!ret)
+ ret = -ERESTARTSYS;
break;
+ }
schedule();
}
@@ -561,7 +562,7 @@ static ssize_t get_random_bytes_user(void __user *buf, size_t nbytes)
nbytes -= len;
buf += len;
ret += len;
- }
+ } while (nbytes);
memzero_explicit(chacha_state, sizeof(chacha_state));
memzero_explicit(output, sizeof(output));