On 29/08/2023 16:10, Luca Vizzarro wrote:
With PCuABI we want to make sure that any userspace capability is correctly validated.
In this commit explicit capability checks are added in first_iovec_segment to ensure that the pointer received by userspace
s/by/from/
Kevin
has the correct bounds and permissions to access such segment.
Signed-off-by: Luca Vizzarro Luca.Vizzarro@arm.com
lib/iov_iter.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 3b082f598162..6d8c41191ed0 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -1536,14 +1536,17 @@ static ssize_t iter_xarray_get_pages(struct iov_iter *i, } /* must be done on non-empty ITER_UBUF or ITER_IOVEC one */ -static unsigned long first_iovec_segment(const struct iov_iter *i, size_t *size) +static void __user *first_iovec_segment(const struct iov_iter *i, size_t *size) {
- bool is_source = iov_iter_rw(i) == ITER_SOURCE;
- void __user *seg; size_t skip; long k;
- if (iter_is_ubuf(i))
/* TODO [PCuABI] - capability checks for uaccess */
return user_ptr_addr(i->ubuf) + i->iov_offset;
- if (iter_is_ubuf(i)) {
seg = i->ubuf + i->iov_offset;
goto ptr_check;
- }
for (k = 0, skip = i->iov_offset; k < i->nr_segs; k++, skip = 0) { const struct iovec *iov = iter_iov(i) + k; @@ -1553,9 +1556,18 @@ static unsigned long first_iovec_segment(const struct iov_iter *i, size_t *size) continue; if (*size > len) *size = len;
return user_ptr_addr(iov->iov_base) + skip;
seg = iov->iov_base + skip;
} BUG(); // if it had been empty, we wouldn't get calledgoto ptr_check;
+ptr_check:
- if ((is_source && !check_user_ptr_read(seg, *size)) ||
(!is_source && !check_user_ptr_write(seg, *size)))
return ERR_USER_PTR(-EFAULT);
- return seg;
} /* must be done on non-empty ITER_BVEC one */ @@ -1599,7 +1611,10 @@ static ssize_t __iov_iter_get_pages_alloc(struct iov_iter *i, if (i->nofault) gup_flags |= FOLL_NOFAULT;
addr = first_iovec_segment(i, &maxsize);
addr = user_ptr_addr(first_iovec_segment(i, &maxsize));
if (IS_ERR_VALUE(addr))
return addr;
- *start = addr % PAGE_SIZE; addr &= PAGE_MASK; n = want_pages_array(pages, maxsize, *start, maxpages);
@@ -2316,7 +2331,9 @@ static ssize_t iov_iter_extract_user_pages(struct iov_iter *i, if (i->nofault) gup_flags |= FOLL_NOFAULT;
- addr = first_iovec_segment(i, &maxsize);
- addr = user_ptr_addr(first_iovec_segment(i, &maxsize));
- if (IS_ERR_VALUE(addr))
*offset0 = offset = addr % PAGE_SIZE; addr &= PAGE_MASK; maxpages = want_pages_array(pages, maxsize, offset, maxpages);return addr;