diff --git a/share/man/man9/copy.9 b/share/man/man9/copy.9 --- a/share/man/man9/copy.9 +++ b/share/man/man9/copy.9 @@ -32,15 +32,19 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd May 11, 2020 +.Dd June 29, 2026 .Dt COPY 9 .Os .Sh NAME .Nm copy , .Nm copyin , .Nm copyin_nofault , +.Nm copyinptr , +.Nm copyinptr_nofault , .Nm copyout , .Nm copyout_nofault , +.Nm copyoutptr , +.Nm copyoutptr_nofault , .Nm copystr , .Nm copyinstr .Nd heterogeneous address space copy functions @@ -52,9 +56,17 @@ .Ft int .Fn copyin_nofault "const void *uaddr" "void *kaddr" "size_t len" .Ft int +.Fn copyinptr "const void *uaddr" "void *kaddr" "size_t len" +.Ft int +.Fn copyinptr_nofault "const void *uaddr" "void *kaddr" "size_t len" +.Ft int .Fn copyout "const void *kaddr" "void *uaddr" "size_t len" .Ft int .Fn copyout_nofault "const void *kaddr" "void *uaddr" "size_t len" +.Ft int +.Fn copyoutptr "const void *kaddr" "void *uaddr" "size_t len" +.Ft int +.Fn copyoutptr_nofault "const void *kaddr" "void *uaddr" "size_t len" .Ft int __deprecated .Fn copystr "const void *kfaddr" "void *kdaddr" "size_t len" "size_t *done" .Ft int @@ -81,7 +93,15 @@ bytes of data from the user-space address .Fa uaddr to the kernel-space address -.Fa kaddr . +.Fa kaddr +without preserving the provenance of pointers in the copied object +.Pq see Xr memory_model 7 for further information . +The +.Fn copyinptr +and +.Fn copyinptr_nofault +functions do the same, +but preserves the provenance of copied pointers to user-space. .Pp The .Fn copyout @@ -92,12 +112,21 @@ bytes of data from the kernel-space address .Fa kaddr to the user-space address -.Fa uaddr . +.Fa uaddr +without preserving the provenance of pointers in the copied object. +The +.Fn copyoutptr +and +.Fn copyoutptr_nofault +functions do the same, +but preserves the provenance of copied pointers to user-space. .Pp The -.Fn copyin_nofault +.Fn copyin_nofault , +.Fn copyinptr_nofault , +.Fn copyout_nofault , and -.Fn copyout_nofault +.Fn copyoutptr_nofault functions require that the kernel-space and user-space data be accessible without incurring a page fault. The source and destination addresses must be physically mapped for @@ -105,6 +134,16 @@ destination addresses may be pageable. .Pp The +.Fn copyinptr , +.Fn copyinptr_nofault , +.Fn copyoutptr , +and +.Fn copyoutptr_nofault +functions must be used when copying data which may contain pointers, +but they should only be used when necessary to limit the number of +code paths that could leak pointers between address spaces. +.Pp +The .Fn copystr function copies a NUL-terminated string, at most .Fa len diff --git a/sys/kern/subr_uio.c b/sys/kern/subr_uio.c --- a/sys/kern/subr_uio.c +++ b/sys/kern/subr_uio.c @@ -88,6 +88,30 @@ return (error); } +#ifdef __CHERI__ +int +copyinptr_nofault(const void *udaddr, void *kaddr, size_t len) +{ + int error, save; + + save = vm_fault_disable_pagefaults(); + error = copyinptr(udaddr, kaddr, len); + vm_fault_enable_pagefaults(save); + return (error); +} + +int +copyoutptr_nofault(const void *kaddr, void *udaddr, size_t len) +{ + int error, save; + + save = vm_fault_disable_pagefaults(); + error = copyoutptr(kaddr, udaddr, len); + vm_fault_enable_pagefaults(save); + return (error); +} +#endif + #define PHYS_PAGE_COUNT(len) (howmany(len, PAGE_SIZE) + 1) int diff --git a/sys/sys/systm.h b/sys/sys/systm.h --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -313,6 +313,24 @@ const void * _Nonnull __restrict kaddr, void * __restrict udaddr, size_t len); +#ifdef __CHERI__ +__nodiscard int copyinptr(const void * __restrict udaddr, + void * _Nonnull __restrict kaddr, size_t len); +__nodiscard int copyinptr_nofault(const void * __restrict udaddr, + void * _Nonnull __restrict kaddr, size_t len); +__nodiscard int copyoutptr( + const void * _Nonnull __restrict kaddr, void * __restrict udaddr, + size_t len); +__nodiscard int copyoutptr_nofault( + const void * _Nonnull __restrict kaddr, void * __restrict udaddr, + size_t len); +#else +#define copyinptr copyin +#define copyinptr_nofault copyin_nofault +#define copyoutptr copyout +#define copyoutptr_nofault copyout_nofault +#endif + #ifdef SAN_NEEDS_INTERCEPTORS int SAN_INTERCEPTOR(copyin)(const void *, void *, size_t); int SAN_INTERCEPTOR(copyinstr)(const void *, void *, size_t, size_t *);