From 61cc4830a7b16400efade3d884a59fda6d80d651 Mon Sep 17 00:00:00 2001 From: Alfredo Mazzinghi Date: Thu, 18 Jan 2024 13:04:41 +0000 Subject: [PATCH] Abstract UIO allocation and deallocation. Introduce the allocuio() and freeuio() functions to allocate and deallocate struct uio. This hides the actual allocator interface, so it is easier to modify the sub-allocation layout of struct uio and the corresponding iovec array. Obtained from: CheriBSD Reviewed by: kib, markj MFC after: 2 weeks Sponsored by: CHaOS, EPSRC grant EP/V000292/1 Differential Revision: https://reviews.freebsd.org/D43711 --- sys/amd64/linux32/linux32_machdep.c | 2 +- .../compat/opensolaris/kern/opensolaris_uio.c | 2 +- sys/compat/freebsd32/freebsd32_misc.c | 29 ++++++-------- sys/compat/linux/linux_file.c | 6 +-- sys/kern/kern_jail.c | 6 +-- sys/kern/kern_ktrace.c | 4 +- sys/kern/kern_sendfile.c | 4 +- sys/kern/subr_prf.c | 2 +- sys/kern/subr_uio.c | 40 ++++++++++++++----- sys/kern/sys_generic.c | 8 ++-- sys/kern/vfs_aio.c | 4 +- sys/kern/vfs_mount.c | 2 +- sys/kern/vfs_vnops.c | 2 +- sys/sys/uio.h | 2 + 14 files changed, 67 insertions(+), 46 deletions(-) diff --git a/sys/amd64/linux32/linux32_machdep.c b/sys/amd64/linux32/linux32_machdep.c index ba4dcc61af7..7f1c85cee20 100644 --- a/sys/amd64/linux32/linux32_machdep.c +++ b/sys/amd64/linux32/linux32_machdep.c @@ -106,7 +106,7 @@ linux_readv(struct thread *td, struct linux_readv_args *uap) if (error) return (error); error = kern_readv(td, uap->fd, auio); - free(auio, M_IOV); + freeuio(auio); return (error); } diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_uio.c b/sys/cddl/compat/opensolaris/kern/opensolaris_uio.c index e1cc8f80276..b2a08a55bba 100644 --- a/sys/cddl/compat/opensolaris/kern/opensolaris_uio.c +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_uio.c @@ -68,7 +68,7 @@ uiocopy(void *p, size_t n, enum uio_rw rw, struct uio *uio, size_t *cbytes) error = vn_io_fault_uiomove(p, n, uio_clone); *cbytes = uio->uio_resid - uio_clone->uio_resid; if (uio_clone != &small_uio_clone) - free(uio_clone, M_IOV); + freeuio(uio_clone); return (error); } diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index f2d66cf74b2..facbf00a4c5 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -1196,32 +1196,29 @@ freebsd32_copyinuio(struct iovec32 *iovp, u_int iovcnt, struct uio **uiop) struct iovec32 iov32; struct iovec *iov; struct uio *uio; - u_int iovlen; int error, i; *uiop = NULL; if (iovcnt > UIO_MAXIOV) return (EINVAL); - iovlen = iovcnt * sizeof(struct iovec); - uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK); - iov = (struct iovec *)(uio + 1); + uio = allocuio(iovcnt); + iov = uio->uio_iov; for (i = 0; i < iovcnt; i++) { error = copyin(&iovp[i], &iov32, sizeof(struct iovec32)); if (error) { - free(uio, M_IOV); + freeuio(uio); return (error); } iov[i].iov_base = PTRIN(iov32.iov_base); iov[i].iov_len = iov32.iov_len; } - uio->uio_iov = iov; uio->uio_iovcnt = iovcnt; uio->uio_segflg = UIO_USERSPACE; uio->uio_offset = -1; uio->uio_resid = 0; for (i = 0; i < iovcnt; i++) { if (iov->iov_len > INT_MAX - uio->uio_resid) { - free(uio, M_IOV); + freeuio(uio); return (EINVAL); } uio->uio_resid += iov->iov_len; @@ -1241,7 +1238,7 @@ freebsd32_readv(struct thread *td, struct freebsd32_readv_args *uap) if (error) return (error); error = kern_readv(td, uap->fd, auio); - free(auio, M_IOV); + freeuio(auio); return (error); } @@ -1255,7 +1252,7 @@ freebsd32_writev(struct thread *td, struct freebsd32_writev_args *uap) if (error) return (error); error = kern_writev(td, uap->fd, auio); - free(auio, M_IOV); + freeuio(auio); return (error); } @@ -1269,7 +1266,7 @@ freebsd32_preadv(struct thread *td, struct freebsd32_preadv_args *uap) if (error) return (error); error = kern_preadv(td, uap->fd, auio, PAIR32TO64(off_t,uap->offset)); - free(auio, M_IOV); + freeuio(auio); return (error); } @@ -1283,7 +1280,7 @@ freebsd32_pwritev(struct thread *td, struct freebsd32_pwritev_args *uap) if (error) return (error); error = kern_pwritev(td, uap->fd, auio, PAIR32TO64(off_t,uap->offset)); - free(auio, M_IOV); + freeuio(auio); return (error); } @@ -2199,9 +2196,9 @@ freebsd32_do_sendfile(struct thread *td, out: if (hdr_uio) - free(hdr_uio, M_IOV); + freeuio(hdr_uio); if (trl_uio) - free(trl_uio, M_IOV); + freeuio(trl_uio); return (error); } @@ -2780,7 +2777,7 @@ freebsd32_jail_set(struct thread *td, struct freebsd32_jail_set_args *uap) if (error) return (error); error = kern_jail_set(td, auio, uap->flags); - free(auio, M_IOV); + freeuio(auio); return (error); } @@ -2807,7 +2804,7 @@ freebsd32_jail_get(struct thread *td, struct freebsd32_jail_get_args *uap) if (error != 0) break; } - free(auio, M_IOV); + freeuio(auio); return (error); } @@ -3540,7 +3537,7 @@ freebsd32_nmount(struct thread *td, return (error); error = vfs_donmount(td, flags, auio); - free(auio, M_IOV); + freeuio(auio); return error; } diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c index 6eab8980a5c..1279490ae8b 100644 --- a/sys/compat/linux/linux_file.c +++ b/sys/compat/linux/linux_file.c @@ -1038,7 +1038,7 @@ linux_preadv(struct thread *td, struct linux_preadv_args *uap) if (error != 0) return (error); error = kern_preadv(td, uap->fd, auio, offset); - free(auio, M_IOV); + freeuio(auio); return (error); } @@ -1065,7 +1065,7 @@ linux_pwritev(struct thread *td, struct linux_pwritev_args *uap) if (error != 0) return (error); error = kern_pwritev(td, uap->fd, auio, offset); - free(auio, M_IOV); + freeuio(auio); return (linux_enobufs2eagain(td, uap->fd, error)); } @@ -1872,6 +1872,6 @@ linux_writev(struct thread *td, struct linux_writev_args *args) if (error != 0) return (error); error = kern_writev(td, args->fd, auio); - free(auio, M_IOV); + freeuio(auio); return (linux_enobufs2eagain(td, args->fd, error)); } diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index fb674b991a7..90a04339479 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -537,7 +537,7 @@ sys_jail_set(struct thread *td, struct jail_set_args *uap) if (error) return (error); error = kern_jail_set(td, auio, uap->flags); - free(auio, M_IOV); + freeuio(auio); return (error); } @@ -2296,8 +2296,8 @@ sys_jail_get(struct thread *td, struct jail_get_args *uap) error = kern_jail_get(td, auio, uap->flags); if (error == 0) error = copyout(auio->uio_iov, uap->iovp, - uap->iovcnt * sizeof (struct iovec)); - free(auio, M_IOV); + uap->iovcnt * sizeof(struct iovec)); + freeuio(auio); return (error); } diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c index eb14d60433d..877a25ffa4c 100644 --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -768,7 +768,7 @@ ktrgenio(int fd, enum uio_rw rw, struct uio *uio, int error) char *buf; if (error) { - free(uio, M_IOV); + freeuio(uio); return; } uio->uio_offset = 0; @@ -776,7 +776,7 @@ ktrgenio(int fd, enum uio_rw rw, struct uio *uio, int error) datalen = MIN(uio->uio_resid, ktr_geniosize); buf = malloc(datalen, M_KTRACE, M_WAITOK); error = uiomove(buf, datalen, uio); - free(uio, M_IOV); + freeuio(uio); if (error) { free(buf, M_KTRACE); return; diff --git a/sys/kern/kern_sendfile.c b/sys/kern/kern_sendfile.c index f6f6b57adfc..323e7fcde07 100644 --- a/sys/kern/kern_sendfile.c +++ b/sys/kern/kern_sendfile.c @@ -1331,8 +1331,8 @@ sendfile(struct thread *td, struct sendfile_args *uap, int compat) (void)copyout(&sbytes, uap->sbytes, sizeof(off_t)); out: - free(hdr_uio, M_IOV); - free(trl_uio, M_IOV); + freeuio(hdr_uio); + freeuio(trl_uio); return (error); } diff --git a/sys/kern/subr_prf.c b/sys/kern/subr_prf.c index 57ca158c631..e291a1fa00a 100644 --- a/sys/kern/subr_prf.c +++ b/sys/kern/subr_prf.c @@ -386,7 +386,7 @@ log_console(struct uio *uio) msglogstr(consbuffer, pri, /*filter_cr*/ 1); } msgbuftrigger = 1; - free(uio, M_IOV); + freeuio(uio); free(consbuffer, M_TEMP); } diff --git a/sys/kern/subr_uio.c b/sys/kern/subr_uio.c index e7c7de406d4..cbc4b0c0ed8 100644 --- a/sys/kern/subr_uio.c +++ b/sys/kern/subr_uio.c @@ -373,21 +373,20 @@ copyinuio(const struct iovec *iovp, u_int iovcnt, struct uio **uiop) if (iovcnt > UIO_MAXIOV) return (EINVAL); iovlen = iovcnt * sizeof(struct iovec); - uio = malloc(iovlen + sizeof(*uio), M_IOV, M_WAITOK); - iov = (struct iovec *)(uio + 1); + uio = allocuio(iovcnt); + iov = uio->uio_iov; error = copyin(iovp, iov, iovlen); - if (error) { - free(uio, M_IOV); + if (error != 0) { + freeuio(uio); return (error); } - uio->uio_iov = iov; uio->uio_iovcnt = iovcnt; uio->uio_segflg = UIO_USERSPACE; uio->uio_offset = -1; uio->uio_resid = 0; for (i = 0; i < iovcnt; i++) { if (iov->iov_len > IOSIZE_MAX - uio->uio_resid) { - free(uio, M_IOV); + freeuio(uio); return (EINVAL); } uio->uio_resid += iov->iov_len; @@ -398,15 +397,38 @@ copyinuio(const struct iovec *iovp, u_int iovcnt, struct uio **uiop) } struct uio * -cloneuio(struct uio *uiop) +allocuio(u_int iovcnt) { struct uio *uio; int iovlen; - iovlen = uiop->uio_iovcnt * sizeof(struct iovec); + KASSERT(iovcnt <= UIO_MAXIOV, + ("Requested %u iovecs exceed UIO_MAXIOV", iovcnt)); + iovlen = iovcnt * sizeof(struct iovec); uio = malloc(iovlen + sizeof(*uio), M_IOV, M_WAITOK); - *uio = *uiop; uio->uio_iov = (struct iovec *)(uio + 1); + + return (uio); +} + +void +freeuio(struct uio *uio) +{ + free(uio, M_IOV); +} + +struct uio * +cloneuio(struct uio *uiop) +{ + struct iovec *iov; + struct uio *uio; + int iovlen; + + iovlen = uiop->uio_iovcnt * sizeof(struct iovec); + uio = allocuio(uiop->uio_iovcnt); + iov = uio->uio_iov; + *uio = *uiop; + uio->uio_iov = iov; bcopy(uiop->uio_iov, uio->uio_iov, iovlen); return (uio); } diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index e185900b93b..9c0cb4e739e 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -271,7 +271,7 @@ sys_readv(struct thread *td, struct readv_args *uap) if (error) return (error); error = kern_readv(td, uap->fd, auio); - free(auio, M_IOV); + freeuio(auio); return (error); } @@ -310,7 +310,7 @@ sys_preadv(struct thread *td, struct preadv_args *uap) if (error) return (error); error = kern_preadv(td, uap->fd, auio, uap->offset); - free(auio, M_IOV); + freeuio(auio); return (error); } @@ -473,7 +473,7 @@ sys_writev(struct thread *td, struct writev_args *uap) if (error) return (error); error = kern_writev(td, uap->fd, auio); - free(auio, M_IOV); + freeuio(auio); return (error); } @@ -512,7 +512,7 @@ sys_pwritev(struct thread *td, struct pwritev_args *uap) if (error) return (error); error = kern_pwritev(td, uap->fd, auio, uap->offset); - free(auio, M_IOV); + freeuio(auio); return (error); } diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c index 13f99a71ef0..1195d92d54a 100644 --- a/sys/kern/vfs_aio.c +++ b/sys/kern/vfs_aio.c @@ -555,7 +555,7 @@ aio_free_entry(struct kaiocb *job) fdrop(job->fd_file, curthread); crfree(job->cred); if (job->uiop != &job->uio) - free(job->uiop, M_IOV); + freeuio(job->uiop); uma_zfree(aiocb_zone, job); AIO_LOCK(ki); @@ -1728,7 +1728,7 @@ aio_aqueue(struct thread *td, struct aiocb *ujob, struct aioliojob *lj, knlist_delete(&job->klist, curthread, 0); err2: if (job->uiop != &job->uio) - free(job->uiop, M_IOV); + freeuio(job->uiop); uma_zfree(aiocb_zone, job); err1: ops->store_error(ujob, error); diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 347ec7f70aa..2b235d39833 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -473,7 +473,7 @@ sys_nmount(struct thread *td, struct nmount_args *uap) } error = vfs_donmount(td, flags, auio); - free(auio, M_IOV); + freeuio(auio); return (error); } diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index dc2efee038b..77e4dd21f27 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -1442,7 +1442,7 @@ vn_io_fault1(struct vnode *vp, struct uio *uio, struct vn_io_fault_args *args, td->td_ma_cnt = prev_td_ma_cnt; curthread_pflags_restore(saveheld); out: - free(uio_clone, M_IOV); + freeuio(uio_clone); return (error); } diff --git a/sys/sys/uio.h b/sys/sys/uio.h index e7bb74c908d..42ab0cda8e3 100644 --- a/sys/sys/uio.h +++ b/sys/sys/uio.h @@ -76,6 +76,8 @@ struct vm_object; struct vm_page; struct bus_dma_segment; +struct uio *allocuio(u_int iovcnt); +void freeuio(struct uio *uio); struct uio *cloneuio(struct uio *uiop); int copyiniov(const struct iovec *iovp, u_int iovcnt, struct iovec **iov, int error);