-
Notifications
You must be signed in to change notification settings - Fork 0
CHERI CSA Checkers
- Pointer Alignment
- Provenance Source
- Capability Copy
- Pointer Size Assumptions
- Subobject Representability
- Allocation
optin.portability.PointerAlignment
Reports
- Pointer casts of underaligned values to types with strict alignment requirements
- Not capability-aligned pointer (potentially) used as capability storage
- Copying capabilities through underaligned memory
See CHERI C/C++ Programming Guide §4.2.2.
Special case for CHERI: casts to pointer to capability. Storing capabilities at not capability-aligned addressed will result in stored capability losing its tag.
double a[2048];
void** foo(void) {
char *p0 = (char*)a;
// Pointer p0 is aligned to a 8 byte boundary;
// type 'void **' requires capability alignment (16 bytes)
return (void**)p0;
}
Currently, this checker (deliberately) does not take into account:
- alignment of static and automatic allocations, enforced by current ABI (other than implied by variable types),
- alignment of fields that is guaranteed implicitly by the alignment of the whole object and current field offset.
Therefore, a variable or field may always be correctly aligned at runtime due to current ABI restrictions or structure layout, but still reported by the checker. This is not considered a False Positive, as relying on this could make the code less portable and easier to break in the future. Specifying expected alignment explicitly is recommended for this case.
Example:
#define N 100
struct S { // aligned as (void*)
int a[N];
// offsetof(struct S, f) == 400 => field f is always 16-byte aligned
char f[N]; /* Warn: Original allocation of type 'char [100]' which has an alignment requirement 1 bytes */
void *p;
} s;
/* Warn: Pointer value aligned to a 1 byte boundary cast to type 'uintptr_t * __capability' with required capability alignment 16 bytes*/
uintptr_t *t = (uintptr_t*)&s.f;
BugType | Category | Notes |
---|---|---|
Cast increases required alignment | Type Error | |
Cast increases required alignment to capability alignment | CHERI portability | Special case for CHERI |
Example:
char extra[100]; // Aligned to 1 byte
void alloc(void** p) {
// Warn: Pointer value aligned to a 1 byte boundary stored as value
// of type 'intptr_t * __capability'. Memory pointed by it is
// supposed to hold capabilities, for which 16-byte capability alignment
// will be required
*p = extra;
}
intptr_t *test_assign(void) {
intptr_t *cp;
alloc((void**)&cp); // call
return cp;
}
BugType | Category | Notes |
---|---|---|
Not capability-aligned pointer used as capability storage | CHERI portability | |
Not capability-aligned pointer stored as void*
|
CHERI portability | Assuming void* can be used as capability storage |
Example:
char a[100]; // Aligned to 1 byte
void foo(intptr_t *pCap, size_t n) {
// Warn: Destination memory object pointed by 'intptr_t * __capability'
// pointer is supposed to contain capabilities that require 16-byte
// capability alignment. Source address alignment is 1, which means that
// copied object may have its capabilities tags stripped earlier
// due to underaligned storage
memcpy(pCap, a, n);
}
BugType | Category | Notes |
---|---|---|
Copying capabilities through underaligned memory | CHERI portability |
cheri.ProvenanceSource
- Tracks integers and pointers stored as
(u)intptr_t
type - Fires a warning for
(u)intptr_t
binary operations with ambiguous provenance source (same as clang) and tells which side carries (or not) the provenance along the path - Fires a warning when the
(u)intptr_t
value obtained from the ambiguous-provenance-operation is cast to pointer type - Fires a warning when
NULL
-derived(u)intptr_t
capability is cast to pointer type
See CHERI C/C++ Programming Guide §4.2.3.
BugType | Notes |
---|---|
CHERI-incompatible pointer arithmetic | RHS and LHS are (u)intptr_t values derived from pointers |
Capability derived from wrong argument | RHS is a (u)intptr_t value derived from pointer (LHS is NULL-derived or unknown) |
Binary operation with ambiguous provenance | RHS is NULL-derived or unknown |
NULL-derived capability: loss of provenance |
(u)intptr_t value derived from NULL cast to pointer type |
NULL-derived capability used as pointer | Pointer passed through non‑capability integer type |
Capability with ambiguous provenance used as pointer | Result of an (u)intptr_t binary operation with ambiguous provenance cast to pointer type |
Option | Type | Default | Description |
---|---|---|---|
ShowFixIts |
bool |
false |
Enable fix-it hints for this checker |
ReportForAmbiguousProvenance |
bool |
true |
Report for binary operations with ambiguous provenance for which the default capability derivation from LHS is fine. Automatically set to false if [-Wcheri-provenance] compiler warning is disabled. |
Example:
-analyzer-config cheri.ProvenanceSource:ShowFixIts=true
cheri.CapabilityCopy
- Detects tag-stripping loads and stores that may be used to copy or swap capabilities.
- Detects capability representation bytes being used in binary operator (e.g. as the input to a hash function or similar computations).
BugType | Notes |
---|---|
Tag-stripping copy of capability | CHERI C/C++ Programming Guide §4.2 |
Part of capability value used in binary operator | CHERI C/C++ Programming Guide §4.6 |
Example:
void memcpy_impl(void* src0, void *dst0, size_t len) {
char *src = src0;
char *dst = dst0;
while (len--)
*dst++ = *src++; // Tag-stripping store of a capability
}
Option | Type | Default | Description |
---|---|---|---|
ReportForCharPtr |
bool |
true |
Report tag-stripping copy for char* function parameters. Suppression of warnings for C-strings is currently used to reduce the number of false alarms, but it's not very reliable |
Example:
-analyzer-config cheri.CapabilityCopy:ReportForCharPtr=true
cheri.PointerSizeAssumptions
This checker detects code where the pointer size was checked against constant, but the case of capabilities was not addressed explicitly.
Example:
long i64;
void *p;
// This code fails to consider the case of 128-bit pointers
if (sizeof(i64) == sizeof(p)) {
// [...]
} else {
// [...]
}
BugType | Notes |
---|---|
Only a limited number of pointer sizes checked | AST-checker |
cheri.SubObjectRepresentability
This checker detects record fields that will not have precise bounds when compiled with -cheri-bounds=subobject-safe
due to big size and underaligned offset, as narrowed capability will not be representable.
See CHERI C/C++ Programming Guide §4.3.3, §7.5.
Example:
struct rte_lpm6 {
struct rte_lpm6_external ext; // 32/32 bytes exposed (may expose capability!)
char name[RTE_LPM6_NAMESIZE]; // 32/32 bytes exposed
uint32_t max_rules; // 32/32 bytes exposed
uint32_t used_rules; // 4/4 bytes exposed
uint32_t number_tbl8s; // 4/4 bytes exposed
// Warn: Field 'tbl24' of type 'struct rte_lpm6_tbl_entry[16777216]'
// (size 67108864) requires 32768 byte alignment for precise bounds;
// field offset is 128 (aligned to 128); Current bounds: 0-67141632
struct rte_lpm6_tbl_entry tbl24[RTE_LPM6_TBL24_NUM_ENTRIES]
...
BugType | Notes |
---|---|
Address taken of a field with imprecise subobject bounds | |
Field with imprecise subobject bounds | superset for previous warning |
alpha.cheri.Allocation
This checker detects unrelated objects being allocated as adjacent suballocations of the bigger memory allocation. It reports situations when an address of such object escapes the function and suggests narrowing the bounds of the escaping capability, so it covers only the current suballocation, following the principle of least privilege.
See CHERI C/C++ Programming Guide §7.3
Example:
struct S2 * foo(int n1, int n2) {
struct S1 *p1 = malloc(sizeof(struct S1)*n1 + sizeof(struct S2)*n2);
struct S2 *p2 = (struct S2 *)(p1+n1);
// Warn: Pointer to suballocation returned from function
// (consider narrowing the bounds for suballocation)
return p2;
}
BugType | Notes |
---|---|
Allocation partitioning | static, stack, heap allocations |
Unknown allocation partitioning | untracked allocations |
Option | Type | Default | Description |
---|---|---|---|
ReportForUnknownAllocations |
bool |
true |
Report for unknown allocations |