about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--config.toml.example4
-rw-r--r--src/bootstrap/builder.rs14
-rw-r--r--src/bootstrap/config.rs3
-rwxr-xr-xsrc/bootstrap/configure.py1
-rw-r--r--src/doc/unstable-book/src/compiler-flags/control-flow-guard.md34
5 files changed, 56 insertions, 0 deletions
diff --git a/config.toml.example b/config.toml.example
index c37cd4a9857..9b7327ea69e 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -444,6 +444,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 d0eed3f12d1..e4b57cddfb8 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1135,6 +1135,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 ac530da3557..214d572329e 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -116,6 +116,7 @@ pub struct Config {
     pub targets: Vec<Interned<String>>,
     pub local_rebuild: bool,
     pub jemalloc: bool,
+    pub control_flow_guard: bool,
 
     // dist misc
     pub dist_sign_folder: Option<PathBuf>,
@@ -333,6 +334,7 @@ struct Rust {
     jemalloc: Option<bool>,
     test_compare_mode: Option<bool>,
     llvm_libunwind: Option<bool>,
+    control_flow_guard: Option<bool>,
 }
 
 /// TOML representation of how each build target is configured.
@@ -580,6 +582,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.