Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Control Flow Guard (CFG/CFGuard) on Windows #301

Closed
alvinhochun opened this issue Aug 19, 2022 · 2 comments · Fixed by #304
Closed

Support Control Flow Guard (CFG/CFGuard) on Windows #301

alvinhochun opened this issue Aug 19, 2022 · 2 comments · Fixed by #304

Comments

@alvinhochun
Copy link
Contributor

Control Flow Guard is a security mitigation that verifies the
target address of indirect calls. It works by having the compiler insert
instrumentation code at indirect call sites, and also the linker write the
necessary data and flags into the PE/COFF image to enable the feature on
Windows' end.

Existing Support in LLVM

In LLVM, Clang already knows how to insert the CFGuard instrumentation code
and LLD is able to produce CFGuard data, like how MSVC does it. 1 2
Conveniently, these work the same when targeting mingw-w64 given the proper
compiler and linker flags. They however assume certain symbols to be available
in order to work, and mingw-w64 does not provide them yet. For example, if
you try to compile a source file into an x86_64 EXE with -Xclang -cfguard,
you may get this:

ld.lld: error: undefined symbol: __guard_dispatch_icall_fptr

To be compatible with MSVC, Clang expects the symbol __guard_dispatch_icall_fptr
on x86_64, and __guard_check_icall_fptr on x86, arm and aarch64. In addition,
LLD uses the contents of the _load_config_used symbol as the load config
directory, which contains CFGuard support flags and data pointers.

Using with mingw-w64

If we are fine with reusing these existing support in LLVM as-is, here is
what we need to do:

  • Add the symbols __guard_check_icall_fptr and __guard_dispatch_icall_fptr
    along with the corresponding placeholder functions (to be used when running
    with CFGuard disabled or unavailable).
  • Provide a default _load_config_used data structure which LLD will use
    as the load config directory, and fill its fields with the LLD-provided
    symbols needed for CFGuard.
  • Compile all included libraries (e.g. mingw-w64-*, compiler-rt, libc++)
    with CFGuard enabled. This means adding -Xclang -cfguard to compile flags
    and -Wl,-Xlink,-guard:cf to link flags.

Users will still need to opt into enabling CFGuard by passing the same compile
flags and link flags. For users who does not enable CFGuard, this setup does
add a small amount of bloat:

  • Every indirect calls in the included libraries get an overhead of several
    instructions and a far call.
  • All images linked with LLD will include the default load config directory,
    which may add a couple hundred bytes to the image.

What About GCC and Binutils?

As far as I can tell, there is zero support for CFGuard in GCC and Binutils.
These changes should not affect a GCC-based mingw-w64 toolchain.

@alvinhochun
Copy link
Contributor Author

I have mentioned on IRC that I am experimenting with this. Here are my current changes:

mingw-w64/mingw-w64@master...alvinhochun:mingw-w64:alvin/cfguard
master...alvinhochun:llvm-mingw:alvin/cfguard

@alvinhochun
Copy link
Contributor Author

Documented some of the stuff here: https://gist.github.com/alvinhochun/a65e4177e2b34d551d7ecb02b55a4b0a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant