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-guardargs. 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_guardinto a target feature, such that it ends up inCARGO_TARGET_FEATURES?