diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -1615,6 +1615,8 @@ mdchain.9 md_get_uio.9 \ mdchain.9 md_initm.9 \ mdchain.9 md_next_record.9 +MLINKS+=memcpy.9 memcpy_data.9 +MLINKS+=memmove.9 memmove_data.9 MLINKS+=microtime.9 bintime.9 \ microtime.9 getbintime.9 \ microtime.9 getmicrotime.9 \ diff --git a/share/man/man9/memcpy.9 b/share/man/man9/memcpy.9 --- a/share/man/man9/memcpy.9 +++ b/share/man/man9/memcpy.9 @@ -33,12 +33,15 @@ .Dt MEMCPY 9 .Os .Sh NAME -.Nm memcpy +.Nm memcpy , +.Nm memcpy_data .Nd copy bytes in memory .Sh SYNOPSIS .In sys/systm.h .Ft void * .Fn memcpy "void *dst" "const void *src" "size_t len" +.Ft void * +.Fn memcpy_data "void *dst" "const void *src" "size_t len" .Sh DESCRIPTION The .Fn memcpy @@ -46,23 +49,30 @@ .Fa len bytes from object .Fa src -to object -.Fa dst . +to string +.Fa dst +in a manner that preserves pointer provenance. If .Fa src and .Fa dst overlap, the results are not defined. +The +.Fn memcpy_data +function does the same except that it does not perserve pointer +provenance. .Sh RETURN VALUES The .Fn memcpy -function -returns the original value of +and +.Fn memcpy_data +functions return the original value of .Fa dst . .Pp .Sh SEE ALSO .Xr bcopy 9 , -.Xr memmove 9 +.Xr memmove 9 , +.Xr memmove_data 9 .Sh STANDARDS The .Fn memcpy @@ -76,3 +86,7 @@ .At V and was reimplemented for .Bx 4.3 Tahoe . +The +.Fn memcpy_data +function first appeared in +.Fx 16.0 . diff --git a/share/man/man9/memmove.9 b/share/man/man9/memmove.9 --- a/share/man/man9/memmove.9 +++ b/share/man/man9/memmove.9 @@ -34,11 +34,14 @@ .Os .Sh NAME .Nm memmove +.Nm memmove_data .Nd copy bytes in memory .Sh SYNOPSIS .In sys/systm.h .Ft void * .Fn memmove "void *dst" "const void *src" "size_t len" +.Ft void * +.Fn memmove_data "void *dst" "const void *src" "size_t len" .Sh DESCRIPTION The .Fn memmove @@ -50,17 +53,29 @@ .Fa dst . The two objects may overlap; the copy is always done in a non-destructive manner. +The +.Fn memcpy_data +function does the same except that it does not perserve pointer +provenance. .Sh RETURN VALUES The .Fn memmove -function returns the original value of +and +.Fn memmove_data +functions return the original value of .Fa dst . .Sh SEE ALSO .Xr bcopy 9 , -.Xr memcpy 9 +.Xr memcpy 9 , +.Xr memcpy_data 9 .Sh STANDARDS The .Fn memmove function conforms to .St -isoC . +.Sh HISTORY +The +.Fn memmove_data +function first appeared in +.Fx 16.0 . diff --git a/sys/libkern/bcopy.c b/sys/libkern/bcopy.c --- a/sys/libkern/bcopy.c +++ b/sys/libkern/bcopy.c @@ -35,10 +35,16 @@ #include #ifdef _KERNEL #include +#include #else +#include #include #endif +#ifdef __CHERI__ +#include +#endif + #undef memcpy #undef memmove @@ -46,7 +52,7 @@ * sizeof(word) MUST BE A POWER OF TWO * SO THAT wmask BELOW IS ALL ONES */ -typedef long word; /* "word" used for optimal copy speed */ +typedef uintptr_t word; /* "word" used for optimal copy speed */ #define wsize sizeof(word) #define wmask (wsize - 1) @@ -56,8 +62,8 @@ * This is the routine that actually implements * (the portable versions of) bcopy, memcpy, and memmove. */ -void * -memcpy(void *dst0, const void *src0, size_t length) +static void * +_memcpy(void *dst0, const void *src0, size_t length, bool keeptags) { char *dst; const char *src; @@ -82,12 +88,12 @@ */ t = (size_t)src; /* only need low bits */ - if ((t | (uintptr_t)dst) & wmask) { + if ((t | (ptraddr_t)dst) & wmask) { /* * Try to align operands. This cannot be done * unless the low bits match. */ - if ((t ^ (uintptr_t)dst) & wmask || length < wsize) { + if ((t ^ (ptraddr_t)dst) & wmask || length < wsize) { t = length; } else { t = wsize - (t & wmask); @@ -100,8 +106,15 @@ * Copy whole words, then mop up any trailing bytes. */ t = length / wsize; - TLOOP(*(word *)dst = *(const word *)src; src += wsize; - dst += wsize); +#ifdef __CHERI__ + if (!keeptags) { + TLOOP(*(word *)dst = (word)cheri_tag_clear( + (void *)*(const word *)src); + src += wsize; dst += wsize); + } else +#endif + TLOOP(*(word *)dst = *(const word *)src; src += wsize; + dst += wsize); t = length & wmask; TLOOP(*dst++ = *src++); } else { @@ -112,10 +125,10 @@ */ src += length; dst += length; - t = (uintptr_t)src; + t = (size_t)src; - if ((t | (uintptr_t)dst) & wmask) { - if ((t ^ (uintptr_t)dst) & wmask || length <= wsize) { + if ((t | (ptraddr_t)dst) & wmask) { + if ((t ^ (ptraddr_t)dst) & wmask || length <= wsize) { t = length; } else { t &= wmask; @@ -125,8 +138,15 @@ TLOOP1(*--dst = *--src); } t = length / wsize; - TLOOP(src -= wsize; dst -= wsize; - *(word *)dst = *(const word *)src); +#ifdef __CHERI__ + if (!keeptags) { + TLOOP(src -= wsize; dst -= wsize; + *(word *)dst = (word)cheri_tag_clear( + (void *)*(const word *)src)); + } else +#endif + TLOOP(src -= wsize; dst -= wsize; + *(word *)dst = *(const word *)src); t = length & wmask; TLOOP(*--dst = *--src); } @@ -134,4 +154,20 @@ return (dst0); } +void * +memcpy(void *dst0, const void *src0, size_t length) +{ + return _memcpy(dst0, src0, length, true); +} + __strong_reference(memcpy, memmove); + +#ifdef __CHERI__ +void * +memcpy_data(void *dst0, const void *src0, size_t length) +{ + return _memcpy(dst0, src0, length, false); +} + +__strong_reference(memcpy_data, memmove_data); +#endif diff --git a/sys/sys/systm.h b/sys/sys/systm.h --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -256,6 +256,15 @@ void *memcpy(void * _Nonnull to, const void * _Nonnull from, size_t len); void *memmove(void * _Nonnull dest, const void * _Nonnull src, size_t n); int memcmp(const void *b1, const void *b2, size_t len); +#ifdef __CHERI__ +void *memcpy_data(void * _Nonnull to, const void * _Nonnull from, + size_t len); +void *memmove_data(void * _Nonnull dest, const void * _Nonnull src, + size_t n); +#else +#define memcpy_data memcpy +#define memmove_data memmove +#endif #ifdef SAN_NEEDS_INTERCEPTORS #define SAN_INTERCEPTOR(func) \