git: afe41f1ab9f6 - main - sys/uio: add updateiov()

From: Brooks Davis <brooks_at_FreeBSD.org>
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 */