KEMBAR78
Control Flow Integrity
the Chromium logo

The Chromium Projects

Control Flow Integrity

We are planning to deploy Clang's control flow integrity mechanisms in Chrome.

The current status:

  • CFI for virtual calls is enabled for the official Chrome on Linux x86-64 (M54 and newer).
  • CFI for indirect (C-style) calls is enabled for the official Chrome on Linux x86-64 (M68 and newer).
  • Chrome is bad-cast clean, and we have a bot on chromium.memory that keeps it that way
  • We're working on additional compiler improvements to allow deploying CFI on more platforms.

To build Chrome with control flow integrity for virtual calls, indirect calls, and bad casts (Linux x86_64 only):

gn gen out/cfi '--args=is_debug=false is_cfi=true use_cfi_icall=true use_cfi_cast=true use_thin_lto=true' --check**

ninja -C out/cfi chrome # Chrome will take 6 minutes or so to link.

Building with additional diagnostics:

gn gen out/cfi-diag '--args=is_debug=false is_cfi=true use_cfi_icall=true use_cfi_cast=true use_cfi_diag=true use_thin_lto=true' --check

ninja -C out/cfi-diag chrome # Chrome will take 6 minutes or so to link.

The deployment is being tracked here:

Meta bug: crbug.com/701937

Linux: crbug.com/464797

Android: crbug.com/469376

ChromeOS: crbug.com/537386

Diagnosing problems with the CFI instrumentation

By default, a program compiled with CFI will crash with SIGILL if it detects a CFI violation.

For better error messages (but not for production use) add use_cfi_diag=true to your args.gn

Indirect call failures

CFI indirect call (cfi-icall) failures are primarily caused by either bad functions casts or dynamically resolved function pointers:

  • CFI-icall checks that a function pointer points to a function matching the function pointer type. Casting function pointers breaks that check and such function pointer casts should be eliminated. Third party libraries that make significant use of such casts to change pointer types may potentially be resolved using type generalization, like so.
  • CFI-icall function pointer checks are optimized to execute quickly at the expense of not being able to check dynamically resolved function pointers, e.g. pointers resolved through the use of dlsym() or GetProcAddress(). In order to provide a security guarantee similar to CFI-icall for dynamically resolved function pointers, e.g. that the pointer can not be maliciously modified to an arbitrary pointer, the pointer can be placed in read-only memory (base::ProtectedMemory) and be called without cfi-icall checking (base::UnsanitizedCfiCall), like so.

Overhead (only tested on x64)

  • CPU overhead is < 1%

  • Code size overhead is 5%-9%

  • RAM overhead is a small constant (read-only tables inside the binary shared between all chrome processes)

Trophies (bugs found or prevented)