Skip to content

Commit bc68467

Browse files
committed
crypto: rng - Skip leading zero-length iovec segments
The fast per-CPU DRBG path computes its initial user destination address straight from the iov_iter. For an ITER_IOVEC iter it reads iter_iov_addr() and iter_iov_len() of the current segment, but when the iovec leads with one or more zero-length segments, the current segment is one of those empty entries. iter_iov_addr() then hands back the base of an empty segment, which is whatever userspace put there: its base can be NULL or some other unwritable address, since a zero-length segment is never actually touched. Right after the setup, that address is prefaulted, and on a bogus base it fails. A failed prefault on the very first address is treated as fatal, so the whole read bails out to -EFAULT even though there are perfectly good non-empty segments later in the iovec. This is reachable with something as simple as readv() on /dev/urandom where the first iovec entry is {NULL, 0}. Fix it by advancing the iterator by zero before reading the first address. The iovec advance loop walks past every leading empty segment and stops at the first non-empty one, and there's guaranteed to be such a segment because iov_iter_count() is nonzero at this point. Empty segments that crop up mid-stream are already skipped by the per-copy advance, so this only needs to run once during setup. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Sultan Alsawaf <sultan@ciq.com>
1 parent d56b576 commit bc68467

1 file changed

Lines changed: 10 additions & 0 deletions

File tree

crypto/rng.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,16 @@ static ssize_t crypto_devrandom_read_iter(struct iov_iter *iter, bool reseed)
442442
uaddr = iter->ubuf + iter->iov_offset;
443443
ulen = iov_iter_count(iter);
444444
} else if (iter_is_iovec(iter)) {
445+
/*
446+
* Skip any leading zero-length segments first, since
447+
* uaddr would otherwise point at an empty segment's
448+
* base (which may be NULL or unwritable). Advancing by
449+
* zero walks past every leading empty segment (the
450+
* iovec advance loop stops at the first non-empty one),
451+
* and there's guaranteed to be a non-empty one because
452+
* iov_iter_count() is nonzero above.
453+
*/
454+
iov_iter_advance(iter, 0);
445455
uaddr = iter_iov_addr(iter);
446456
ulen = iter_iov_len(iter);
447457
} else {

0 commit comments

Comments
 (0)