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).
  • 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:

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

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)

- - invalid cast in ProcessManagerBrowserTest.NestedURLNavigationsToAppBlocked - invalid cast in blink::BytesConsumerTestUtil::TwoPhaseReader - invalid cast in SkTArray.h - invalid cast in PaymentRequestTest.NullShippingOptionWhenNoOptionsAvailable - HeapVector::operator= is deleting garbage collected elements
- - improper deserialization of cc::HeadsUpDisplayLayer
- - invalid cast in AutofillDialogControllerTest
- - invalid cast in CachingCorrectnessTest.ReuseImageExpiredFromExpires
- - invalid cast in AnimationTranslationUtilTest.filtersWork
- - invalid cast in TileManagerPerfTest.PrepareTiles
- - invalid cast in
- - invalid cast in cdm_wrapper
- - Bad-cast to blink::HTMLOptionElement from blink::HTMLOptGroupElement
- - Bad-cast to webrtc::ProcessThreadImpl from invalid vptr;
- - invalid cast in SafeBrowsingService::GetProtocolManagerDelegate
- - invalid cast in browser_plugin_guest
- - invalid cast in AutofillDialogControllerTest - invalid cast in net/http/
- - invalid cast in ppapi/proxy/
- - Bad-cast to Profile from invalid vptr;
- - invalid cast in SkTextBlobBuilder::build
- - invalid cast in sfntly/port/refcount.h
- - invalid cast in HeapTest.VectorDestructorsWithVtable
- - invalid cast in blink::LifecycleNotifier
- - invalid cast in list_container.h
- - Bad-cast to icu_54::UnicodeSet from icu_54::Quantifier
- - Bad-cast to blink::ScriptWrappable from blink::WebGLRenderingContextBase::TypedExtensionTracker<blink::ANGLEInstancedArrays>
- - invalid cast in RenderFrameHostManagerTest
- - invalid cast in AutofillDialogControllerTest
- - Invalid cast in ppapi/proxy/
- - Invalid cast in / ToPumpIO
- - Invalid static_cast in ThreadLocalPointer::Get
- - invalid cast in ChromeLauncherControllerTest
- - invalid cast in content::TestWebContents::GetMainFrame
- - invalid cast in NavigatorTestWithBrowserSideNavigation
- - Invalid cast in AppCacheHost::AddUpdateObserver
- - Invalid cast in SkTArray.h
- - invalid cast in GrTRecorder.h
- - Invalid cast in v8::internal::compiler::Typer::Visitor::Reduce
- - Invalid cast in SocketsTcpUnitTest
- - Invalid cast in FeedbackUploaderTest
- - Bad cast in KeyedServiceBaseFactory
- - Invalid cast Event -> CancelModeEvent for NonCancelableEvent
- - Invalid cast Task -> RasterTask in
- - Bad-cast to blink::ScriptWrappable from blink::WorkerWebSocketChannel;DOMWrapperMap.h
- - CHECK failed: io_thread_.StartWithOptions(thread_options) in - Invalid cast in TabDesktopMediaListTest

Subpages (1): Overhead