Skip to content

Add MemTagSanitizer Support #91675

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
Feb 19, 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
13 changes: 13 additions & 0 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ pub fn sanitize<'ll>(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &
if enabled.contains(SanitizerSet::HWADDRESS) {
llvm::Attribute::SanitizeHWAddress.apply_llfn(Function, llfn);
}
if enabled.contains(SanitizerSet::MEMTAG) {
// Check to make sure the mte target feature is actually enabled.
let sess = cx.tcx.sess;
let features = llvm_util::llvm_global_features(sess).join(",");
let mte_feature_enabled = features.rfind("+mte");
let mte_feature_disabled = features.rfind("-mte");

if mte_feature_enabled.is_none() || (mte_feature_disabled > mte_feature_enabled) {
sess.err("`-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`");
}

llvm::Attribute::SanitizeMemTag.apply_llfn(Function, llfn);
}
}

/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
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 @@ -190,6 +190,7 @@ pub enum Attribute {
StackProtectStrong = 31,
StackProtect = 32,
NoUndef = 33,
SanitizeMemTag = 34,
}

/// 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 @@ -83,6 +83,7 @@ enum LLVMRustAttribute {
StackProtectStrong = 31,
StackProtect = 32,
NoUndef = 33,
SanitizeMemTag = 34,
};

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 @@ -226,6 +226,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
return Attribute::StackProtect;
case NoUndef:
return Attribute::NoUndef;
case SanitizeMemTag:
return Attribute::SanitizeMemTag;
}
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 @@ -376,7 +376,7 @@ mod desc {
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
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` or `thread`";
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, 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 @@ -638,6 +638,7 @@ mod parse {
"cfi" => SanitizerSet::CFI,
"leak" => SanitizerSet::LEAK,
"memory" => SanitizerSet::MEMORY,
"memtag" => SanitizerSet::MEMTAG,
"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 @@ -875,6 +875,7 @@ symbols! {
mem_zeroed,
member_constraints,
memory,
memtag,
message,
meta,
metadata_type,
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_target/src/spec/aarch64_linux_android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ pub fn target() -> Target {
// As documented in https://developer.android.com/ndk/guides/cpu-features.html
// the neon (ASIMD) and FP must exist on all android aarch64 targets.
features: "+neon,+fp-armv8".to_string(),
supported_sanitizers: SanitizerSet::CFI | SanitizerSet::HWADDRESS,
supported_sanitizers: SanitizerSet::CFI
| SanitizerSet::HWADDRESS
| SanitizerSet::MEMTAG,
..super::android_base::opts()
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub fn target() -> Target {
| SanitizerSet::CFI
| SanitizerSet::LEAK
| SanitizerSet::MEMORY
| SanitizerSet::MEMTAG
| SanitizerSet::THREAD
| SanitizerSet::HWADDRESS,
..super::linux_gnu_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 @@ -606,6 +606,7 @@ bitflags::bitflags! {
const THREAD = 1 << 3;
const HWADDRESS = 1 << 4;
const CFI = 1 << 5;
const MEMTAG = 1 << 6;
}
}

Expand All @@ -619,6 +620,7 @@ impl SanitizerSet {
SanitizerSet::CFI => "cfi",
SanitizerSet::LEAK => "leak",
SanitizerSet::MEMORY => "memory",
SanitizerSet::MEMTAG => "memtag",
SanitizerSet::THREAD => "thread",
SanitizerSet::HWADDRESS => "hwaddress",
_ => return None,
Expand Down Expand Up @@ -652,6 +654,7 @@ impl IntoIterator for SanitizerSet {
SanitizerSet::CFI,
SanitizerSet::LEAK,
SanitizerSet::MEMORY,
SanitizerSet::MEMTAG,
SanitizerSet::THREAD,
SanitizerSet::HWADDRESS,
]
Expand Down Expand Up @@ -1881,6 +1884,7 @@ impl Target {
Some("cfi") => SanitizerSet::CFI,
Some("leak") => SanitizerSet::LEAK,
Some("memory") => SanitizerSet::MEMORY,
Some("memtag") => SanitizerSet::MEMTAG,
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 @@ -3008,14 +3008,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
} else if item.has_name(sym::memory) {
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::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`, `hwaddress`, `memory` or `thread`")
.note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`")
.emit();
}
}
Expand Down
20 changes: 18 additions & 2 deletions src/doc/unstable-book/src/compiler-flags/sanitizer.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ This feature allows for use of one of following sanitizers:
AddressSanitizer, but based on partial hardware assistance.
* [LeakSanitizer][clang-lsan] a run-time memory leak detector.
* [MemorySanitizer][clang-msan] a detector of uninitialized reads.
* [MemTagSanitizer][clang-memtag] fast memory error detector based on
Armv8.5-A Memory Tagging Extension.
* [ThreadSanitizer][clang-tsan] a fast data race detector.

To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory` or
`-Zsanitizer=thread`.
`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`,
`-Zsanitizer=memtag`, or `-Zsanitizer=thread`.

# AddressSanitizer

Expand Down Expand Up @@ -494,6 +496,20 @@ $ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
#0 0x560c04b2bc50 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:3
```

# MemTagSanitizer

MemTagSanitizer detects a similar class of errors as AddressSanitizer and HardwareAddressSanitizer, but with lower overhead suitable for use as hardening for production binaries.

MemTagSanitizer is supported on the following targets:

* `aarch64-linux-android`
* `aarch64-unknown-linux-gnu`

MemTagSanitizer requires hardware support and the `mte` target feature.
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).

# ThreadSanitizer

ThreadSanitizer is a data race detection tool. It is supported on the following
Expand Down
12 changes: 12 additions & 0 deletions src/test/codegen/sanitizer_memtag_attr_check.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// This tests that the sanitize_memtag attribute is
// applied when enabling the memtag sanitizer.
//
// needs-sanitizer-memtag
// compile-flags: -Zsanitizer=memtag -Ctarget-feature=+mte

#![crate_type = "lib"]

// CHECK: ; Function Attrs:{{.*}}sanitize_memtag
pub fn tagged() {}

// CHECK: attributes #0 = {{.*}}sanitize_memtag
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`, `hwaddress`, `memory` or `thread`
= note: expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`

error: aborting due to previous error

2 changes: 2 additions & 0 deletions src/tools/compiletest/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,7 @@ pub fn make_test_description<R: Read>(
let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target);
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);
// for `-Z gcc-ld=lld`
let has_rust_lld = config
.compile_lib_path
Expand Down Expand Up @@ -899,6 +900,7 @@ pub fn make_test_description<R: Read>(
ignore |= !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory");
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 |= config.target_panic == PanicStrategy::Abort
&& config.parse_name_directive(ln, "needs-unwind");
ignore |= config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln);
Expand Down
3 changes: 3 additions & 0 deletions src/tools/compiletest/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[
pub const HWASAN_SUPPORTED_TARGETS: &[&str] =
&["aarch64-linux-android", "aarch64-unknown-linux-gnu"];

pub const MEMTAG_SUPPORTED_TARGETS: &[&str] =
&["aarch64-linux-android", "aarch64-unknown-linux-gnu"];

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