mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-13 04:26:48 +00:00
Add ShadowCallStack Support
Adds support for the LLVM ShadowCallStack sanitizer.
This commit is contained in:
parent
a289cfcfb3
commit
adf61e3b2b
@ -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(());
|
||||
|
@ -192,6 +192,7 @@ pub enum AttributeKind {
|
||||
NoUndef = 33,
|
||||
SanitizeMemTag = 34,
|
||||
NoCfCheck = 35,
|
||||
ShadowCallStack = 36,
|
||||
}
|
||||
|
||||
/// LLVMIntPredicate
|
||||
|
@ -85,6 +85,7 @@ enum LLVMRustAttribute {
|
||||
NoUndef = 33,
|
||||
SanitizeMemTag = 34,
|
||||
NoCfCheck = 35,
|
||||
ShadowCallStack = 36,
|
||||
};
|
||||
|
||||
typedef struct OpaqueRustString *RustStringRef;
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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`";
|
||||
@ -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,
|
||||
|
@ -1282,6 +1282,7 @@ symbols! {
|
||||
self_in_typedefs,
|
||||
self_struct_ctor,
|
||||
semitransparent,
|
||||
shadow_call_stack,
|
||||
shl,
|
||||
shl_assign,
|
||||
should_panic,
|
||||
|
@ -17,6 +17,7 @@ pub fn target() -> Target {
|
||||
supported_sanitizers: SanitizerSet::CFI
|
||||
| SanitizerSet::HWADDRESS
|
||||
| SanitizerSet::MEMTAG
|
||||
| SanitizerSet::SHADOWCALLSTACK
|
||||
| SanitizerSet::ADDRESS,
|
||||
..super::android_base::opts()
|
||||
},
|
||||
|
@ -618,6 +618,7 @@ bitflags::bitflags! {
|
||||
const HWADDRESS = 1 << 4;
|
||||
const CFI = 1 << 5;
|
||||
const MEMTAG = 1 << 6;
|
||||
const SHADOWCALLSTACK = 1 << 7;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
@ -666,6 +668,7 @@ impl IntoIterator for SanitizerSet {
|
||||
SanitizerSet::LEAK,
|
||||
SanitizerSet::MEMORY,
|
||||
SanitizerSet::MEMTAG,
|
||||
SanitizerSet::SHADOWCALLSTACK,
|
||||
SanitizerSet::THREAD,
|
||||
SanitizerSet::HWADDRESS,
|
||||
]
|
||||
@ -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)),
|
||||
|
@ -2939,6 +2939,8 @@ 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) {
|
||||
@ -2946,7 +2948,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
```
|
||||
@ -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
|
||||
@ -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
src/test/codegen/sanitizer_scs_attr_check.rs
Normal file
17
src/test/codegen/sanitizer_scs_attr_check.rs
Normal file
@ -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() {}
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
@ -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"
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user