-
Notifications
You must be signed in to change notification settings - Fork 56
Unaligned capability copies
Copying a capability to an unaligned destination will result in tag bits being stripped since they are only retained when using copies with csc
/clc
instructions.
Diagnosed function calls: memcpy()
, memmove()
, __builtin_memcpy()
and __builtin_memmove()
There are two issues that need to be considered here:
For example the following code will sometimes result in buffer
not containing the tag bit from value
:
void test(uintcap_t value) {
char buffer[sizeof(uintcap_t)];
memcpy(buffer, &value, sizeof(value));
do_something(buffer);
}
If buffer
happens to be aligned to alignof(void*__capability)
(i.e. 16 bytes or 32 for CHERI256) at runtime then a call to memcpy()
will
result in the tag bits being copied because memcpy()
will use csc
/clc
. However, if it is only aligned to four or eight bytes, then memcpy()
will end up using clw
or cld
instructions and produce a byte-by-byte indetical copy of the capability but without the tag bit set.
If you use memcpy() with a source type containing capability to a buffer that the compiler cannot statically prove to be at least capability aligned, it will not be able to expand the memcpy() in a sequence of loads and stores. Even if it is only 16 bytes of data being copied.
void* my_copy(void* dst, void* src) {
// The following could be expanded inline by the compiler and strip tags.
// Possible since the size is a constant and small enough to be expanded
// in a few instructions.
return memcpy(dst, src, sizeof(uincap_t));
}
Note: we could diagnose copies with a void*
source and assume these might contain capabilities but that would
almost certainly be an extremely noisy warning.