Skip to content

Commit

Permalink
libkern: Fix bcopy_c/memcpy_c handling of final capability
Browse files Browse the repository at this point in the history
The use of > rather than >= meant that for capability-aligned ends the
final capability was copied byte-wise, losing its tag, rather than as a
capability. This bug has been present since the very first commit of
this generic C version, but does not appear to have existed in the old
CHERI-MIPS assembly version.

Notably this breaks the DRM_IOCTL_VERSION ioctl, which has a capability
as its final struct member, in hybrid kernels, since the memcpy_c used
in drm_ioctl clears the tag on that member and then proceeds to EFAULT
when trying to copy out to it. This gets even worse for libdrm since the
mutated struct is then copied back out itself, and libdrm tries to free
the pointer on error, which results in a tag fault.
  • Loading branch information
jrtc27 committed Nov 16, 2022
1 parent c9a12b8 commit a0af5b2
Showing 1 changed file with 2 additions and 2 deletions.
4 changes: 2 additions & 2 deletions sys/libkern/bcopy_c.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ memcpy_c(void * __capability dst0, const void * __capability src0, size_t len)
(void *)(__cheri_addr uintptr_t)src));

/* Copy capabilities. */
while (len > sizeof(uintcap_t)) {
while (len >= sizeof(uintcap_t)) {
*(uintcap_t * __capability)dst =
*(const uintcap_t * __capability)src;
dst += sizeof(uintcap_t);
Expand Down Expand Up @@ -118,7 +118,7 @@ memcpy_c(void * __capability dst0, const void * __capability src0, size_t len)
("src %p not aligned", (void *)(__cheri_addr uintptr_t)src));

/* Copy capabilities. */
while (len > sizeof(uintcap_t)) {
while (len >= sizeof(uintcap_t)) {
dst -= sizeof(uintcap_t);
src -= sizeof(uintcap_t);
*(uintcap_t * __capability)dst =
Expand Down

0 comments on commit a0af5b2

Please sign in to comment.