diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index d2fb65b5d4f8e..3132e29f32be1 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -626,6 +626,7 @@ fn test_codegen_options_tracking_hash() { tracked!(relocation_model, Some(RelocModel::Pic)); tracked!(soft_float, true); tracked!(split_debuginfo, Some(SplitDebuginfo::Packed)); + tracked!(stack_protector, StackProtector::All); tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0)); tracked!(target_cpu, Some(String::from("abc"))); tracked!(target_feature, String::from("all the features, all of them")); @@ -837,7 +838,6 @@ fn test_unstable_options_tracking_hash() { tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc"))); tracked!(split_lto_unit, Some(true)); tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1)); - tracked!(stack_protector, StackProtector::All); tracked!(teach, true); tracked!(thinlto, Some(true)); tracked!(tiny_const_eval_limit, true); diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index b8dacc6968d30..717a02c21c336 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -109,7 +109,7 @@ session_split_lto_unit_requires_lto = `-Zsplit-lto-unit` requires `-Clto`, `-Clt session_target_requires_unwind_tables = target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no` -session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored +session_target_stack_protector_not_supported = `-C stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored session_unleashed_feature_help_named = skipping check for `{$gate}` feature session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 7aca86f7169d7..e70c94e971f94 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -19,7 +19,7 @@ use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_ST use rustc_span::source_map::FilePathMapping; use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm}; use rustc_target::spec::{LinkSelfContainedComponents, LinkerFeatures}; -use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple}; +use rustc_target::spec::{SplitDebuginfo, StackProtector, Target, TargetTriple}; use std::collections::btree_map::{ Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter, }; @@ -2390,6 +2390,22 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M } } + // Check for unstable values of `-C stack-protector`. + // This is what prevents them from being used on stable compilers. + match cg.stack_protector { + // Stable values: + StackProtector::All | StackProtector::None => {} + // Unstable values: + StackProtector::Basic | StackProtector::Strong => { + if !unstable_opts.unstable_options { + early_dcx.early_fatal( + "`-C stack-protector=basic` and `-C stack-protector=strong` \ + require `-Z unstable-options`", + ); + } + } + } + if cg.instrument_coverage != InstrumentCoverage::No { if cg.profile_generate.enabled() || cg.profile_use.is_some() { early_dcx.early_fatal( diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 963c9558c170c..72c130ba4b217 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1545,6 +1545,9 @@ options! { #[rustc_lint_opt_deny_field_access("use `Session::split_debuginfo` instead of this field")] split_debuginfo: Option = (None, parse_split_debuginfo, [TRACKED], "how to handle split-debuginfo, a platform-specific option"), + #[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")] + stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED], + "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), symbol_mangling_version: Option = (None, @@ -1951,9 +1954,6 @@ written to standard error output)"), "enable LTO unit splitting (default: no)"), src_hash_algorithm: Option = (None, parse_src_file_hash, [TRACKED], "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"), - #[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")] - stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED], - "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"), staticlib_allow_rdylib_deps: bool = (false, parse_bool, [TRACKED], "allow staticlibs to have rust dylib dependencies"), staticlib_prefer_dynamic: bool = (false, parse_bool, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 22ca8a3cf3ec2..7358f4433f67d 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -764,7 +764,7 @@ impl Session { pub fn stack_protector(&self) -> StackProtector { if self.target.options.supports_stack_protector { - self.opts.unstable_opts.stack_protector + self.opts.cg.stack_protector } else { StackProtector::None } @@ -1273,10 +1273,10 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } } - if sess.opts.unstable_opts.stack_protector != StackProtector::None { + if sess.opts.cg.stack_protector != StackProtector::None { if !sess.target.options.supports_stack_protector { sess.dcx().emit_warn(errors::StackProtectorNotSupportedForTarget { - stack_protector: sess.opts.unstable_opts.stack_protector, + stack_protector: sess.opts.cg.stack_protector, target_triple: &sess.opts.target_triple, }); } diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index c8f5d64957030..ff3b461287a1c 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -541,6 +541,26 @@ Note that all three options are supported on Linux and Apple platforms, Attempting to use an unsupported option requires using the nightly channel with the `-Z unstable-options` flag. +## stack-protector + +The option `-C stack-protector=val` controls stack smashing protection. See [Stack smashing +protection][stack-smashing] for more details. + +Supported values for this option are: + +- `none` - no stack protectors +- `all` - force use of stack protectors for all functions + +Unstable options for this value are: + +- `basic` - enable stack protectors for functions potentially vulnerable to stack smashing (basic + heuristic) +- `strong` - enable stack protectors for functions potentially vulnerable to stack smashing (strong + heuristic) + +`basic` and `strong` values for `-C stack-protector` require using the nightly channel with the +`-Z unstable-options` flag. + ## strip The option `-C strip=val` controls stripping of debuginfo and similar auxiliary @@ -642,3 +662,4 @@ effective only for x86 targets. [instrumentation-based code coverage]: ../instrument-coverage.md [profile-guided optimization]: ../profile-guided-optimization.md [option-g-debug]: ../command-line-arguments.md#option-g-debug +[stack-smashing]: ../exploit-mitigations.md#stack-smashing-protection diff --git a/src/doc/rustc/src/exploit-mitigations.md b/src/doc/rustc/src/exploit-mitigations.md index d4e2fc52e973f..4407680cc5f8f 100644 --- a/src/doc/rustc/src/exploit-mitigations.md +++ b/src/doc/rustc/src/exploit-mitigations.md @@ -63,7 +63,7 @@ equivalent. | Stack clashing protection | Yes | 1.20.0 (2017-08-31) | | Read-only relocations and immediate binding | Yes | 1.21.0 (2017-10-12) | | Heap corruption protection | Yes | 1.32.0 (2019-01-17) (via operating system default or specified allocator) | -| Stack smashing protection | Yes | Nightly | +| Stack smashing protection | Yes | 1.78.0 (2024-05-02) | | Forward-edge control flow protection | Yes | Nightly | | Backward-edge control flow protection (e.g., shadow and safe stack) | Yes | Nightly | @@ -357,7 +357,8 @@ instruction pointer, and checking if this value has changed when returning from a function. This is also known as “Stack Protector” or “Stack Smashing Protector (SSP)”. -The Rust compiler supports stack smashing protection on nightly builds[40]. +The Rust compiler supports stack smashing protection with the `-C stack-protector=all` +flag since version 1.78.0 (2024-05-02)[40], [47]. ![Screenshot of IDA Pro listing cross references to __stack_chk_fail in hello-rust.](images/image3.png "Cross references to __stack_chk_fail in hello-rust.") Fig. 14. IDA Pro listing cross references to `__stack_chk_fail` in hello-rust. @@ -627,3 +628,6 @@ to `READ_IMPLIES_EXEC`). 46. “SafeStack.” The Rust Unstable Book. [https://doc.rust-lang/org/unstable-book/compiler-flags/sanitizer.html#safestack](../unstable-book/compiler-flags/sanitizer.html#safestack). + +47. D. Wood. “sess: stabilize stack-protector=all #121742” GitHub. + diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs index 12339cb4415c6..b25a14791ce6a 100644 --- a/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs +++ b/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs @@ -3,10 +3,10 @@ //@ only-windows //@ only-msvc //@ ignore-64bit 64-bit table based SEH has slightly different behaviors than classic SEH -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic -//@ [none] compile-flags: -Z stack-protector=none +//@ [all] compile-flags: -C stack-protector=all +//@ [strong] compile-flags: -C stack-protector=strong -Z unstable-options +//@ [basic] compile-flags: -C stack-protector=basic -Z unstable-options +//@ [none] compile-flags: -C stack-protector=none //@ compile-flags: -C opt-level=2 -Z merge-functions=disabled #![crate_type = "lib"] diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs index 46c7751125197..143b7fdbf0bdd 100644 --- a/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs +++ b/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs @@ -3,10 +3,10 @@ //@ only-windows //@ only-msvc //@ ignore-32bit 64-bit table based SEH has slightly different behaviors than classic SEH -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic -//@ [none] compile-flags: -Z stack-protector=none +//@ [all] compile-flags: -C stack-protector=all +//@ [strong] compile-flags: -C stack-protector=strong -Z unstable-options +//@ [basic] compile-flags: -C stack-protector=basic -Z unstable-options +//@ [none] compile-flags: -C stack-protector=none //@ compile-flags: -C opt-level=2 -Z merge-functions=disabled #![crate_type = "lib"] diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs index e63adc88ff501..b8c296aff730b 100644 --- a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs +++ b/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs @@ -4,10 +4,10 @@ //@ ignore-msvc stack check code uses different function names //@ ignore-nvptx64 stack protector is not supported //@ ignore-wasm32-bare -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic -//@ [none] compile-flags: -Z stack-protector=none +//@ [all] compile-flags: -C stack-protector=all +//@ [strong] compile-flags: -C stack-protector=strong -Z unstable-options +//@ [basic] compile-flags: -C stack-protector=basic -Z unstable-options +//@ [none] compile-flags: -C stack-protector=none //@ compile-flags: -C opt-level=2 -Z merge-functions=disabled //@ min-llvm-version: 17.0.2 diff --git a/tests/assembly/stack-protector/stack-protector-target-support.rs b/tests/assembly/stack-protector/stack-protector-target-support.rs index 74a609dcdcc1c..6f935325028dd 100644 --- a/tests/assembly/stack-protector/stack-protector-target-support.rs +++ b/tests/assembly/stack-protector/stack-protector-target-support.rs @@ -175,7 +175,7 @@ //@ [r84] needs-llvm-components: x86 //@ [r85] compile-flags: --target x86_64-unknown-redox //@ [r85] needs-llvm-components: x86 -//@ compile-flags: -Z stack-protector=all +//@ compile-flags: -C stack-protector=all //@ compile-flags: -C opt-level=2 #![crate_type = "lib"] diff --git a/tests/codegen/stack-protector.rs b/tests/codegen/stack-protector.rs index 8ab25b470cda1..7c7561911a480 100644 --- a/tests/codegen/stack-protector.rs +++ b/tests/codegen/stack-protector.rs @@ -1,8 +1,8 @@ //@ revisions: all strong basic none //@ ignore-nvptx64 stack protector not supported -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic +//@ [all] compile-flags: -C stack-protector=all +//@ [strong] compile-flags: -C stack-protector=strong -Z unstable-options +//@ [basic] compile-flags: -C stack-protector=basic -Z unstable-options #![crate_type = "lib"] diff --git a/tests/ui/abi/stack-protector.rs b/tests/ui/abi/stack-protector.rs index 29332861977b7..a0a0fc5d8017a 100644 --- a/tests/ui/abi/stack-protector.rs +++ b/tests/ui/abi/stack-protector.rs @@ -1,7 +1,7 @@ //@ run-pass //@ only-x86_64-unknown-linux-gnu //@ revisions: ssp no-ssp -//@ [ssp] compile-flags: -Z stack-protector=all +//@ [ssp] compile-flags: -C stack-protector=all //@ compile-flags: -C opt-level=2 //@ compile-flags: -g diff --git a/tests/ui/stack-protector/stack-protector-unstable.basic.stderr b/tests/ui/stack-protector/stack-protector-unstable.basic.stderr new file mode 100644 index 0000000000000..dd8fcdb21e109 --- /dev/null +++ b/tests/ui/stack-protector/stack-protector-unstable.basic.stderr @@ -0,0 +1,2 @@ +error: `-C stack-protector=basic` and `-C stack-protector=strong` require `-Z unstable-options` + diff --git a/tests/ui/stack-protector/stack-protector-unstable.rs b/tests/ui/stack-protector/stack-protector-unstable.rs new file mode 100644 index 0000000000000..be1c31ea50e38 --- /dev/null +++ b/tests/ui/stack-protector/stack-protector-unstable.rs @@ -0,0 +1,25 @@ +//@ revisions: all strong strong-ok basic basic-ok +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ needs-llvm-components: x86 +//@ [all] check-pass +//@ [all] compile-flags: -C stack-protector=all +//@ [strong] check-fail +//@ [strong] compile-flags: -C stack-protector=strong +//@ [strong-ok] check-pass +//@ [strong-ok] compile-flags: -C stack-protector=strong -Z unstable-options +//@ [basic] check-fail +//@ [basic] compile-flags: -C stack-protector=basic +//@ [basic-ok] check-pass +//@ [basic-ok] compile-flags: -C stack-protector=basic -Z unstable-options + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +pub fn main(){} diff --git a/tests/ui/stack-protector/stack-protector-unstable.strong.stderr b/tests/ui/stack-protector/stack-protector-unstable.strong.stderr new file mode 100644 index 0000000000000..dd8fcdb21e109 --- /dev/null +++ b/tests/ui/stack-protector/stack-protector-unstable.strong.stderr @@ -0,0 +1,2 @@ +error: `-C stack-protector=basic` and `-C stack-protector=strong` require `-Z unstable-options` + diff --git a/tests/ui/stack-protector/warn-stack-protector-unsupported.all.stderr b/tests/ui/stack-protector/warn-stack-protector-unsupported.all.stderr index 54887715523c1..c196c344ecb5b 100644 --- a/tests/ui/stack-protector/warn-stack-protector-unsupported.all.stderr +++ b/tests/ui/stack-protector/warn-stack-protector-unsupported.all.stderr @@ -1,4 +1,4 @@ -warning: `-Z stack-protector=all` is not supported for target nvptx64-nvidia-cuda and will be ignored +warning: `-C stack-protector=all` is not supported for target nvptx64-nvidia-cuda and will be ignored warning: 1 warning emitted diff --git a/tests/ui/stack-protector/warn-stack-protector-unsupported.basic.stderr b/tests/ui/stack-protector/warn-stack-protector-unsupported.basic.stderr index f7a1ee39fb9af..04b9ca06b5eea 100644 --- a/tests/ui/stack-protector/warn-stack-protector-unsupported.basic.stderr +++ b/tests/ui/stack-protector/warn-stack-protector-unsupported.basic.stderr @@ -1,4 +1,4 @@ -warning: `-Z stack-protector=basic` is not supported for target nvptx64-nvidia-cuda and will be ignored +warning: `-C stack-protector=basic` is not supported for target nvptx64-nvidia-cuda and will be ignored warning: 1 warning emitted diff --git a/tests/ui/stack-protector/warn-stack-protector-unsupported.rs b/tests/ui/stack-protector/warn-stack-protector-unsupported.rs index 9205d4052ad48..b39671dc5b6d7 100644 --- a/tests/ui/stack-protector/warn-stack-protector-unsupported.rs +++ b/tests/ui/stack-protector/warn-stack-protector-unsupported.rs @@ -2,9 +2,9 @@ //@ revisions: all strong basic //@ compile-flags: --target nvptx64-nvidia-cuda //@ needs-llvm-components: nvptx -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic +//@ [all] compile-flags: -C stack-protector=all +//@ [strong] compile-flags: -C stack-protector=strong -Z unstable-options +//@ [basic] compile-flags: -C stack-protector=basic -Z unstable-options #![crate_type = "lib"] #![feature(no_core, lang_items)] diff --git a/tests/ui/stack-protector/warn-stack-protector-unsupported.strong.stderr b/tests/ui/stack-protector/warn-stack-protector-unsupported.strong.stderr index ccc2f9f2cc5b8..741eb40910e0a 100644 --- a/tests/ui/stack-protector/warn-stack-protector-unsupported.strong.stderr +++ b/tests/ui/stack-protector/warn-stack-protector-unsupported.strong.stderr @@ -1,4 +1,4 @@ -warning: `-Z stack-protector=strong` is not supported for target nvptx64-nvidia-cuda and will be ignored +warning: `-C stack-protector=strong` is not supported for target nvptx64-nvidia-cuda and will be ignored warning: 1 warning emitted