diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2021-05-02 11:57:37 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2021-06-10 11:45:10 -0400 |
commit | 8409a0d261e20180361e7afe6d89847d1bad4ce8 (patch) | |
tree | 1c489a52514e16da863c535465c2b4206189a4b7 /lib | |
parent | 185ac4d43669314f31c9c27d1ffc5ebcad791351 (diff) | |
download | linux-8409a0d261e20180361e7afe6d89847d1bad4ce8.tar.gz linux-8409a0d261e20180361e7afe6d89847d1bad4ce8.tar.bz2 linux-8409a0d261e20180361e7afe6d89847d1bad4ce8.zip |
sanitize iov_iter_fault_in_readable()
1) constify iov_iter argument; we are not advancing it in this primitive.
2) cap the amount requested by the amount of data in iov_iter. All
existing callers should've been safe, but the check is really cheap and
doing it here makes for easier analysis, as well as more consistent
semantics among the primitives.
3) don't bother with iterate_iovec(). Explicit loop is not any harder
to follow, and we get rid of standalone iterate_iovec() users - it's
only used by iterate_and_advance() and (soon to be gone) iterate_all_kinds().
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/iov_iter.c | 26 |
1 files changed, 16 insertions, 10 deletions
diff --git a/lib/iov_iter.c b/lib/iov_iter.c index cd23c79acb94..2b543bea1e0d 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -466,19 +466,25 @@ out: * Return 0 on success, or non-zero if the memory could not be accessed (i.e. * because it is an invalid address). */ -int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes) +int iov_iter_fault_in_readable(const struct iov_iter *i, size_t bytes) { - size_t skip = i->iov_offset; - const struct iovec *iov; - int err; - struct iovec v; - if (iter_is_iovec(i)) { - iterate_iovec(i, bytes, v, iov, skip, ({ - err = fault_in_pages_readable(v.iov_base, v.iov_len); + const struct iovec *p; + size_t skip; + + if (bytes > i->count) + bytes = i->count; + for (p = i->iov, skip = i->iov_offset; bytes; p++, skip = 0) { + size_t len = min(bytes, p->iov_len - skip); + int err; + + if (unlikely(!len)) + continue; + err = fault_in_pages_readable(p->iov_base + skip, len); if (unlikely(err)) - return err; - 0;})) + return err; + bytes -= len; + } } return 0; } |