summaryrefslogtreecommitdiffstats
path: root/lib/iov_iter.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2021-05-02 17:57:37 +0200
committerAl Viro <viro@zeniv.linux.org.uk>2021-06-10 17:45:10 +0200
commit8409a0d261e20180361e7afe6d89847d1bad4ce8 (patch)
tree1c489a52514e16da863c535465c2b4206189a4b7 /lib/iov_iter.c
parentiov_iter: optimize iov_iter_advance() for iovec and kvec (diff)
downloadlinux-8409a0d261e20180361e7afe6d89847d1bad4ce8.tar.xz
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/iov_iter.c')
-rw-r--r--lib/iov_iter.c26
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;
}