Skip to content

Commit b2c554a

Browse files
committed
-Zharden-sls flag (target modifier) added to enable mitigation against straight line speculation (SLS)
1 parent 922958c commit b2c554a

File tree

10 files changed

+196
-5
lines changed

10 files changed

+196
-5
lines changed

compiler/rustc_codegen_gcc/src/gcc_util.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use smallvec::{SmallVec, smallvec};
66

77
fn gcc_features_by_flags(sess: &Session, features: &mut Vec<String>) {
88
target_features::retpoline_features_by_flags(sess, features);
9+
target_features::sls_features_by_flags(sess, features);
910
// FIXME: LLVM also sets +reserve-x18 here under some conditions.
1011
}
1112

compiler/rustc_codegen_llvm/src/llvm_util.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,7 @@ pub(crate) fn target_cpu(sess: &Session) -> &str {
647647
/// The target features for compiler flags other than `-Ctarget-features`.
648648
fn llvm_features_by_flags(sess: &Session, features: &mut Vec<String>) {
649649
target_features::retpoline_features_by_flags(sess, features);
650+
target_features::sls_features_by_flags(sess, features);
650651

651652
// -Zfixed-x18
652653
if sess.opts.unstable_opts.fixed_x18 {

compiler/rustc_codegen_ssa/src/target_features.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
77
use rustc_middle::query::Providers;
88
use rustc_middle::ty::TyCtxt;
99
use rustc_session::Session;
10+
use rustc_session::config::HardenSls;
1011
use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
1112
use rustc_session::parse::feature_err;
1213
use rustc_span::{Span, Symbol, sym};
@@ -412,6 +413,18 @@ pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<String>) {
412413
}
413414
}
414415

416+
pub fn sls_features_by_flags(sess: &Session, features: &mut Vec<String>) {
417+
match &sess.opts.unstable_opts.harden_sls {
418+
HardenSls::None => (),
419+
HardenSls::All => {
420+
features.push("+harden-sls-ijmp".into());
421+
features.push("+harden-sls-ret".into());
422+
}
423+
HardenSls::Return => features.push("+harden-sls-ret".into()),
424+
HardenSls::IndirectJmp => features.push("+harden-sls-ijmp".into()),
425+
}
426+
}
427+
415428
pub(crate) fn provide(providers: &mut Providers) {
416429
*providers = Providers {
417430
rust_target_features: |tcx, cnum| {

compiler/rustc_session/src/config.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3213,11 +3213,11 @@ pub(crate) mod dep_tracking {
32133213
use super::{
32143214
AutoDiff, BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CoverageOptions,
32153215
CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, FunctionReturn,
3216-
InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail,
3217-
LtoCli, MirStripDebugInfo, NextSolverConfig, Offload, OomStrategy, OptLevel, OutFileName,
3218-
OutputType, OutputTypes, PatchableFunctionEntry, Polonius, RemapPathScopeComponents,
3219-
ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath,
3220-
SymbolManglingVersion, WasiExecModel,
3216+
HardenSls, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto,
3217+
LocationDetail, LtoCli, MirStripDebugInfo, NextSolverConfig, Offload, OomStrategy,
3218+
OptLevel, OutFileName, OutputType, OutputTypes, PatchableFunctionEntry, Polonius,
3219+
RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind,
3220+
SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
32213221
};
32223222
use crate::lint;
32233223
use crate::utils::NativeLib;
@@ -3320,6 +3320,7 @@ pub(crate) mod dep_tracking {
33203320
Polonius,
33213321
InliningThreshold,
33223322
FunctionReturn,
3323+
HardenSls,
33233324
Align,
33243325
);
33253326

@@ -3574,6 +3575,16 @@ pub enum FunctionReturn {
35743575
ThunkExtern,
35753576
}
35763577

3578+
/// The different settings that the `-Zharden-sls` flag can have.
3579+
#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3580+
pub enum HardenSls {
3581+
#[default]
3582+
None,
3583+
All,
3584+
Return,
3585+
IndirectJmp,
3586+
}
3587+
35773588
/// Whether extra span comments are included when dumping MIR, via the `-Z mir-include-spans` flag.
35783589
/// By default, only enabled in the NLL MIR dumps, and disabled in all other passes.
35793590
#[derive(Clone, Copy, Default, PartialEq, Debug)]

compiler/rustc_session/src/options.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,7 @@ mod desc {
808808
"either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number";
809809
pub(crate) const parse_llvm_module_flag: &str = "<key>:<type>:<value>:<behavior>. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)";
810810
pub(crate) const parse_function_return: &str = "`keep` or `thunk-extern`";
811+
pub(crate) const parse_harden_sls: &str = "`none`, `all`, `return` or `indirect-jmp`";
811812
pub(crate) const parse_wasm_c_abi: &str = "`spec`";
812813
pub(crate) const parse_mir_include_spans: &str =
813814
"either a boolean (`yes`, `no`, `on`, `off`, etc), or `nll` (default: `nll`)";
@@ -1936,6 +1937,17 @@ pub mod parse {
19361937
true
19371938
}
19381939

1940+
pub(crate) fn parse_harden_sls(slot: &mut HardenSls, v: Option<&str>) -> bool {
1941+
match v {
1942+
Some("none") => *slot = HardenSls::None,
1943+
Some("all") => *slot = HardenSls::All,
1944+
Some("return") => *slot = HardenSls::Return,
1945+
Some("indirect-jmp") => *slot = HardenSls::IndirectJmp,
1946+
_ => return false,
1947+
}
1948+
true
1949+
}
1950+
19391951
pub(crate) fn parse_wasm_c_abi(_slot: &mut (), v: Option<&str>) -> bool {
19401952
v == Some("spec")
19411953
}
@@ -2273,6 +2285,9 @@ options! {
22732285
graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED],
22742286
"use the given `fontname` in graphviz output; can be overridden by setting \
22752287
environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"),
2288+
harden_sls: HardenSls = (HardenSls::None, parse_harden_sls, [TRACKED TARGET_MODIFIER],
2289+
"flag to mitigate against straight line speculation (SLS) [none|all|return|indirect-jmp] \
2290+
(default: none)"),
22762291
has_thread_local: Option<bool> = (None, parse_opt_bool, [TRACKED],
22772292
"explicitly enable the `cfg(target_thread_local)` directive"),
22782293
higher_ranked_assumptions: bool = (false, parse_bool, [TRACKED],

compiler/rustc_target/src/target_features.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,16 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
437437
("fma", Stable, &["avx"]),
438438
("fxsr", Stable, &[]),
439439
("gfni", Stable, &["sse2"]),
440+
(
441+
"harden-sls-ijmp",
442+
Stability::Forbidden { reason: "use `harden-sls` compiler flag instead" },
443+
&[],
444+
),
445+
(
446+
"harden-sls-ret",
447+
Stability::Forbidden { reason: "use `harden-sls` compiler flag instead" },
448+
&[],
449+
),
440450
("kl", Stable, &["sse2"]),
441451
("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
442452
("lzcnt", Stable, &[]),

tests/assembly-llvm/x86_64-sls.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Test harden-sls flag
2+
3+
#![feature(core_intrinsics)]
4+
//@ revisions: NONE ALL RET IJMP
5+
//@ assembly-output: emit-asm
6+
//@ compile-flags: -Copt-level=3 -Cunsafe-allow-abi-mismatch=harden-sls
7+
//@ [NONE] compile-flags: -Zharden-sls=none
8+
//@ [ALL] compile-flags: -Zharden-sls=all
9+
//@ [RET] compile-flags: -Zharden-sls=return
10+
//@ [IJMP] compile-flags: -Zharden-sls=indirect-jmp
11+
//@ only-x86_64
12+
#![crate_type = "lib"]
13+
14+
#[no_mangle]
15+
pub fn double_return(a: i32, b: i32) -> i32 {
16+
// CHECK-LABEL: double_return:
17+
// CHECK: jle
18+
// CHECK-NOT: int3
19+
// CHECK: retq
20+
// RET-NEXT: int3
21+
// ALL-NEXT: int3
22+
// IJMP-NOT: int3
23+
// NONE-NOT: int3
24+
// CHECK: retq
25+
// RET-NEXT: int3
26+
// ALL-NEXT: int3
27+
// IJMP-NOT: int3
28+
// NONE-NOT: int3
29+
if a > 0 {
30+
return unsafe { std::intrinsics::unchecked_div(a, b) };
31+
} else {
32+
return unsafe { std::intrinsics::unchecked_div(b, a) };
33+
}
34+
}
35+
36+
#[no_mangle]
37+
pub fn indirect_branch(a: i32, b: i32, i: i32) -> i32 {
38+
// CHECK-LABEL: indirect_branch:
39+
// CHECK: jmpq *
40+
// RET-NOT: int3
41+
// NONE-NOT: int3
42+
// IJMP-NEXT: int3
43+
// ALL-NEXT: int3
44+
// CHECK: retq
45+
// RET-NEXT: int3
46+
// ALL-NEXT: int3
47+
// IJMP-NOT: int3
48+
// NONE-NOT: int3
49+
// CHECK: retq
50+
// RET-NEXT: int3
51+
// ALL-NEXT: int3
52+
// IJMP-NOT: int3
53+
// NONE-NOT: int3
54+
match i {
55+
0 => unsafe {
56+
return std::intrinsics::unchecked_div(a, b);
57+
},
58+
1 => unsafe { return std::intrinsics::unchecked_div(b, a) },
59+
2 => unsafe { return std::intrinsics::unchecked_div(b, a) + 2 },
60+
3 => unsafe { return std::intrinsics::unchecked_div(b, a) + 3 },
61+
4 => unsafe { return std::intrinsics::unchecked_div(b, a) + 4 },
62+
5 => unsafe { return std::intrinsics::unchecked_div(b, a) + 5 },
63+
6 => unsafe { return std::intrinsics::unchecked_div(b, a) + 6 },
64+
_ => panic!(""),
65+
}
66+
}
67+
68+
#[no_mangle]
69+
pub fn bar(ptr: fn()) {
70+
// CHECK-LABEL: bar:
71+
// CHECK: jmpq *
72+
// RET-NOT: int3
73+
// NONE-NOT: int3
74+
// IJMP-NEXT: int3
75+
// ALL-NEXT: int3
76+
// CHECK-NOT: ret
77+
ptr()
78+
}

tests/codegen-llvm/harden-sls.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// ignore-tidy-linelength
2+
// Test that the `harden-sls-ijmp`, `harden-sls-ret` target features is (not) emitted when
3+
// the `harden-sls=[none|all|return|indirect-jmp]` flag is (not) set.
4+
5+
//@ add-core-stubs
6+
//@ revisions: none all return indirect_jmp
7+
//@ needs-llvm-components: x86
8+
//@ compile-flags: --target x86_64-unknown-linux-gnu
9+
//@ [none] compile-flags: -Zharden-sls=none
10+
//@ [all] compile-flags: -Zharden-sls=all
11+
//@ [return] compile-flags: -Zharden-sls=return
12+
//@ [indirect_jmp] compile-flags: -Zharden-sls=indirect-jmp
13+
14+
#![crate_type = "lib"]
15+
#![feature(no_core)]
16+
#![no_core]
17+
18+
extern crate minicore;
19+
use minicore::*;
20+
21+
#[no_mangle]
22+
pub fn foo() {
23+
// CHECK: @foo() unnamed_addr #0
24+
25+
// none-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+harden-sls-ijmp{{.*}} }
26+
// none-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+harden-sls-ret{{.*}} }
27+
28+
// all: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+harden-sls-ijmp,+harden-sls-ret{{.*}} }
29+
30+
// return-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+harden-sls-ijmp{{.*}} }
31+
// return: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+harden-sls-ret{{.*}} }
32+
33+
// indirect_jmp-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+harden-sls-ret{{.*}} }
34+
// indirect_jmp: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+harden-sls-ijmp{{.*}} }
35+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
warning: target feature `harden-sls-ijmp` cannot be enabled with `-Ctarget-feature`: use `harden-sls` compiler flag instead
2+
|
3+
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
4+
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
5+
6+
warning: target feature `harden-sls-ret` cannot be enabled with `-Ctarget-feature`: use `harden-sls` compiler flag instead
7+
|
8+
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
9+
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
10+
11+
warning: 2 warnings emitted
12+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//@ add-core-stubs
2+
//@ revisions: by_flag by_feature
3+
//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
4+
//@ needs-llvm-components: x86
5+
//@ [by_flag]compile-flags: -Zharden-sls=all
6+
//@ [by_feature]compile-flags: -Ctarget-feature=+harden-sls-ijmp,+harden-sls-ret
7+
//@ [by_flag]build-pass
8+
// For now this is just a warning.
9+
//@ [by_feature]build-pass
10+
#![feature(no_core, lang_items)]
11+
#![no_std]
12+
#![no_core]
13+
14+
//[by_feature]~? WARN target feature `harden-sls-ijmp` cannot be enabled with `-Ctarget-feature`: use `harden-sls` compiler flag instead
15+
//[by_feature]~? WARN target feature `harden-sls-ret` cannot be enabled with `-Ctarget-feature`: use `harden-sls` compiler flag instead

0 commit comments

Comments
 (0)