From 98682fe6266037bf3a86164a8f56a4975fa96112 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Fri, 21 Oct 2022 10:31:54 -0700 Subject: [PATCH] uiomove*_cap: Refactor using UIO_READ/WRITE_CAP permissions This approach is more orthogonal and permits using capability copies with uiomove_frompyhs or higher level APIs like proc_rwmem without requiring additional *_cap wrapper routines. --- sys/arm64/arm64/mem.c | 5 +++ sys/arm64/arm64/uio_machdep.c | 19 ++++++++- sys/cam/scsi/scsi_target.c | 8 ++-- sys/compat/lindebugfs/lindebugfs.c | 5 +++ sys/dev/iicbus/iic.c | 10 +++++ sys/fs/procfs/procfs_osrel.c | 5 +++ sys/kern/kern_physio.c | 10 +++++ sys/kern/subr_uio.c | 63 ++++++++++++------------------ sys/kern/vfs_vnops.c | 23 +++++++++++ sys/riscv/riscv/mem.c | 5 +++ sys/riscv/riscv/uio_machdep.c | 16 ++++++++ sys/sys/_uio.h | 9 ++++- sys/sys/uio.h | 20 +++++++++- sys/ufs/ffs/ffs_suspend.c | 5 +++ 14 files changed, 160 insertions(+), 43 deletions(-) diff --git a/sys/arm64/arm64/mem.c b/sys/arm64/arm64/mem.c index 3e567b7e7db8..17487c51f59d 100644 --- a/sys/arm64/arm64/mem.c +++ b/sys/arm64/arm64/mem.c @@ -95,6 +95,11 @@ memrw(struct cdev *dev, struct uio *uio, int flags) case UIO_WRITE: prot = VM_PROT_WRITE; break; +#if __has_feature(capabilities) + case UIO_READ_CAP: + case UIO_WRITE_CAP: + __assert_unreachable(); +#endif } if (!kernacc((void *)(uintptr_t)v, cnt, prot)) { diff --git a/sys/arm64/arm64/uio_machdep.c b/sys/arm64/arm64/uio_machdep.c index 610edf566450..d77543f7154a 100644 --- a/sys/arm64/arm64/uio_machdep.c +++ b/sys/arm64/arm64/uio_machdep.c @@ -63,7 +63,8 @@ uiomove_fromphys(vm_page_t ma[], vm_offset_t offset, int n, struct uio *uio) int save = 0; bool mapped; - KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE, + KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE || + uio->uio_rw == UIO_READ_CAP || uio->uio_rw == UIO_WRITE_CAP, ("uiomove_fromphys: mode")); KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread, ("uiomove_fromphys proc")); @@ -97,6 +98,14 @@ uiomove_fromphys(vm_page_t ma[], vm_offset_t offset, int n, struct uio *uio) case UIO_USERSPACE: maybe_yield(); switch (uio->uio_rw) { +#if __has_feature(capabilities) + case UIO_READ_CAP: + error = copyoutcap(cp, iov->iov_base, cnt); + break; + case UIO_WRITE_CAP: + error = copyincap(iov->iov_base, cp, cnt); + break; +#endif case UIO_READ: error = copyout(cp, iov->iov_base, cnt); break; @@ -109,6 +118,14 @@ uiomove_fromphys(vm_page_t ma[], vm_offset_t offset, int n, struct uio *uio) break; case UIO_SYSSPACE: switch (uio->uio_rw) { +#if __has_feature(capabilities) + case UIO_READ_CAP: + bcopy_c(PTR2CAP(cp), iov->iov_base, cnt); + break; + case UIO_WRITE_CAP: + bcopy_c(iov->iov_base, PTR2CAP(cp), cnt); + break; +#endif case UIO_READ: bcopynocap_c(PTR2CAP(cp), iov->iov_base, cnt); break; diff --git a/sys/cam/scsi/scsi_target.c b/sys/cam/scsi/scsi_target.c index f826e1e953a0..b67708503a8c 100644 --- a/sys/cam/scsi/scsi_target.c +++ b/sys/cam/scsi/scsi_target.c @@ -530,10 +530,11 @@ targwrite(struct cdev *dev, struct uio *uio, int ioflag) write_len = error = 0; CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("write - uio_resid %zd\n", uio->uio_resid)); + uiomove_enable_cap(uio); while (uio->uio_resid >= sizeof(user_ccb) && error == 0) { union ccb *ccb; - error = uiomove_cap((caddr_t)&user_ccb, sizeof(user_ccb), uio); + error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio); if (error != 0) { CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("write - uiomove failed (%d)\n", error)); @@ -811,6 +812,7 @@ targread(struct cdev *dev, struct uio *uio, int ioflag) user_queue = &softc->user_ccb_queue; abort_queue = &softc->abort_queue; CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targread\n")); + uiomove_enable_cap(uio); /* If no data is available, wait or return immediately */ cam_periph_lock(softc->periph); @@ -850,7 +852,7 @@ targread(struct cdev *dev, struct uio *uio, int ioflag) if (error != 0) goto read_fail; cam_periph_unlock(softc->periph); - error = uiomove_cap((caddr_t)&user_ccb, sizeof(user_ccb), uio); + error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio); cam_periph_lock(softc->periph); if (error != 0) goto read_fail; @@ -873,7 +875,7 @@ targread(struct cdev *dev, struct uio *uio, int ioflag) goto read_fail; } cam_periph_unlock(softc->periph); - error = uiomove_cap((caddr_t)&user_ccb, sizeof(user_ccb), uio); + error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio); cam_periph_lock(softc->periph); if (error != 0) goto read_fail; diff --git a/sys/compat/lindebugfs/lindebugfs.c b/sys/compat/lindebugfs/lindebugfs.c index 5b84762f589c..871e4f90d0ed 100644 --- a/sys/compat/lindebugfs/lindebugfs.c +++ b/sys/compat/lindebugfs/lindebugfs.c @@ -158,6 +158,11 @@ debugfs_fill(PFS_FILL_ARGS) &off); } break; +#if __has_feature(capabilities) + case UIO_READ_CAP: + case UIO_WRITE_CAP: + __assert_unreachable(); +#endif } if (d->dm_fops->release) diff --git a/sys/dev/iicbus/iic.c b/sys/dev/iicbus/iic.c index 967f874e1479..b43fb75630ee 100644 --- a/sys/dev/iicbus/iic.c +++ b/sys/dev/iicbus/iic.c @@ -257,6 +257,11 @@ iicuio_move(struct iic_cdevpriv *priv, struct uio *uio, int last) if (error == 0) error = uiomove(buffer, transferred_bytes, uio); break; +#if __has_feature(capabilities) + case UIO_READ_CAP: + case UIO_WRITE_CAP: + __assert_unreachable(); +#endif } } @@ -299,6 +304,11 @@ iicuio(struct cdev *dev, struct uio *uio, int ioflag) case UIO_WRITE: addr = priv->addr & ~LSB; break; +#if __has_feature(capabilities) + case UIO_READ_CAP: + case UIO_WRITE_CAP: + __assert_unreachable(); +#endif } error = iicbus_start(parent, addr, 0); diff --git a/sys/fs/procfs/procfs_osrel.c b/sys/fs/procfs/procfs_osrel.c index 0102090de4da..43212214c7ae 100644 --- a/sys/fs/procfs/procfs_osrel.c +++ b/sys/fs/procfs/procfs_osrel.c @@ -65,6 +65,11 @@ procfs_doosrel(PFS_FILL_ARGS) } p->p_osrel = osrel; break; +#if __has_feature(capabilities) + case UIO_READ_CAP: + case UIO_WRITE_CAP: + __assert_unreachable(); +#endif } return (0); } diff --git a/sys/kern/kern_physio.c b/sys/kern/kern_physio.c index 707a38db256d..9e84ed61f0f9 100644 --- a/sys/kern/kern_physio.c +++ b/sys/kern/kern_physio.c @@ -127,6 +127,11 @@ physio(struct cdev *dev, struct uio *uio, int ioflag) uio->uio_iov[i].iov_len); racct_add_force(curproc, RACCT_WRITEIOPS, 1); break; +#if __has_feature(capabilities) + case UIO_READ_CAP: + case UIO_WRITE_CAP: + __assert_unreachable(); +#endif } PROC_UNLOCK(curproc); } @@ -143,6 +148,11 @@ physio(struct cdev *dev, struct uio *uio, int ioflag) bp->bio_cmd = BIO_WRITE; curthread->td_ru.ru_oublock++; break; +#if __has_feature(capabilities) + case UIO_READ_CAP: + case UIO_WRITE_CAP: + __assert_unreachable(); +#endif } bp->bio_offset = uio->uio_offset; base = uio->uio_iov[i].iov_base; diff --git a/sys/kern/subr_uio.c b/sys/kern/subr_uio.c index 9351ee548066..f04d7c6bae8c 100644 --- a/sys/kern/subr_uio.c +++ b/sys/kern/subr_uio.c @@ -68,8 +68,7 @@ SYSCTL_INT(_kern, KERN_IOV_MAX, iov_max, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, UIO_MA static uma_zone_t uio_zone; -static int uiomove_flags(void *cp, int n, struct uio *uio, bool nofault, - bool preserve_tags); +static int uiomove_flags(void *cp, int n, struct uio *uio, bool nofault); static void uio_init(void *arg __unused) @@ -214,27 +213,18 @@ int uiomove(void *cp, int n, struct uio *uio) { - return (uiomove_flags(cp, n, uio, false, false)); + return (uiomove_flags(cp, n, uio, false)); } int uiomove_nofault(void *cp, int n, struct uio *uio) { - return (uiomove_flags(cp, n, uio, true, false)); + return (uiomove_flags(cp, n, uio, true)); } -int -uiomove_cap(void *cp, int n, struct uio *uio) -{ - - return (uiomove_flags(cp, n, uio, false, true)); -} - - static int -uiomove_flags(void *cp, int n, struct uio *uio, bool nofault, - bool preserve_tags) +uiomove_flags(void *cp, int n, struct uio *uio, bool nofault) { struct iovec *iov; size_t cnt; @@ -242,7 +232,8 @@ uiomove_flags(void *cp, int n, struct uio *uio, bool nofault, save = error = 0; - KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE, + KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE || + uio->uio_rw == UIO_READ_CAP || uio->uio_rw == UIO_WRITE_CAP, ("uiomove: mode")); KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread, ("uiomove proc")); @@ -283,19 +274,19 @@ uiomove_flags(void *cp, int n, struct uio *uio, bool nofault, case UIO_USERSPACE: maybe_yield(); switch (uio->uio_rw) { +#if __has_feature(capabilities) + case UIO_READ_CAP: + error = copyoutcap(cp, iov->iov_base, cnt); + break; + case UIO_WRITE_CAP: + error = copyincap(iov->iov_base, cp, cnt); + break; +#endif case UIO_READ: - if (preserve_tags) - error = copyoutcap(cp, iov->iov_base, - cnt); - else - error = copyout(cp, iov->iov_base, cnt); + error = copyout(cp, iov->iov_base, cnt); break; case UIO_WRITE: - if (preserve_tags) - error = copyincap(iov->iov_base, cp, - cnt); - else - error = copyout(cp, iov->iov_base, cnt); + error = copyin(iov->iov_base, cp, cnt); break; } if (error) @@ -304,21 +295,19 @@ uiomove_flags(void *cp, int n, struct uio *uio, bool nofault, case UIO_SYSSPACE: switch (uio->uio_rw) { +#if __has_feature(capabilities) + case UIO_READ_CAP: + bcopy_c(PTR2CAP(cp), iov->iov_base, cnt); + break; + case UIO_WRITE_CAP: + bcopy_c(iov->iov_base, PTR2CAP(cp), cnt); + break; +#endif case UIO_READ: - if (preserve_tags) - bcopy_c(PTR2CAP(cp), iov->iov_base, - cnt); - else - bcopynocap_c(PTR2CAP(cp), iov->iov_base, - cnt); + bcopynocap_c(PTR2CAP(cp), iov->iov_base, cnt); break; case UIO_WRITE: - if (preserve_tags) - bcopy_c(iov->iov_base, PTR2CAP(cp), - cnt); - else - bcopynocap_c(iov->iov_base, PTR2CAP(cp), - cnt); + bcopynocap_c(iov->iov_base, PTR2CAP(cp), cnt); break; } break; diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 7d075cb80096..05a464b7e6c9 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -1268,6 +1268,11 @@ vn_io_fault_doio(struct vn_io_fault_args *args, struct uio *uio, error = VOP_WRITE(args->args.vop_args.vp, uio, args->flags, args->cred); break; +#if __has_feature(capabilities) + case UIO_READ_CAP: + case UIO_WRITE_CAP: + __assert_unreachable(); +#endif } break; default: @@ -1559,6 +1564,14 @@ vn_io_fault_uiomove(char *data, int xfersize, struct uio *uio) case UIO_READ: transp_uio.uio_rw = UIO_WRITE; break; +#if __has_feature(capabilities) + case UIO_WRITE_CAP: + transp_uio.uio_rw = UIO_READ_CAP; + break; + case UIO_READ_CAP: + transp_uio.uio_rw = UIO_WRITE_CAP; + break; +#endif } transp_uio.uio_td = uio->uio_td; error = uiomove_fromphys(td->td_ma, @@ -1603,6 +1616,16 @@ vn_io_fault_pgmove(vm_page_t ma[], vm_offset_t offset, int xfersize, pmap_copy_pages(ma, offset, td->td_ma, iov_base & PAGE_MASK, cnt); break; +#if __has_feature(capabilities) + case UIO_WRITE_CAP: + pmap_copy_pages_tags(td->td_ma, iov_base & PAGE_MASK, ma, + offset, cnt); + break; + case UIO_READ_CAP: + pmap_copy_pages_tags(ma, offset, td->td_ma, + iov_base & PAGE_MASK, cnt); + break; +#endif } pgadv = ((iov_base + cnt) >> PAGE_SHIFT) - (iov_base >> PAGE_SHIFT); td->td_ma += pgadv; diff --git a/sys/riscv/riscv/mem.c b/sys/riscv/riscv/mem.c index df1071213084..fce73ec02bc9 100644 --- a/sys/riscv/riscv/mem.c +++ b/sys/riscv/riscv/mem.c @@ -102,6 +102,11 @@ memrw(struct cdev *dev, struct uio *uio, int flags) case UIO_WRITE: prot = VM_PROT_WRITE; break; +#if __has_feature(capabilities) + case UIO_READ_CAP: + case UIO_WRITE_CAP: + __assert_unreachable(); +#endif } if (!kernacc((void *)(uintptr_t)v, cnt, prot)) { diff --git a/sys/riscv/riscv/uio_machdep.c b/sys/riscv/riscv/uio_machdep.c index 16e02df7b910..0d2a0541e5fa 100644 --- a/sys/riscv/riscv/uio_machdep.c +++ b/sys/riscv/riscv/uio_machdep.c @@ -97,6 +97,14 @@ uiomove_fromphys(vm_page_t ma[], vm_offset_t offset, int n, struct uio *uio) case UIO_USERSPACE: maybe_yield(); switch (uio->uio_rw) { +#if __has_feature(capabilities) + case UIO_READ_CAP: + error = copyoutcap(cp, iov->iov_base, cnt); + break; + case UIO_WRITE_CAP: + error = copyincap(iov->iov_base, cp, cnt); + break; +#endif case UIO_READ: error = copyout(cp, iov->iov_base, cnt); break; @@ -109,6 +117,14 @@ uiomove_fromphys(vm_page_t ma[], vm_offset_t offset, int n, struct uio *uio) break; case UIO_SYSSPACE: switch (uio->uio_rw) { +#if __has_feature(capabilities) + case UIO_READ_CAP: + bcopy_c(PTR2CAP(cp), iov->iov_base, cnt); + break; + case UIO_WRITE_CAP: + bcopy_c(iov->iov_base, PTR2CAP(cp), cnt); + break; +#endif case UIO_READ: bcopynocap_c(PTR2CAP(cp), iov->iov_base, cnt); break; diff --git a/sys/sys/_uio.h b/sys/sys/_uio.h index 5fc789a41c52..5a343b8245ce 100644 --- a/sys/sys/_uio.h +++ b/sys/sys/_uio.h @@ -35,7 +35,14 @@ #if __BSD_VISIBLE enum uio_rw { UIO_READ, - UIO_WRITE + UIO_WRITE, +#if __has_feature(capabilities) + UIO_READ_CAP, + UIO_WRITE_CAP +#else + UIO_READ_CAP = UIO_READ, + UIO_WRITE_CAP = UIO_WRITE +#endif }; /* Segment flag values. */ diff --git a/sys/sys/uio.h b/sys/sys/uio.h index 6d4db59505bd..de91757dbbe0 100644 --- a/sys/sys/uio.h +++ b/sys/sys/uio.h @@ -84,6 +84,25 @@ struct uio { }; } __aligned(sizeof(void * __capability)); +#if __has_feature(capabilities) +static __inline void +uiomove_enable_cap(struct uio *uio) +{ + switch (uio->uio_rw) { + case UIO_READ: + uio->uio_rw = UIO_READ_CAP; + break; + case UIO_WRITE: + uio->uio_rw = UIO_WRITE_CAP; + break; + default: + break; + } +} +#else +#define uiomove_enable_cap(uio) +#endif + /* * Limits * @@ -117,7 +136,6 @@ int physcopyin_vlist(struct bus_dma_segment *src, off_t offset, int physcopyout_vlist(vm_paddr_t src, struct bus_dma_segment *dst, off_t offset, size_t len); int uiomove(void *cp, int n, struct uio *uio); -int uiomove_cap(void *cp, int n, struct uio *uio); int uiomove_frombuf(void *buf, int buflen, struct uio *uio); int uiomove_fromphys(struct vm_page *ma[], vm_offset_t offset, int n, struct uio *uio); diff --git a/sys/ufs/ffs/ffs_suspend.c b/sys/ufs/ffs/ffs_suspend.c index b33a0efb016a..d603d4f6aff7 100644 --- a/sys/ufs/ffs/ffs_suspend.c +++ b/sys/ufs/ffs/ffs_suspend.c @@ -156,6 +156,11 @@ ffs_susp_rdwr(struct cdev *dev, struct uio *uio, int ioflag) if (error != 0) goto out; break; +#if __has_feature(capabilities) + case UIO_READ_CAP: + case UIO_WRITE_CAP: + __assert_unreachable(); +#endif } IOVEC_ADVANCE(&uio->uio_iov[i], len); uio->uio_resid -= len;