Skip to content

Add support for LLVM ShadowCallStack. #98208

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

Merged
merged 1 commit into from
Jul 23, 2022
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
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ pub fn sanitize_attrs<'ll>(
if enabled.contains(SanitizerSet::HWADDRESS) {
attrs.push(llvm::AttributeKind::SanitizeHWAddress.create_attr(cx.llcx));
}
if enabled.contains(SanitizerSet::SHADOWCALLSTACK) {
attrs.push(llvm::AttributeKind::ShadowCallStack.create_attr(cx.llcx));
}
if enabled.contains(SanitizerSet::MEMTAG) {
// Check to make sure the mte target feature is actually enabled.
let features = cx.tcx.global_backend_features(());
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ pub enum AttributeKind {
NoUndef = 33,
SanitizeMemTag = 34,
NoCfCheck = 35,
ShadowCallStack = 36,
}

/// LLVMIntPredicate
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ enum LLVMRustAttribute {
NoUndef = 33,
SanitizeMemTag = 34,
NoCfCheck = 35,
ShadowCallStack = 36,
};

typedef struct OpaqueRustString *RustStringRef;
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
return Attribute::NoUndef;
case SanitizeMemTag:
return Attribute::SanitizeMemTag;
case ShadowCallStack:
return Attribute::ShadowCallStack;
}
report_fatal_error("bad AttributeKind");
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ mod desc {
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
pub const parse_oom_strategy: &str = "either `panic` or `abort`";
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, or `thread`";
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, `shadow-call-stack`, or `thread`";
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
pub const parse_cfguard: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
Expand Down Expand Up @@ -683,6 +683,7 @@ mod parse {
"leak" => SanitizerSet::LEAK,
"memory" => SanitizerSet::MEMORY,
"memtag" => SanitizerSet::MEMTAG,
"shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
"thread" => SanitizerSet::THREAD,
"hwaddress" => SanitizerSet::HWADDRESS,
_ => return false,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1282,6 +1282,7 @@ symbols! {
self_in_typedefs,
self_struct_ctor,
semitransparent,
shadow_call_stack,
shl,
shl_assign,
should_panic,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_target/src/spec/aarch64_linux_android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub fn target() -> Target {
supported_sanitizers: SanitizerSet::CFI
| SanitizerSet::HWADDRESS
| SanitizerSet::MEMTAG
| SanitizerSet::SHADOWCALLSTACK
| SanitizerSet::ADDRESS,
..super::android_base::opts()
},
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ bitflags::bitflags! {
const HWADDRESS = 1 << 4;
const CFI = 1 << 5;
const MEMTAG = 1 << 6;
const SHADOWCALLSTACK = 1 << 7;
}
}

Expand All @@ -632,6 +633,7 @@ impl SanitizerSet {
SanitizerSet::LEAK => "leak",
SanitizerSet::MEMORY => "memory",
SanitizerSet::MEMTAG => "memtag",
SanitizerSet::SHADOWCALLSTACK => "shadow-call-stack",
SanitizerSet::THREAD => "thread",
SanitizerSet::HWADDRESS => "hwaddress",
_ => return None,
Expand Down Expand Up @@ -666,6 +668,7 @@ impl IntoIterator for SanitizerSet {
SanitizerSet::LEAK,
SanitizerSet::MEMORY,
SanitizerSet::MEMTAG,
SanitizerSet::SHADOWCALLSTACK,
SanitizerSet::THREAD,
SanitizerSet::HWADDRESS,
]
Expand Down Expand Up @@ -1960,6 +1963,7 @@ impl Target {
Some("leak") => SanitizerSet::LEAK,
Some("memory") => SanitizerSet::MEMORY,
Some("memtag") => SanitizerSet::MEMTAG,
Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK,
Some("thread") => SanitizerSet::THREAD,
Some("hwaddress") => SanitizerSet::HWADDRESS,
Some(s) => return Err(format!("unknown sanitizer {}", s)),
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_typeck/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2939,14 +2939,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
} else if item.has_name(sym::memtag) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
} else if item.has_name(sym::shadow_call_stack) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK;
} else if item.has_name(sym::thread) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
} else if item.has_name(sym::hwaddress) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
} else {
tcx.sess
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
.note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`")
.note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
.emit();
}
}
Expand Down
17 changes: 16 additions & 1 deletion src/doc/unstable-book/src/compiler-flags/sanitizer.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ This feature allows for use of one of following sanitizers:
* [MemorySanitizer][clang-msan] a detector of uninitialized reads.
* [MemTagSanitizer][clang-memtag] fast memory error detector based on
Armv8.5-A Memory Tagging Extension.
* [ShadowCallStack][clang-scs] provides backward-edge control flow protection.
* [ThreadSanitizer][clang-tsan] a fast data race detector.

To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`,
`-Zsanitizer=memtag`, or `-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags. Example:
`-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or `-Zsanitizer=thread`.
You might also need the `--target` and `build-std` flags. Example:
```shell
$ RUSTFLAGS=-Zsanitizer=address cargo build -Zbuild-std --target x86_64-unknown-linux-gnu
```
Expand Down Expand Up @@ -513,6 +515,18 @@ To enable this target feature compile with `-C target-feature="+mte"`.

More information can be found in the associated [LLVM documentation](https://llvm.org/docs/MemTagSanitizer.html).

# ShadowCallStack

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.

ShadowCallStack requires a platform ABI which reserves `x18` as the instrumentation makes use of this register.

ShadowCallStack can be enabled with `-Zsanitizer=shadow-call-stack` option and is supported on the following targets:

* `aarch64-linux-android`

A runtime must be provided by the application or operating system. See the [LLVM documentation][clang-scs] for further details.

# ThreadSanitizer

ThreadSanitizer is a data race detection tool. It is supported on the following
Expand Down Expand Up @@ -610,4 +624,5 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
[clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
[clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
[clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
[clang-scs]: https://clang.llvm.org/docs/ShadowCallStack.html
[clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html
17 changes: 17 additions & 0 deletions src/test/codegen/sanitizer_scs_attr_check.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// This tests that the shadowcallstack attribute is
// applied when enabling the shadow-call-stack sanitizer.
//
// needs-sanitizer-shadow-call-stack
// compile-flags: -Zsanitizer=shadow-call-stack

#![crate_type = "lib"]
#![feature(no_sanitize)]

// CHECK: ; Function Attrs:{{.*}}shadowcallstack
// CHECK-NEXT: scs
pub fn scs() {}

// CHECK-NOT: ; Function Attrs:{{.*}}shadowcallstack
// CHECK-NEXT: no_scs
#[no_sanitize(shadow_call_stack)]
pub fn no_scs() {}
2 changes: 1 addition & 1 deletion src/test/ui/invalid/invalid-no-sanitize.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error: invalid argument for `no_sanitize`
LL | #[no_sanitize(brontosaurus)]
| ^^^^^^^^^^^^
|
= note: expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`
= note: expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread`

error: aborting due to previous error

3 changes: 3 additions & 0 deletions src/tools/compiletest/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,7 @@ pub fn make_test_description<R: Read>(
let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target);
let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target);
let has_memtag = util::MEMTAG_SUPPORTED_TARGETS.contains(&&*config.target);
let has_shadow_call_stack = util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(&&*config.target);
// for `-Z gcc-ld=lld`
let has_rust_lld = config
.compile_lib_path
Expand Down Expand Up @@ -899,6 +900,8 @@ pub fn make_test_description<R: Read>(
ignore |= !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread");
ignore |= !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress");
ignore |= !has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag");
ignore |= !has_shadow_call_stack
&& config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack");
ignore |= config.target_panic == PanicStrategy::Abort
&& config.parse_name_directive(ln, "needs-unwind");
ignore |= config.target == "wasm32-unknown-unknown"
Expand Down
2 changes: 2 additions & 0 deletions src/tools/compiletest/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ pub const HWASAN_SUPPORTED_TARGETS: &[&str] =
pub const MEMTAG_SUPPORTED_TARGETS: &[&str] =
&["aarch64-linux-android", "aarch64-unknown-linux-gnu"];

pub const SHADOWCALLSTACK_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android"];

const BIG_ENDIAN: &[&str] = &[
"aarch64_be",
"armebv7r",
Expand Down