With Rust 1.47, the Rust flag -C control-flow-guard
has been stabilized, mitigating potential memory vulnerabilities in unsafe Rust by utilizing windows' Control Flow Guard mechanism to ensure a memory corruption doesn't subvert control flow.
While most rust code is protected by this mechanism, a lot of Rust program still link to non-Rust, C/C++ code. This is often done through build script that compile C code through the cc
crate. Examples include ring, sqlite, and many others. This code won't, by default, be protected by Control Flow Guard. In order for this code to also be protected, one must pass /guard:cf
to the C compiler. This can be done today by setting the CFLAGS=/guard:cf
environment variable before running cargo build
.
This is, however, suboptimal. It requires setting a variable outside of the normal cargo mechanisms in order to ensure the code will be properly protected. It's error prone. Ideally, build scripts should be able to observe the current state of the control-flow-guard
flag, and automatically inject the appropriate compiler flag to their compiler when building code. For instance, cc-rs
could check if control-flow-guard
is enabled and automatically add /guard:cf
when invoking the MSVC compiler. See https://github.com/alexcrichton/cc-rs/issues/557
The problem then becomes how to detect the current state of the control-flow-guard
flag. Right now, I believe there is no simple way of getting its state. It can be enabled in a myriad of ways (RUSTFLAGS
, .cargo/config
, cargo rustc
arguments...). I can see a few ways of enabling build scripts to check its state:
- Expose the final RUSTFLAGS to build script, let them parse it to find the
control-flow-guard
args. This could be useful for other purposes. - Add some kind of
cfg(control_flow_guard)
when rustflags is enabled, which would get populated inCARGO_CFG_*
. - Make
control_flow_guard
into a target feature, such that it ends up inCARGO_TARGET_FEATURES
?