Skip to content

Warning description

Irina Dudina edited this page Apr 1, 2024 · 3 revisions

Pointer alignment

1. Cast increases required alignment to capability alignment

Not capability-aligned pointer cast to pointer to capability-aligned type.

Example:

typedef struct S_t {
  /* other fields */
  double f[1];  // aligned to 8-byte boundary
} S;

void foo(int n) {
  S* p = malloc(sizeof(S) + (n-1)*sizeof(double) + n*sizeof(T*));

  /* 1. &p->f[n] is 8-bytes aligned
   * 2. T** type requires 16-byte alignment
   */
  T** t = (T**)&p->f[n];
}

Warning message:

Pointer value aligned to a 8 byte boundary cast to type 'T * __capability * __capability' with 16-byte capability alignment

2. Not capability-aligned pointer used as capability storage

Underaligned pointer value assigned to a pointer that must be capability-aligned.

uint8_t extra[100]; // aligned to 1-byte boundary

void alloc(void** pp) {
    *pp = &extra[0]; // assign
}

intptr_t *foo(void) {
  intptr_t *cp; // requires 16-byte alignment
  alloc((void**)&cp); // cp initialised with underaligned value
  return cp;
}

Warning message:

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

3. Not capability-aligned pointer stored as 'void*'

This checker assumes that void* fields and global variables are intended to hold pointers to arbitrary data, potentially including capability-containing objects. Assigning an address of an underaligned allocation to such variable is reported (unless this allocation is already initialized).

Example:

struct S {
  void *p; // *p may be used to hold capabilities
};

uint8_t extra[100]; // aligned to 1-byte boundary

void foo(struct S *pS) {
  pS->p = &extra[0]; // assigning underaligned allocation to void* field
}

Warning message:

Pointer value aligned to a 1 byte boundary stored as value of type 'void * __capability'. Memory pointed by it may be used to hold capabilities, for which 16-byte capability alignment will be required

4. Copying capabilities through underaligned memory

Example:

uint8_t extra[100]; // aligned to 1-byte boundary

void foo(intptr_t *pCap, int n) {
  memcpy(extra, pCap, n * sizeof(intptr_t));
}

Warning message:

Copied memory object pointed by 'intptr_t * __capability' pointer contains capabilities that require 16-byte capability alignment. Destination address alignment is 1. Storing a capability at an underaligned address leads to tag stripping.

Pointers as integers

1. NULL-derived capability used as pointer

char *foo(char *a, unsigned x) {
  intptr_t ip = ((ptrdiff_t)a | (intptr_t)x); // ip derived from x
  char *p = (char*) ip; // p is not a valid pointer
  return p;
}

Warning message:

NULL-derived capability used as pointer

2. cheri_no_provenance capability used as pointer

Similar to previous warning, but with immediate integer->(u)intptr_t->pointer conversion. This is usually intentional.

void* foo(unsigned x) {
  void *q = (void*)(uintptr_t)x; // q is not a valid pointer
}

Warning message:

cheri_no_provenance capability used as pointer

3. CHERI-incompatible pointer arithmetic

intptr_t cmp1 (char *e0, char *e1) {
  intptr_t x = (intptr_t)e0 ^ (intptr_t)e1; // single-provenance rule violated
  return x & (cmp(e0, e1) >> 31); // x is not a valid capability
}

Clang warning:

binary expression on capability types 'uintptr_t' (aka 'unsigned __intcap') and 'uintptr_t'; it is not clear which should be used as the source of provenance; currently provenance is inherited from the left-hand side

CSA-warning:

Result of '^' on capability type 'unsigned __intcap'; it is unclear which side should be used as the source of provenance. Note: along this path, LHS and RHS were derived from pointers. Result capability will be derived from LHS by default. This code may need to be rewritten for CHERI.

4. Capability derived from wrong argument

uintptr_t foo(unsigned d, char *p) {
  uintptr_t a = d; // NULL-derived
  uintptr_t b = (uintptr_t)p;

  uintptr_t s = a + b; // s is derived from a
  return s;
}

Clang warning:

binary expression on capability types 'uintptr_t' (aka 'unsigned __intcap') and 'uintptr_t'; it is not clear which should be used as the source of provenance; currently provenance is inherited from the left-hand side

CSA-warning:

Result of '+' on capability type 'unsigned __intcap'; it is unclear which side should be used as the source of provenance. Note: along this path, LHS was derived from NULL, RHS was derived from pointer. Currently, provenance is inherited from LHS, therefore result capability will be invalid

5. Binary operation with ambiguous provenance

uintptr_t align_down(void *p, size_t a) {
    uintptr_t sz = (uintptr_t)p;
    uintptr_t m = a - 1;
    return (sz & ~m);
}

Clang warning:

binary expression on capability types 'uintptr_t' (aka 'unsigned __intcap') and 'uintptr_t'; it is not clear which should be used as the source of provenance; currently provenance is inherited from the left-hand side

CSA-warning:

Result of '&' on capability type 'unsigned __intcap'; it is unclear which side should be used as the source of provenance; consider indicating the provenance-carrying argument explicitly by casting the other argument to 'size_t'. Note: along this path, LHS was derived from pointer, RHS was derived from NULL

Clone this wiki locally