random(4): Poll for signals during large reads
Occasionally poll for signals during large reads of the /dev/u?random devices. This allows cancellation via SIGINT of accidental invocations of very large reads. (A 2GB /dev/random read, which takes about 10 seconds on my 2017 AMD Zen processor, can be aborted.) I believe this behavior was intended since 2014 (r273997), just not fully implemented. This is motivated by a potential getrandom(2) interface that may not explicitly forbid extremely large reads on 64-bit platforms -- even larger than the 2GB limit imposed on devfs I/O by default. Such reads, if they are to be allowed, should be cancellable by the user or administrator. Reviewed by: delphij Approved by: secteam (delphij) Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D14684
This commit is contained in:
parent
64b1deb8c7
commit
d9759abd65
@ -130,6 +130,12 @@ READ_RANDOM_UIO(struct uio *uio, bool nonblock)
|
||||
uint8_t *random_buf;
|
||||
int error, spamcount;
|
||||
ssize_t read_len, total_read, c;
|
||||
/* 16 MiB takes about 0.08 s CPU time on my 2017 AMD Zen CPU */
|
||||
#define SIGCHK_PERIOD (16 * 1024 * 1024)
|
||||
const size_t sigchk_period = SIGCHK_PERIOD;
|
||||
|
||||
CTASSERT(SIGCHK_PERIOD % PAGE_SIZE == 0);
|
||||
#undef SIGCHK_PERIOD
|
||||
|
||||
random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
|
||||
p_random_alg_context->ra_pre_read();
|
||||
@ -167,11 +173,22 @@ READ_RANDOM_UIO(struct uio *uio, bool nonblock)
|
||||
read_len = MIN(read_len, PAGE_SIZE);
|
||||
p_random_alg_context->ra_read(random_buf, read_len);
|
||||
c = MIN(uio->uio_resid, read_len);
|
||||
/*
|
||||
* uiomove() may yield the CPU before each 'c' bytes
|
||||
* (up to PAGE_SIZE) are copied out.
|
||||
*/
|
||||
error = uiomove(random_buf, c, uio);
|
||||
total_read += c;
|
||||
/*
|
||||
* Poll for signals every few MBs to avoid very long
|
||||
* uninterruptible syscalls.
|
||||
*/
|
||||
if (error == 0 && uio->uio_resid != 0 &&
|
||||
total_read % sigchk_period == 0)
|
||||
error = tsleep_sbt(&random_alg_context, PCATCH,
|
||||
"randrd", SBT_1NS, 0, C_HARDCLOCK);
|
||||
}
|
||||
if (total_read != uio->uio_resid && (error == ERESTART || error == EINTR))
|
||||
/* Return partial read, not error. */
|
||||
if (error == ERESTART || error == EINTR)
|
||||
error = 0;
|
||||
}
|
||||
free(random_buf, M_ENTROPY);
|
||||
|
Loading…
Reference in New Issue
Block a user