Skip to content

Commit adf61e3

Browse files
committed
Add ShadowCallStack Support
Adds support for the LLVM ShadowCallStack sanitizer.
1 parent a289cfc commit adf61e3

File tree

14 files changed

+57
-4
lines changed

14 files changed

+57
-4
lines changed

compiler/rustc_codegen_llvm/src/attributes.rs

+3
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ pub fn sanitize_attrs<'ll>(
6969
if enabled.contains(SanitizerSet::HWADDRESS) {
7070
attrs.push(llvm::AttributeKind::SanitizeHWAddress.create_attr(cx.llcx));
7171
}
72+
if enabled.contains(SanitizerSet::SHADOWCALLSTACK) {
73+
attrs.push(llvm::AttributeKind::ShadowCallStack.create_attr(cx.llcx));
74+
}
7275
if enabled.contains(SanitizerSet::MEMTAG) {
7376
// Check to make sure the mte target feature is actually enabled.
7477
let features = cx.tcx.global_backend_features(());

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+1
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ pub enum AttributeKind {
192192
NoUndef = 33,
193193
SanitizeMemTag = 34,
194194
NoCfCheck = 35,
195+
ShadowCallStack = 36,
195196
}
196197

197198
/// LLVMIntPredicate

compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ enum LLVMRustAttribute {
8585
NoUndef = 33,
8686
SanitizeMemTag = 34,
8787
NoCfCheck = 35,
88+
ShadowCallStack = 36,
8889
};
8990

9091
typedef struct OpaqueRustString *RustStringRef;

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
232232
return Attribute::NoUndef;
233233
case SanitizeMemTag:
234234
return Attribute::SanitizeMemTag;
235+
case ShadowCallStack:
236+
return Attribute::ShadowCallStack;
235237
}
236238
report_fatal_error("bad AttributeKind");
237239
}

compiler/rustc_session/src/options.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ mod desc {
377377
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
378378
pub const parse_oom_strategy: &str = "either `panic` or `abort`";
379379
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
380-
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, or `thread`";
380+
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, `shadow-call-stack`, or `thread`";
381381
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
382382
pub const parse_cfguard: &str =
383383
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
@@ -683,6 +683,7 @@ mod parse {
683683
"leak" => SanitizerSet::LEAK,
684684
"memory" => SanitizerSet::MEMORY,
685685
"memtag" => SanitizerSet::MEMTAG,
686+
"shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
686687
"thread" => SanitizerSet::THREAD,
687688
"hwaddress" => SanitizerSet::HWADDRESS,
688689
_ => return false,

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,7 @@ symbols! {
12821282
self_in_typedefs,
12831283
self_struct_ctor,
12841284
semitransparent,
1285+
shadow_call_stack,
12851286
shl,
12861287
shl_assign,
12871288
should_panic,

compiler/rustc_target/src/spec/aarch64_linux_android.rs

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub fn target() -> Target {
1717
supported_sanitizers: SanitizerSet::CFI
1818
| SanitizerSet::HWADDRESS
1919
| SanitizerSet::MEMTAG
20+
| SanitizerSet::SHADOWCALLSTACK
2021
| SanitizerSet::ADDRESS,
2122
..super::android_base::opts()
2223
},

compiler/rustc_target/src/spec/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,7 @@ bitflags::bitflags! {
618618
const HWADDRESS = 1 << 4;
619619
const CFI = 1 << 5;
620620
const MEMTAG = 1 << 6;
621+
const SHADOWCALLSTACK = 1 << 7;
621622
}
622623
}
623624

@@ -632,6 +633,7 @@ impl SanitizerSet {
632633
SanitizerSet::LEAK => "leak",
633634
SanitizerSet::MEMORY => "memory",
634635
SanitizerSet::MEMTAG => "memtag",
636+
SanitizerSet::SHADOWCALLSTACK => "shadow-call-stack",
635637
SanitizerSet::THREAD => "thread",
636638
SanitizerSet::HWADDRESS => "hwaddress",
637639
_ => return None,
@@ -666,6 +668,7 @@ impl IntoIterator for SanitizerSet {
666668
SanitizerSet::LEAK,
667669
SanitizerSet::MEMORY,
668670
SanitizerSet::MEMTAG,
671+
SanitizerSet::SHADOWCALLSTACK,
669672
SanitizerSet::THREAD,
670673
SanitizerSet::HWADDRESS,
671674
]
@@ -1960,6 +1963,7 @@ impl Target {
19601963
Some("leak") => SanitizerSet::LEAK,
19611964
Some("memory") => SanitizerSet::MEMORY,
19621965
Some("memtag") => SanitizerSet::MEMTAG,
1966+
Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK,
19631967
Some("thread") => SanitizerSet::THREAD,
19641968
Some("hwaddress") => SanitizerSet::HWADDRESS,
19651969
Some(s) => return Err(format!("unknown sanitizer {}", s)),

compiler/rustc_typeck/src/collect.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2939,14 +2939,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
29392939
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
29402940
} else if item.has_name(sym::memtag) {
29412941
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
2942+
} else if item.has_name(sym::shadow_call_stack) {
2943+
codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK;
29422944
} else if item.has_name(sym::thread) {
29432945
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
29442946
} else if item.has_name(sym::hwaddress) {
29452947
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
29462948
} else {
29472949
tcx.sess
29482950
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
2949-
.note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`")
2951+
.note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
29502952
.emit();
29512953
}
29522954
}

src/doc/unstable-book/src/compiler-flags/sanitizer.md

+16-1
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ This feature allows for use of one of following sanitizers:
1818
* [MemorySanitizer][clang-msan] a detector of uninitialized reads.
1919
* [MemTagSanitizer][clang-memtag] fast memory error detector based on
2020
Armv8.5-A Memory Tagging Extension.
21+
* [ShadowCallStack][clang-scs] provides backward-edge control flow protection.
2122
* [ThreadSanitizer][clang-tsan] a fast data race detector.
2223

2324
To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
2425
`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`,
25-
`-Zsanitizer=memtag`, or `-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags. Example:
26+
`-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or `-Zsanitizer=thread`.
27+
You might also need the `--target` and `build-std` flags. Example:
2628
```shell
2729
$ RUSTFLAGS=-Zsanitizer=address cargo build -Zbuild-std --target x86_64-unknown-linux-gnu
2830
```
@@ -513,6 +515,18 @@ To enable this target feature compile with `-C target-feature="+mte"`.
513515
514516
More information can be found in the associated [LLVM documentation](https://llvm.org/docs/MemTagSanitizer.html).
515517
518+
# ShadowCallStack
519+
520+
ShadowCallStack provides backward edge control flow protection by storing a function's return address in a separately allocated 'shadow call stack' and loading the return address from that shadow call stack.
521+
522+
ShadowCallStack requires a platform ABI which reserves `x18` as the instrumentation makes use of this register.
523+
524+
ShadowCallStack can be enabled with `-Zsanitizer=shadow-call-stack` option and is supported on the following targets:
525+
526+
* `aarch64-linux-android`
527+
528+
A runtime must be provided by the application or operating system. See the [LLVM documentation][clang-scs] for further details.
529+
516530
# ThreadSanitizer
517531
518532
ThreadSanitizer is a data race detection tool. It is supported on the following
@@ -610,4 +624,5 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
610624
[clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
611625
[clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
612626
[clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
627+
[clang-scs]: https://clang.llvm.org/docs/ShadowCallStack.html
613628
[clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// This tests that the shadowcallstack attribute is
2+
// applied when enabling the shadow-call-stack sanitizer.
3+
//
4+
// needs-sanitizer-shadow-call-stack
5+
// compile-flags: -Zsanitizer=shadow-call-stack
6+
7+
#![crate_type = "lib"]
8+
#![feature(no_sanitize)]
9+
10+
// CHECK: ; Function Attrs:{{.*}}shadowcallstack
11+
// CHECK-NEXT: scs
12+
pub fn scs() {}
13+
14+
// CHECK-NOT: ; Function Attrs:{{.*}}shadowcallstack
15+
// CHECK-NEXT: no_scs
16+
#[no_sanitize(shadow_call_stack)]
17+
pub fn no_scs() {}

src/test/ui/invalid/invalid-no-sanitize.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: invalid argument for `no_sanitize`
44
LL | #[no_sanitize(brontosaurus)]
55
| ^^^^^^^^^^^^
66
|
7-
= note: expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`
7+
= note: expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
88

99
error: aborting due to previous error
1010

src/tools/compiletest/src/header.rs

+3
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,7 @@ pub fn make_test_description<R: Read>(
862862
let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target);
863863
let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target);
864864
let has_memtag = util::MEMTAG_SUPPORTED_TARGETS.contains(&&*config.target);
865+
let has_shadow_call_stack = util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(&&*config.target);
865866
// for `-Z gcc-ld=lld`
866867
let has_rust_lld = config
867868
.compile_lib_path
@@ -899,6 +900,8 @@ pub fn make_test_description<R: Read>(
899900
ignore |= !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread");
900901
ignore |= !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress");
901902
ignore |= !has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag");
903+
ignore |= !has_shadow_call_stack
904+
&& config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack");
902905
ignore |= config.target_panic == PanicStrategy::Abort
903906
&& config.parse_name_directive(ln, "needs-unwind");
904907
ignore |= config.target == "wasm32-unknown-unknown"

src/tools/compiletest/src/util.rs

+2
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ pub const HWASAN_SUPPORTED_TARGETS: &[&str] =
121121
pub const MEMTAG_SUPPORTED_TARGETS: &[&str] =
122122
&["aarch64-linux-android", "aarch64-unknown-linux-gnu"];
123123

124+
pub const SHADOWCALLSTACK_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android"];
125+
124126
const BIG_ENDIAN: &[&str] = &[
125127
"aarch64_be",
126128
"armebv7r",

0 commit comments

Comments
 (0)