From 87df124ba77a2ce64e11782bddeadae85d26603d Mon Sep 17 00:00:00 2001 From: Andrew Paverd Date: Tue, 28 Jan 2020 14:29:44 +0000 Subject: [PATCH] Enable Control Flow Guard in rustbuild --- config.toml.example | 4 +++ src/bootstrap/builder.rs | 14 ++++++++ src/bootstrap/config.rs | 3 ++ src/bootstrap/configure.py | 1 + .../src/compiler-flags/control-flow-guard.md | 34 +++++++++++++++++++ 5 files changed, 56 insertions(+) create mode 100644 src/doc/unstable-book/src/compiler-flags/control-flow-guard.md diff --git a/config.toml.example b/config.toml.example index c9e17337ee2..b4e3b3e5e67 100644 --- a/config.toml.example +++ b/config.toml.example @@ -435,6 +435,10 @@ # Use LLVM libunwind as the implementation for Rust's unwinder. #llvm-libunwind = false +# Enable Windows Control Flow Guard checks in the standard library. +# This only applies from stage 1 onwards, and only for Windows targets. +#control-flow-guard = false + # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index d9c894aa9c6..0737d017df2 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1111,6 +1111,20 @@ impl<'a> Builder<'a> { ); } + // If Control Flow Guard is enabled, pass the `control_flow_guard=checks` flag to rustc + // when compiling the standard library, since this might be linked into the final outputs + // produced by rustc. Since this mitigation is only available on Windows, only enable it + // for the standard library in case the compiler is run on a non-Windows platform. + // This is not needed for stage 0 artifacts because these will only be used for building + // the stage 1 compiler. + if cfg!(windows) + && mode == Mode::Std + && self.config.control_flow_guard + && compiler.stage >= 1 + { + rustflags.arg("-Zcontrol_flow_guard=checks"); + } + // For `cargo doc` invocations, make rustdoc print the Rust version into the docs cargo.env("RUSTDOC_CRATE_VERSION", self.rust_version()); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 110c8b844d5..d376d9664e0 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -116,6 +116,7 @@ pub struct Config { pub targets: Vec>, pub local_rebuild: bool, pub jemalloc: bool, + pub control_flow_guard: bool, // dist misc pub dist_sign_folder: Option, @@ -332,6 +333,7 @@ struct Rust { jemalloc: Option, test_compare_mode: Option, llvm_libunwind: Option, + control_flow_guard: Option, } /// TOML representation of how each build target is configured. @@ -578,6 +580,7 @@ impl Config { set(&mut config.rust_verify_llvm_ir, rust.verify_llvm_ir); config.rust_thin_lto_import_instr_limit = rust.thin_lto_import_instr_limit; set(&mut config.rust_remap_debuginfo, rust.remap_debuginfo); + set(&mut config.control_flow_guard, rust.control_flow_guard); if let Some(ref backends) = rust.codegen_backends { config.rust_codegen_backends = diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 7cfc5385e21..1fdd5d13e7f 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -60,6 +60,7 @@ o("lld", "rust.lld", "build lld") o("lldb", "rust.lldb", "build lldb") o("missing-tools", "dist.missing-tools", "allow failures when building tools") o("use-libcxx", "llvm.use-libcxx", "build LLVM with libc++") +o("control-flow-guard", "rust.control-flow-guard", "Enable Control Flow Guard") o("cflags", "llvm.cflags", "build LLVM with these extra compiler flags") o("cxxflags", "llvm.cxxflags", "build LLVM with these extra compiler flags") diff --git a/src/doc/unstable-book/src/compiler-flags/control-flow-guard.md b/src/doc/unstable-book/src/compiler-flags/control-flow-guard.md new file mode 100644 index 00000000000..f871df46250 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/control-flow-guard.md @@ -0,0 +1,34 @@ +# `control_flow_guard` + +The tracking issue for this feature is: [#68793](https://github.com/rust-lang/rust/issues/68793). + +------------------------ + +The `-Zcontrol_flow_guard=checks` compiler flag enables the Windows [Control Flow Guard][cfguard-docs] platform security feature. When enabled, the compiler outputs a list of valid indirect call targets, and inserts runtime checks on all indirect jump instructions to ensure that the destination is in the list of valid call targets. + +[cfguard-docs]: https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard + +For testing purposes, the `-Zcontrol_flow_guard=nochecks` compiler flag can be used to emit only the list of valid call targets, but not the runtime checks. + +It is strongly recommended to also enable Control Flow Guard checks in all linked libraries, including the standard library. + +To enable Control Flow Guard in the standard library, you can use the [cargo `-Zbuild-std` functionality][build-std] to recompile the standard library with the same configuration options as the main program. + +[build-std]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std + +For example: +```cmd +rustup toolchain install --force nightly +rustup component add rust-src +SET RUSTFLAGS=-Zcontrol_flow_guard=checks +cargo +nightly build -Z build-std --target x86_64-pc-windows-msvc +``` + +```PowerShell +rustup toolchain install --force nightly +rustup component add rust-src +$Env:RUSTFLAGS = "-Zcontrol_flow_guard=checks" +cargo +nightly build -Z build-std --target x86_64-pc-windows-msvc +``` + +Alternatively, if you are building the standard library from source, you can set `control-flow-guard = true` in the config.toml file.