Skip to content

Commit 568aeda

Browse files
committed
MemTagSanitizer Support
Adds support for the LLVM MemTagSanitizer.
1 parent 5569757 commit 568aeda

File tree

15 files changed

+67
-6
lines changed

15 files changed

+67
-6
lines changed

compiler/rustc_codegen_llvm/src/attributes.rs

+13
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,19 @@ pub fn sanitize<'ll>(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &
5555
if enabled.contains(SanitizerSet::HWADDRESS) {
5656
llvm::Attribute::SanitizeHWAddress.apply_llfn(Function, llfn);
5757
}
58+
if enabled.contains(SanitizerSet::MEMTAG) {
59+
// Check to make sure the mte target feature is actually enabled.
60+
let sess = cx.tcx.sess;
61+
let features = llvm_util::llvm_global_features(sess).join(",");
62+
let mte_feature_enabled = features.rfind("+mte");
63+
let mte_feature_disabled = features.rfind("-mte");
64+
65+
if mte_feature_enabled.is_none() || (mte_feature_disabled > mte_feature_enabled) {
66+
sess.err("`-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`");
67+
}
68+
69+
llvm::Attribute::SanitizeMemTag.apply_llfn(Function, llfn);
70+
}
5871
}
5972

6073
/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+1
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ pub enum Attribute {
190190
StackProtectStrong = 31,
191191
StackProtect = 32,
192192
NoUndef = 33,
193+
SanitizeMemTag = 34,
193194
}
194195

195196
/// LLVMIntPredicate

compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ enum LLVMRustAttribute {
8383
StackProtectStrong = 31,
8484
StackProtect = 32,
8585
NoUndef = 33,
86+
SanitizeMemTag = 34,
8687
};
8788

8889
typedef struct OpaqueRustString *RustStringRef;

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
226226
return Attribute::StackProtect;
227227
case NoUndef:
228228
return Attribute::NoUndef;
229+
case SanitizeMemTag:
230+
return Attribute::SanitizeMemTag;
229231
}
230232
report_fatal_error("bad AttributeKind");
231233
}

compiler/rustc_session/src/options.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ mod desc {
376376
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
377377
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
378378
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
379-
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory` or `thread`";
379+
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, or `thread`";
380380
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
381381
pub const parse_cfguard: &str =
382382
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
@@ -638,6 +638,7 @@ mod parse {
638638
"cfi" => SanitizerSet::CFI,
639639
"leak" => SanitizerSet::LEAK,
640640
"memory" => SanitizerSet::MEMORY,
641+
"memtag" => SanitizerSet::MEMTAG,
641642
"thread" => SanitizerSet::THREAD,
642643
"hwaddress" => SanitizerSet::HWADDRESS,
643644
_ => return false,

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,7 @@ symbols! {
875875
mem_zeroed,
876876
member_constraints,
877877
memory,
878+
memtag,
878879
message,
879880
meta,
880881
metadata_type,

compiler/rustc_target/src/spec/aarch64_linux_android.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ pub fn target() -> Target {
1414
// As documented in https://developer.android.com/ndk/guides/cpu-features.html
1515
// the neon (ASIMD) and FP must exist on all android aarch64 targets.
1616
features: "+neon,+fp-armv8".to_string(),
17-
supported_sanitizers: SanitizerSet::CFI | SanitizerSet::HWADDRESS,
17+
supported_sanitizers: SanitizerSet::CFI
18+
| SanitizerSet::HWADDRESS
19+
| SanitizerSet::MEMTAG,
1820
..super::android_base::opts()
1921
},
2022
}

compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub fn target() -> Target {
1414
| SanitizerSet::CFI
1515
| SanitizerSet::LEAK
1616
| SanitizerSet::MEMORY
17+
| SanitizerSet::MEMTAG
1718
| SanitizerSet::THREAD
1819
| SanitizerSet::HWADDRESS,
1920
..super::linux_gnu_base::opts()

compiler/rustc_target/src/spec/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@ bitflags::bitflags! {
606606
const THREAD = 1 << 3;
607607
const HWADDRESS = 1 << 4;
608608
const CFI = 1 << 5;
609+
const MEMTAG = 1 << 6;
609610
}
610611
}
611612

@@ -619,6 +620,7 @@ impl SanitizerSet {
619620
SanitizerSet::CFI => "cfi",
620621
SanitizerSet::LEAK => "leak",
621622
SanitizerSet::MEMORY => "memory",
623+
SanitizerSet::MEMTAG => "memtag",
622624
SanitizerSet::THREAD => "thread",
623625
SanitizerSet::HWADDRESS => "hwaddress",
624626
_ => return None,
@@ -652,6 +654,7 @@ impl IntoIterator for SanitizerSet {
652654
SanitizerSet::CFI,
653655
SanitizerSet::LEAK,
654656
SanitizerSet::MEMORY,
657+
SanitizerSet::MEMTAG,
655658
SanitizerSet::THREAD,
656659
SanitizerSet::HWADDRESS,
657660
]
@@ -1881,6 +1884,7 @@ impl Target {
18811884
Some("cfi") => SanitizerSet::CFI,
18821885
Some("leak") => SanitizerSet::LEAK,
18831886
Some("memory") => SanitizerSet::MEMORY,
1887+
Some("memtag") => SanitizerSet::MEMTAG,
18841888
Some("thread") => SanitizerSet::THREAD,
18851889
Some("hwaddress") => SanitizerSet::HWADDRESS,
18861890
Some(s) => return Err(format!("unknown sanitizer {}", s)),

compiler/rustc_typeck/src/collect.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -3008,14 +3008,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
30083008
codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
30093009
} else if item.has_name(sym::memory) {
30103010
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
3011+
} else if item.has_name(sym::memtag) {
3012+
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
30113013
} else if item.has_name(sym::thread) {
30123014
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
30133015
} else if item.has_name(sym::hwaddress) {
30143016
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
30153017
} else {
30163018
tcx.sess
30173019
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
3018-
.note("expected one of: `address`, `hwaddress`, `memory` or `thread`")
3020+
.note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`")
30193021
.emit();
30203022
}
30213023
}

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

+18-2
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ This feature allows for use of one of following sanitizers:
1616
AddressSanitizer, but based on partial hardware assistance.
1717
* [LeakSanitizer][clang-lsan] a run-time memory leak detector.
1818
* [MemorySanitizer][clang-msan] a detector of uninitialized reads.
19+
* [MemTagSanitizer][clang-memtag] fast memory error detector based on
20+
Armv8.5-A Memory Tagging Extension.
1921
* [ThreadSanitizer][clang-tsan] a fast data race detector.
2022

2123
To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
22-
`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory` or
23-
`-Zsanitizer=thread`.
24+
`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`,
25+
`-Zsanitizer=memtag`, or `-Zsanitizer=thread`.
2426

2527
# AddressSanitizer
2628

@@ -494,6 +496,20 @@ $ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
494496
#0 0x560c04b2bc50 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:3
495497
```
496498
499+
# MemTagSanitizer
500+
501+
MemTagSanitizer detects a similar class of errors as AddressSanitizer and HardwareAddressSanitizer, but with lower overhead suitable for use as hardening for production binaries.
502+
503+
MemTagSanitizer is supported on the following targets:
504+
505+
* `aarch64-linux-android`
506+
* `aarch64-unknown-linux-gnu`
507+
508+
MemTagSanitizer requires hardware support and the `mte` target feature.
509+
To enable this target feature compile with `-C target-feature="+mte"`.
510+
511+
More information can be found in the associated [LLVM documentation](https://llvm.org/docs/MemTagSanitizer.html).
512+
497513
# ThreadSanitizer
498514
499515
ThreadSanitizer is a data race detection tool. It is supported on the following
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// This tests that the sanitize_memtag attribute is
2+
// applied when enabling the memtag sanitizer.
3+
//
4+
// needs-sanitizer-memtag
5+
// compile-flags: -Zsanitizer=memtag -Ctarget-feature=+mte
6+
7+
#![crate_type = "lib"]
8+
9+
// CHECK: ; Function Attrs:{{.*}}sanitize_memtag
10+
pub fn tagged() {}
11+
12+
// CHECK: attributes #0 = {{.*}}sanitize_memtag

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`, `hwaddress`, `memory` or `thread`
7+
= note: expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`
88

99
error: aborting due to previous error
1010

src/tools/compiletest/src/header.rs

+2
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,7 @@ pub fn make_test_description<R: Read>(
863863
let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target);
864864
let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target);
865865
let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target);
866+
let has_memtag = util::MEMTAG_SUPPORTED_TARGETS.contains(&&*config.target);
866867
// for `-Z gcc-ld=lld`
867868
let has_rust_lld = config
868869
.compile_lib_path
@@ -899,6 +900,7 @@ pub fn make_test_description<R: Read>(
899900
ignore |= !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory");
900901
ignore |= !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread");
901902
ignore |= !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress");
903+
ignore |= !has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag");
902904
ignore |= config.target_panic == PanicStrategy::Abort
903905
&& config.parse_name_directive(ln, "needs-unwind");
904906
ignore |= config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln);

src/tools/compiletest/src/util.rs

+3
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[
117117
pub const HWASAN_SUPPORTED_TARGETS: &[&str] =
118118
&["aarch64-linux-android", "aarch64-unknown-linux-gnu"];
119119

120+
pub const MEMTAG_SUPPORTED_TARGETS: &[&str] =
121+
&["aarch64-linux-android", "aarch64-unknown-linux-gnu"];
122+
120123
const BIG_ENDIAN: &[&str] = &[
121124
"aarch64_be",
122125
"armebv7r",

0 commit comments

Comments
 (0)