CHERI: declare copy{in,out}ptr{,_nofault}

These provenance-preserving functions are to be used when copying
objects that are expected to contain pointers.  Data buffers which do
not contain pointers should be copied by the traditional copyin/copyout
functions which *do not* preserve pointer provenance (on CHERI they
clear validity tags).

NOTE: Going forward, this requires changes when adding new syscalls or
ioctl that take pointers to objects containing pointers.  Fortunately,
the vast majority (>90%) of copyin and copyout statements do not copy
pointers and require no change.  Failure to make the chance will have no
effect on non-CHERI architectures.

Reviewed by:	kib, markj
Effort:		CHERI upstreaming
Sponsored by:	DARPA, AFRL, Innovate UK
Differential Revision:	https://reviews.freebsd.org/D57663
This commit is contained in:
Brooks Davis committed 2026-06-29 13:59:29 +01:00
1 parent bbc2d15857
commit b517edb8de
3 files changed
+86 -5

No files matched your search

+44 -5
View File
@@ -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 @@ functions copy
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 @@ functions copy
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 @@ read and write access, respectively, and neither the source nor
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
+24
View File
@@ -88,6 +88,30 @@ copyout_nofault(const void *kaddr, void *udaddr, size_t len)
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
+18
View File
@@ -313,6 +313,24 @@ __nodiscard int copyout_nofault(
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 *);