Any views expressed within media held on this service are those of the contributors, should not be taken as approved or endorsed by the University, and do not necessarily reflect the views of the University in respect of any particular issue.

Morello / Edinburgh

Morello / Edinburgh

Digital Security by Design Technology Platform Prototype

Static Analysis for CHERI

Fork of Clang Static Analyzer for detecting portability issues in C/C++ on CHERI

Porting to CHERI for many projects is relatively easy and requires minimal changes to the source code. Most of the incompatibility issues are detected at compile time, and compiler warnings are usually very helpful to understand and fix the problem.
However, some issues, especially in low-level code, are not flagged by the compiler and only surface at runtime, hopefully during testing. In this case, the chances of uncovering the issue depend on the test coverage of the project.
A static analysis tool could be helpful to increase the number of incompatibility issues detected at the early stage of the porting process, get an insight into the root cause of the problem, and a suggestion on how this might be fixed.

CHERI CSA tool is based on a Clang Static Analyzer and provides a couple of useful checkers to detect common issues missed by the compiler. It’s just a start, and more checkers are to be added in the future.

 

Dragons and cherries in Neo-Cubism

Illustration created in NightCafe Studio by AI

 

 

Clang Static Analyzer (CSA)

CSA performs inter-procedural path-sensitive analysis in the boundary of one translation unit. It means that it analyses many possible paths in the function one at a time, also looking into called functions. Therefore it could detect problems that arise only in specific scenarios (on a particular path) and track inter-procedural dependencies.

Checkers

Provenance Source Checker

Consider a binary arithmetic C-expression with operands of type intptr_t. The result of this expression is a capability that should be derived according to the operator’s semantics from one of the sides of the expression. Unless one of the arguments is a cast from a non-capability (integer) type, the compiler will not know which side should the resulting capability be derived from and will emit a warning. To fix this warning, one should explicitly tell the compiler what side to pick by casting the other argument to a non-capability type. For more details, see §6.2 of CHERI C/C++ Programming Guide [1].

Provenance Source Checker is designed to help with resolving such warnings. It tracks integers and pointers stored as (u)intptr_t type and then ,at the binary operation with “ambiguous provenance”, tells which side could be a valid capability on the considered path. For example, consider a code snippet from the compiler-rt project below.

static uintptr_t readEncodedPointer(const uint8_t **data, uint8_t encoding) {
  ...
  uintptr_t result = 0;
  switch (encoding & 0x0F) {
  case DW_EH_PE_sdata8:
    // Warning note:
    // NULL-derived capability: implicit cast from 'int64_t'
    // to 'unsigned __intcap __attribute__((cheri_no_provenance))'
    result = *((const int64_t *)p); 
  }
  ...
  return result;
}

uintptr_t funcStart = // ...
uintptr_t landingPad = readEncodedPointer(&p, callSiteEncoding);

// Warning message from CSA:
// 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, RHS was derived from NULL
_Unwind_SetIP(context, (funcStart + landingPad));

Ambiguous provenance warning in newlib

As long as funcStart and landingPad variables have type uintptr_t, the compiler will emit a warning for funcStart + landingPad expression. CSA can additionally track the origin of the values of those variables, and it was able to see inside readEncodedPointer function, therefore suggested that landingPad variable may hold a NULL-derived capability. During porting of this project, the type of this variable was changed to size_t.

 

Additionally, Provenance Source Checker fires a warning when the (u)intptr_t value obtained from the ambiguous-provenance operation is cast to the pointer type and also reports NULL-derived (u)intptr_t capabilities that are being cast to the pointer type. See the warning emitted by this checker from the newlib library below.

BUFHEAD *bp;
...
// Warning message:
// Invalid capability is used as pointer
segp[segment_ndx] = 
    // Warning note:
    // Result of '|' is a NULL-derived capability
    (BUFHEAD *)((ptrdiff_t)bp | (intptr_t)is_disk_mask);

Invalid capability warning in newlib

Variable bp here was cast to the non-capability type ptrdiff_t, therefore the result of the (ptrdiff_t)bp | (intptr_t)is_disk_mask expression is a NULL-derived capability, that is later used as a pointer. During porting of this project,  (ptrdiff_t) cast was replaces with (intptr_t) cast.

Capability Copy Checker

Whenever there is a need to copy or move (swap) a capability, it must be copied as a whole, otherwise, the copy will lose the tag and will not be a valid capability. Therefore, any routines that could potentially move around capabilities (memcpy, realloc, qsort, etc.) should be aware of this requirement. See §4.2 of CHERI C/C++ Programming Guide [1] for more details.

Capability Copy Checker is aimed to detect functions that move around arbitrary data in a way that could potentially result in a tag-stripping capability copying. For example, an original implementation of memcpy function in the newlib would copy capabilities by long-sized chunks, which could lead to having an invalid capability in dst. Capability Copy Checker reports such issues.

#define UNALIGNED(X, Y) \
  (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))

#define BIGBLOCKSIZE    (sizeof (long) << 2)
void * memcpy (void *dst0, const void *src0, size_t len0) {
  // Warning note:
  // void* argument may be a pointer to capability
  char *dst = dst0;const char *src = src0;
  if (len0 >= BIGBLOCKSIZE && !UNALIGNED (src, dst)) {
    long *aligned_dst = (long*)dst;
    long *aligned_src = (long*)src;
    while (len0 >= BIGBLOCKSIZE) {
      // Warning message:
      // Tag-stripping store of a capability
      *aligned_dst++ = *aligned_src++;
      *aligned_dst++ = *aligned_src++;
      *aligned_dst++ = *aligned_src++;
      *aligned_dst++ = *aligned_src++;
      len0 -= BIGBLOCKSIZE;
    }
  }
  return dst0;
}

Tag-stripping capability copy warning in newlib

Using the analyzer

Source code and instructions on how to build and run the analyzer can be found in GitHub repo.

 

Links

[2] Clang Static Analyzer

css.php

Report this page

To report inappropriate content on this page, please use the form below. Upon receiving your report, we will be in touch as per the Take Down Policy of the service.

Please note that personal data collected through this form is used and stored for the purposes of processing this report and communication with you.

If you are unable to report a concern about content via this form please contact the Service Owner.

Please enter an email address you wish to be contacted on. Please describe the unacceptable content in sufficient detail to allow us to locate it, and why you consider it to be unacceptable.
By submitting this report, you accept that it is accurate and that fraudulent or nuisance complaints may result in action by the University.

  Cancel