Skip to content

Commit c9ba734

Browse files
authored
Unrolled build for rust-lang#118013
Rollup merge of rust-lang#118013 - sivadeilra:user/ardavis/ehcont, r=wesleywiser Enable Rust to use the EHCont security feature of Windows In the future Windows will enable Control-flow Enforcement Technology (CET aka Shadow Stacks). To protect the path where the context is updated during exception handling, the binary is required to enumerate valid unwind entrypoints in a dedicated section which is validated when the context is being set during exception handling. The required support for EHCONT Guard has already been merged into LLVM, long ago. This change simply adds the Rust codegen option to enable it. Relevant LLVM change: https://reviews.llvm.org/D40223 This also adds a new `ehcont-guard` option to the bootstrap config which enables EHCont Guard when building std. We at Microsoft have been using this feature for a significant period of time; we are confident that the LLVM feature, when enabled, generates well-formed code. We currently enable EHCONT using a codegen feature, but I'm certainly open to refactoring this to be a target feature instead, or to use any appropriate mechanism to enable it.
2 parents 6d2b84b + 80896cb commit c9ba734

File tree

10 files changed

+76
-1
lines changed

10 files changed

+76
-1
lines changed

compiler/rustc_codegen_llvm/src/context.rs

+10
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,16 @@ pub unsafe fn create_module<'ll>(
351351
);
352352
}
353353

354+
// Set module flag to enable Windows EHCont Guard (/guard:ehcont).
355+
if sess.opts.unstable_opts.ehcont_guard {
356+
llvm::LLVMRustAddModuleFlag(
357+
llmod,
358+
llvm::LLVMModFlagBehavior::Warning,
359+
"ehcontguard\0".as_ptr() as *const _,
360+
1,
361+
)
362+
}
363+
354364
// Insert `llvm.ident` metadata.
355365
//
356366
// On the wasm targets it will get hooked up to the "producer" sections

compiler/rustc_codegen_ssa/src/back/link.rs

+5
Original file line numberDiff line numberDiff line change
@@ -2378,6 +2378,11 @@ fn add_order_independent_options(
23782378
cmd.control_flow_guard();
23792379
}
23802380

2381+
// OBJECT-FILES-NO, AUDIT-ORDER
2382+
if sess.opts.unstable_opts.ehcont_guard {
2383+
cmd.ehcont_guard();
2384+
}
2385+
23812386
add_rpath_args(cmd, sess, codegen_results, out_filename);
23822387
}
23832388

compiler/rustc_codegen_ssa/src/back/linker.rs

+21
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ pub trait Linker {
185185
fn optimize(&mut self);
186186
fn pgo_gen(&mut self);
187187
fn control_flow_guard(&mut self);
188+
fn ehcont_guard(&mut self);
188189
fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]);
189190
fn no_crt_objects(&mut self);
190191
fn no_default_libraries(&mut self);
@@ -605,6 +606,8 @@ impl<'a> Linker for GccLinker<'a> {
605606

606607
fn control_flow_guard(&mut self) {}
607608

609+
fn ehcont_guard(&mut self) {}
610+
608611
fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
609612
// MacOS linker doesn't support stripping symbols directly anymore.
610613
if self.sess.target.is_like_osx {
@@ -914,6 +917,12 @@ impl<'a> Linker for MsvcLinker<'a> {
914917
self.cmd.arg("/guard:cf");
915918
}
916919

920+
fn ehcont_guard(&mut self) {
921+
if self.sess.target.pointer_width == 64 {
922+
self.cmd.arg("/guard:ehcont");
923+
}
924+
}
925+
917926
fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]) {
918927
match strip {
919928
Strip::None => {
@@ -1127,6 +1136,8 @@ impl<'a> Linker for EmLinker<'a> {
11271136

11281137
fn control_flow_guard(&mut self) {}
11291138

1139+
fn ehcont_guard(&mut self) {}
1140+
11301141
fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
11311142
// Preserve names or generate source maps depending on debug info
11321143
// For more information see https://emscripten.org/docs/tools_reference/emcc.html#emcc-g
@@ -1319,6 +1330,8 @@ impl<'a> Linker for WasmLd<'a> {
13191330

13201331
fn control_flow_guard(&mut self) {}
13211332

1333+
fn ehcont_guard(&mut self) {}
1334+
13221335
fn no_crt_objects(&mut self) {}
13231336

13241337
fn no_default_libraries(&mut self) {}
@@ -1472,6 +1485,8 @@ impl<'a> Linker for L4Bender<'a> {
14721485

14731486
fn control_flow_guard(&mut self) {}
14741487

1488+
fn ehcont_guard(&mut self) {}
1489+
14751490
fn no_crt_objects(&mut self) {}
14761491
}
14771492

@@ -1613,6 +1628,8 @@ impl<'a> Linker for AixLinker<'a> {
16131628

16141629
fn control_flow_guard(&mut self) {}
16151630

1631+
fn ehcont_guard(&mut self) {}
1632+
16161633
fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
16171634
match strip {
16181635
Strip::None => {}
@@ -1835,6 +1852,8 @@ impl<'a> Linker for PtxLinker<'a> {
18351852

18361853
fn control_flow_guard(&mut self) {}
18371854

1855+
fn ehcont_guard(&mut self) {}
1856+
18381857
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {}
18391858

18401859
fn subsystem(&mut self, _subsystem: &str) {}
@@ -1931,6 +1950,8 @@ impl<'a> Linker for BpfLinker<'a> {
19311950

19321951
fn control_flow_guard(&mut self) {}
19331952

1953+
fn ehcont_guard(&mut self) {}
1954+
19341955
fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
19351956
let path = tmpdir.join("symbols");
19361957
let res: io::Result<()> = try {

compiler/rustc_session/src/options.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1582,6 +1582,8 @@ options! {
15821582
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
15831583
dylib_lto: bool = (false, parse_bool, [UNTRACKED],
15841584
"enables LTO for dylib crate type"),
1585+
ehcont_guard: bool = (false, parse_bool, [TRACKED],
1586+
"generate Windows EHCont Guard tables"),
15851587
emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
15861588
"emit a section containing stack size metadata (default: no)"),
15871589
emit_thin_lto: bool = (true, parse_bool, [TRACKED],

config.example.toml

+4
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,10 @@ change-id = 116881
686686
# This only applies from stage 1 onwards, and only for Windows targets.
687687
#control-flow-guard = false
688688

689+
# Enable Windows EHCont Guard checks in the standard library.
690+
# This only applies from stage 1 onwards, and only for Windows targets.
691+
#ehcont-guard = false
692+
689693
# Enable symbol-mangling-version v0. This can be helpful when profiling rustc,
690694
# as generics will be preserved in symbols (rather than erased into opaque T).
691695
# When no setting is given, the new scheme will be used when compiling the

src/bootstrap/src/core/builder.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1964,6 +1964,16 @@ impl<'a> Builder<'a> {
19641964
rustflags.arg("-Ccontrol-flow-guard");
19651965
}
19661966

1967+
// If EHCont Guard is enabled, pass the `-Zehcont-guard` flag to rustc when compiling the
1968+
// standard library, since this might be linked into the final outputs produced by rustc.
1969+
// Since this mitigation is only available on Windows, only enable it for the standard
1970+
// library in case the compiler is run on a non-Windows platform.
1971+
// This is not needed for stage 0 artifacts because these will only be used for building
1972+
// the stage 1 compiler.
1973+
if cfg!(windows) && mode == Mode::Std && self.config.ehcont_guard && compiler.stage >= 1 {
1974+
rustflags.arg("-Zehcont-guard");
1975+
}
1976+
19671977
// For `cargo doc` invocations, make rustdoc print the Rust version into the docs
19681978
// This replaces spaces with tabs because RUSTDOCFLAGS does not
19691979
// support arguments with regular spaces. Hopefully someday Cargo will

src/bootstrap/src/core/config/config.rs

+3
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ pub struct Config {
248248
pub local_rebuild: bool,
249249
pub jemalloc: bool,
250250
pub control_flow_guard: bool,
251+
pub ehcont_guard: bool,
251252

252253
// dist misc
253254
pub dist_sign_folder: Option<PathBuf>,
@@ -1019,6 +1020,7 @@ define_config! {
10191020
test_compare_mode: Option<bool> = "test-compare-mode",
10201021
llvm_libunwind: Option<String> = "llvm-libunwind",
10211022
control_flow_guard: Option<bool> = "control-flow-guard",
1023+
ehcont_guard: Option<bool> = "ehcont-guard",
10221024
new_symbol_mangling: Option<bool> = "new-symbol-mangling",
10231025
profile_generate: Option<String> = "profile-generate",
10241026
profile_use: Option<String> = "profile-use",
@@ -1452,6 +1454,7 @@ impl Config {
14521454
config.rust_thin_lto_import_instr_limit = rust.thin_lto_import_instr_limit;
14531455
set(&mut config.rust_remap_debuginfo, rust.remap_debuginfo);
14541456
set(&mut config.control_flow_guard, rust.control_flow_guard);
1457+
set(&mut config.ehcont_guard, rust.ehcont_guard);
14551458
config.llvm_libunwind_default = rust
14561459
.llvm_libunwind
14571460
.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"));

src/bootstrap/src/tests/builder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::*;
2-
use crate::core::config::{Config, DryRun, TargetSelection};
32
use crate::core::build_steps::doc::DocumentationFormat;
3+
use crate::core::config::{Config, DryRun, TargetSelection};
44
use std::thread;
55

66
fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {

tests/codegen/ehcontguard_disabled.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// compile-flags:
2+
3+
#![crate_type = "lib"]
4+
5+
// A basic test function.
6+
pub fn test() {
7+
}
8+
9+
// Ensure the module flag ehcontguard is not present
10+
// CHECK-NOT: !"ehcontguard"

tests/codegen/ehcontguard_enabled.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// compile-flags: -Z ehcont-guard
2+
3+
#![crate_type = "lib"]
4+
5+
// A basic test function.
6+
pub fn test() {
7+
}
8+
9+
// Ensure the module flag ehcontguard=1 is present
10+
// CHECK: !"ehcontguard", i32 1

0 commit comments

Comments
 (0)