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

Enable Control Flow Guard in rustbuild #68824

Merged
merged 1 commit into from
Feb 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -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
#
Expand Down
14 changes: 14 additions & 0 deletions src/bootstrap/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
ajpaverd marked this conversation as resolved.
Show resolved Hide resolved
// 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());

Expand Down
3 changes: 3 additions & 0 deletions src/bootstrap/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down Expand Up @@ -332,6 +333,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.
Expand Down Expand Up @@ -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 =
Expand Down
1 change: 1 addition & 0 deletions src/bootstrap/configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def v(*args):
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")
Expand Down
34 changes: 34 additions & 0 deletions src/doc/unstable-book/src/compiler-flags/control-flow-guard.md
Original file line number Diff line number Diff line change
@@ -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.