git: afe41f1ab9f6 - main - sys/uio: add updateiov()
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 29 Sep 2026 18:14:28 UTC
The branch main has been updated by brooks:
URL: https://cgit.FreeBSD.org/src/commit/?id=afe41f1ab9f6cbabf43f28446a61ed3fe1cd72a7
commit afe41f1ab9f6cbabf43f28446a61ed3fe1cd72a7
Author: Brooks Davis <brooks@FreeBSD.org>
AuthorDate: 2026-09-29 17:30:14 +0000
Commit: Brooks Davis <brooks@FreeBSD.org>
CommitDate: 2026-09-29 18:14:06 +0000
sys/uio: add updateiov()
This function take a struct uio previously created by copyinuio and and
updates the lengths of the user-space iovec to match those in the uio.
To reduce the risks of pointer leakage and cross-ABI pointer confusion,
lengths are updated individually.
Reviewed by: jamie, jhb
Effort: CHERI upstreaming
Sponsored by: DARPA, AFRL, Innovate UK
Differential Revision: https://reviews.freebsd.org/D60025
---
sys/kern/subr_uio.c | 18 ++++++++++++++++++
sys/sys/syscallsubr.h | 7 +++++++
sys/sys/uio.h | 1 +
3 files changed, 26 insertions(+)
diff --git a/sys/kern/subr_uio.c b/sys/kern/subr_uio.c
index 51001aacf0c9..b7be8c55b512 100644
--- a/sys/kern/subr_uio.c
+++ b/sys/kern/subr_uio.c
@@ -468,6 +468,24 @@ copyinuio(const void *iovp, u_int iovcnt, struct uio **uiop)
return (0);
}
+/*
+ * Update the lengths of a userspace iovec to match those in a struct uio's
+ * iovec (previously created by copyinuio).
+ */
+int
+updateiov(const struct uio *uiop, void *uiovp)
+{
+ int i, error;
+ struct iovec *iovp = uiovp;
+
+ for (i = 0; i < uiop->uio_iovcnt; i++) {
+ error = suword(&iovp[i].iov_len, uiop->uio_iov[i].iov_len);
+ if (error != 0)
+ return (EFAULT);
+ }
+ return (0);
+}
+
struct uio *
allocuio(u_int iovcnt)
{
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index 3a30c9cd984d..d38d10880ec8 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -96,6 +96,13 @@ typedef int (copyin_hdtr_t)(const void *hdtrp, struct sf_hdtr *hdtr);
typedef int (copyinuio_t)(const void *iovp, unsigned int iovcnt,
struct uio **iov);
+/*
+ * A updateiov_t takes a pointer to a struct uio previously created with
+ * copyinuio_t and a pointer to the corresponding iovec in userspace.
+ * It updates all lengths in userspace to match those in the uio.
+ */
+typedef int(updateiov_t)(const struct uio *uiop, void *iovp);
+
uint64_t at2cnpflags(u_int at_flags, u_int mask);
int kern___getcwd(struct thread *td, char *buf, enum uio_seg bufseg,
size_t buflen, size_t path_max);
diff --git a/sys/sys/uio.h b/sys/sys/uio.h
index 0e0d42d04144..6549a23314e3 100644
--- a/sys/sys/uio.h
+++ b/sys/sys/uio.h
@@ -99,6 +99,7 @@ int uiomove_fromphys(struct vm_page *ma[], vm_offset_t offset, int n,
int uiomove_nofault(void *cp, int n, struct uio *uio);
int uiomove_object(struct vm_object *obj, off_t obj_size, struct uio *uio);
int uiomove_step(void *cp, void *base, size_t cnt, struct uio *uio);
+int updateiov(const struct uio *uiop, void *iovp);
#else /* !_KERNEL */