]> granicus.if.org Git - clang/commitdiff
ARM MTE stack sanitizer.
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>
Mon, 15 Jul 2019 20:02:23 +0000 (20:02 +0000)
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>
Mon, 15 Jul 2019 20:02:23 +0000 (20:02 +0000)
Add "memtag" sanitizer that detects and mitigates stack memory issues
using armv8.5 Memory Tagging Extension.

It is similar in principle to HWASan, which is a software implementation
of the same idea, but there are enough differencies to warrant a new
sanitizer type IMHO. It is also expected to have very different
performance properties.

The new sanitizer does not have a runtime library (it may grow one
later, along with a "debugging" mode). Similar to SafeStack and
StackProtector, the instrumentation pass (in a follow up change) will be
inserted in all cases, but will only affect functions marked with the
new sanitize_memtag attribute.

Reviewers: pcc, hctim, vitalybuka, ostannard

Subscribers: srhines, mehdi_amini, javed.absar, kristof.beyls, hiraditya, cryptoad, steven_wu, dexonsmith, cfe-commits, llvm-commits

Tags: #clang, #llvm

Differential Revision: https://reviews.llvm.org/D64169

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@366123 91177308-0d34-0410-b5e6-96231b3b80d8

12 files changed:
include/clang/Basic/Features.def
include/clang/Basic/Sanitizers.def
lib/CodeGen/CGDeclCXX.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/SanitizerMetadata.cpp
lib/Driver/SanitizerArgs.cpp
lib/Driver/ToolChains/Linux.cpp
test/CodeGen/memtag-attr.cpp [new file with mode: 0644]
test/Driver/fsanitize.c
test/Lexer/has_feature_memtag_sanitizer.cpp [new file with mode: 0644]
test/SemaCXX/attr-no-sanitize.cpp

index 7ab7c4d17005b669506050921fa88f5d9f29695b..7081c02e83eac9171ad11b480dde885fccdc2e57 100644 (file)
@@ -42,6 +42,7 @@ FEATURE(address_sanitizer,
 FEATURE(hwaddress_sanitizer,
         LangOpts.Sanitize.hasOneOf(SanitizerKind::HWAddress |
                                    SanitizerKind::KernelHWAddress))
+FEATURE(memtag_sanitizer, LangOpts.Sanitize.has(SanitizerKind::MemTag))
 FEATURE(xray_instrument, LangOpts.XRayInstrument)
 FEATURE(undefined_behavior_sanitizer,
         LangOpts.Sanitize.hasOneOf(SanitizerKind::Undefined))
index 1bb433a2b0e9b4028f9b7bb7457c145797ba84a7..0037cc2146f26e335bdf1e16f3cbc561aa4930f9 100644 (file)
@@ -55,6 +55,9 @@ SANITIZER("hwaddress", HWAddress)
 // Kernel Hardware-assisted AddressSanitizer (KHWASan)
 SANITIZER("kernel-hwaddress", KernelHWAddress)
 
+// A variant of AddressSanitizer using AArch64 MTE extension.
+SANITIZER("memtag", MemTag)
+
 // MemorySanitizer
 SANITIZER("memory", Memory)
 
index 1c7c6fb5413db3a937804f92f3fdff8470563211..7a0605b8450ac237d524f3f020fe831655d1d651 100644 (file)
@@ -369,6 +369,10 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrDestructFunction(
       !isInSanitizerBlacklist(SanitizerKind::KernelHWAddress, Fn, Loc))
     Fn->addFnAttr(llvm::Attribute::SanitizeHWAddress);
 
+  if (getLangOpts().Sanitize.has(SanitizerKind::MemTag) &&
+      !isInSanitizerBlacklist(SanitizerKind::MemTag, Fn, Loc))
+    Fn->addFnAttr(llvm::Attribute::SanitizeMemTag);
+
   if (getLangOpts().Sanitize.has(SanitizerKind::Thread) &&
       !isInSanitizerBlacklist(SanitizerKind::Thread, Fn, Loc))
     Fn->addFnAttr(llvm::Attribute::SanitizeThread);
index 937648700a2e8393c185eb1af46a9d3fecb0eebc..eafe26674434fd4b008c77a112511c9108f27bd4 100644 (file)
@@ -696,6 +696,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
     Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
   if (SanOpts.hasOneOf(SanitizerKind::HWAddress | SanitizerKind::KernelHWAddress))
     Fn->addFnAttr(llvm::Attribute::SanitizeHWAddress);
+  if (SanOpts.has(SanitizerKind::MemTag))
+    Fn->addFnAttr(llvm::Attribute::SanitizeMemTag);
   if (SanOpts.has(SanitizerKind::Thread))
     Fn->addFnAttr(llvm::Attribute::SanitizeThread);
   if (SanOpts.hasOneOf(SanitizerKind::Memory | SanitizerKind::KernelMemory))
index ba501d645c2c90390ba26fb90ae568ba5a297bf5..7ab960e8bcee5e1564015eed7b6c877b1ed336e4 100644 (file)
@@ -2239,9 +2239,11 @@ bool CodeGenModule::isInSanitizerBlacklist(llvm::GlobalVariable *GV,
                                            SourceLocation Loc, QualType Ty,
                                            StringRef Category) const {
   // For now globals can be blacklisted only in ASan and KASan.
-  const SanitizerMask EnabledAsanMask = LangOpts.Sanitize.Mask &
+  const SanitizerMask EnabledAsanMask =
+      LangOpts.Sanitize.Mask &
       (SanitizerKind::Address | SanitizerKind::KernelAddress |
-       SanitizerKind::HWAddress | SanitizerKind::KernelHWAddress);
+       SanitizerKind::HWAddress | SanitizerKind::KernelHWAddress |
+       SanitizerKind::MemTag);
   if (!EnabledAsanMask)
     return false;
   const auto &SanitizerBL = getContext().getSanitizerBlacklist();
index 3211a3e74d255a3aa43d180d4b0bea9bcff2889d..ebc9cd5529bc6f595fe580d6f65c613d135a4567 100644 (file)
@@ -20,14 +20,17 @@ using namespace CodeGen;
 
 SanitizerMetadata::SanitizerMetadata(CodeGenModule &CGM) : CGM(CGM) {}
 
+static bool isAsanHwasanOrMemTag(const SanitizerSet& SS) {
+  return SS.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress |
+                     SanitizerKind::HWAddress | SanitizerKind::KernelHWAddress |
+                     SanitizerKind::MemTag);
+}
+
 void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
                                            SourceLocation Loc, StringRef Name,
                                            QualType Ty, bool IsDynInit,
                                            bool IsBlacklisted) {
-  if (!CGM.getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address |
-                                           SanitizerKind::KernelAddress |
-                                           SanitizerKind::HWAddress |
-                                           SanitizerKind::KernelHWAddress))
+  if (!isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize))
     return;
   IsDynInit &= !CGM.isInSanitizerBlacklist(GV, Loc, Ty, "init");
   IsBlacklisted |= CGM.isInSanitizerBlacklist(GV, Loc, Ty);
@@ -58,10 +61,7 @@ void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
 
 void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
                                            const VarDecl &D, bool IsDynInit) {
-  if (!CGM.getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address |
-                                           SanitizerKind::KernelAddress |
-                                           SanitizerKind::HWAddress |
-                                           SanitizerKind::KernelHWAddress))
+  if (!isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize))
     return;
   std::string QualName;
   llvm::raw_string_ostream OS(QualName);
@@ -78,10 +78,7 @@ void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
 void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
   // For now, just make sure the global is not modified by the ASan
   // instrumentation.
-  if (CGM.getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address |
-                                          SanitizerKind::KernelAddress |
-                                          SanitizerKind::HWAddress |
-                                          SanitizerKind::KernelHWAddress))
+  if (isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize))
     reportGlobalToASan(GV, SourceLocation(), "", QualType(), false, true);
 }
 
index 8d4b9fc85de232a19173d13444fd277a1f3cbc14..9132faa917646f391fa28171f6cabcc4b3dcc0dc 100644 (file)
@@ -40,7 +40,8 @@ static const SanitizerMask NeedsUnwindTables =
 static const SanitizerMask SupportsCoverage =
     SanitizerKind::Address | SanitizerKind::HWAddress |
     SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress |
-    SanitizerKind::Memory | SanitizerKind::KernelMemory | SanitizerKind::Leak |
+    SanitizerKind::MemTag | SanitizerKind::Memory |
+    SanitizerKind::KernelMemory | SanitizerKind::Leak |
     SanitizerKind::Undefined | SanitizerKind::Integer |
     SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
     SanitizerKind::DataFlow | SanitizerKind::Fuzzer |
@@ -122,6 +123,7 @@ static void addDefaultBlacklists(const Driver &D, SanitizerMask Kinds,
     SanitizerMask Mask;
   } Blacklists[] = {{"asan_blacklist.txt", SanitizerKind::Address},
                     {"hwasan_blacklist.txt", SanitizerKind::HWAddress},
+                    {"memtag_blacklist.txt", SanitizerKind::MemTag},
                     {"msan_blacklist.txt", SanitizerKind::Memory},
                     {"tsan_blacklist.txt", SanitizerKind::Thread},
                     {"dfsan_abilist.txt", SanitizerKind::DataFlow},
@@ -420,7 +422,11 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
                      SanitizerKind::Address | SanitizerKind::HWAddress |
                          SanitizerKind::Leak | SanitizerKind::Thread |
                          SanitizerKind::Memory | SanitizerKind::KernelAddress |
-                         SanitizerKind::Scudo | SanitizerKind::SafeStack)};
+                         SanitizerKind::Scudo | SanitizerKind::SafeStack),
+      std::make_pair(SanitizerKind::MemTag,
+                     SanitizerKind::Address | SanitizerKind::KernelAddress |
+                         SanitizerKind::HWAddress |
+                         SanitizerKind::KernelHWAddress)};
   // Enable toolchain specific default sanitizers if not explicitly disabled.
   SanitizerMask Default = TC.getDefaultSanitizers() & ~AllRemove;
 
index b4e19b12c8d72b686f3ef0598a9543a7c253db48..d900508ad9385ac6d07decf0b7b31b602893d2f3 100644 (file)
@@ -1026,6 +1026,8 @@ SanitizerMask Linux::getSupportedSanitizers() const {
     Res |= SanitizerKind::HWAddress;
     Res |= SanitizerKind::KernelHWAddress;
   }
+  if (IsAArch64)
+    Res |= SanitizerKind::MemTag;
   return Res;
 }
 
diff --git a/test/CodeGen/memtag-attr.cpp b/test/CodeGen/memtag-attr.cpp
new file mode 100644 (file)
index 0000000..f0b0785
--- /dev/null
@@ -0,0 +1,19 @@
+// Make sure the sanitize_memtag attribute is emitted when using MemTag sanitizer.
+// Make sure __attribute__((no_sanitize("memtag")) disables instrumentation.
+
+// RUN: %clang_cc1 -triple aarch64-unknown-linux -disable-O0-optnone \
+// RUN:   -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NO %s
+
+// RUN: %clang_cc1 -triple aarch64-unknown-linux -fsanitize=memtag \
+// RUN:   -disable-O0-optnone -emit-llvm -o - %s | \
+// RUN:   FileCheck -check-prefix=CHECK-MEMTAG %s
+
+int HasSanitizeMemTag() { return 1; }
+// CHECK-NO: {{Function Attrs: noinline nounwind$}}
+// CHECK-MEMTAG: Function Attrs: noinline nounwind sanitize_memtag
+
+__attribute__((no_sanitize("memtag"))) int NoSanitizeQuoteAddress() {
+  return 0;
+}
+// CHECK-NO: {{Function Attrs: noinline nounwind$}}
+// CHECK-MEMTAG: {{Function Attrs: noinline nounwind$}}
index a275b576688e60d878b2e88b50f5981c709e70bd..01367c7e67881a5f021d3cfa2e33cf28c0170737 100644 (file)
 // RUN: %clang -target x86_64-linux-gnu -fsanitize=hwaddress,address -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANHA-SANA
 // CHECK-SANHA-SANA: '-fsanitize=hwaddress' not allowed with '-fsanitize=address'
 
+// RUN: %clang -target aarch64-linux-android -fsanitize=memtag,address -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANMT-SANA
+// CHECK-SANMT-SANA: '-fsanitize=memtag' not allowed with '-fsanitize=address'
+
+// RUN: %clang -target aarch64-linux-android -fsanitize=memtag,hwaddress -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANMT-SANHA
+// CHECK-SANMT-SANHA: '-fsanitize=memtag' not allowed with '-fsanitize=hwaddress'
+
+// RUN: %clang -target i386-linux-android -fsanitize=memtag -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANMT-BAD-ARCH
+// RUN: %clang -target x86_64-linux-android -fsanitize=memtag -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANMT-BAD-ARCH
+// CHECK-SANMT-BAD-ARCH: unsupported option '-fsanitize=memtag' for target
+
 // RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-use-after-scope %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-SCOPE
 // RUN: %clang_cl --target=x86_64-windows -fsanitize=address -fsanitize-address-use-after-scope -### -- %s 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-SCOPE
 // CHECK-USE-AFTER-SCOPE: -cc1{{.*}}-fsanitize-address-use-after-scope
diff --git a/test/Lexer/has_feature_memtag_sanitizer.cpp b/test/Lexer/has_feature_memtag_sanitizer.cpp
new file mode 100644 (file)
index 0000000..64e55d7
--- /dev/null
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -E -fsanitize=memtag %s -o - | FileCheck --check-prefix=CHECK-MEMTAG %s
+// RUN: %clang_cc1 -E  %s -o - | FileCheck --check-prefix=CHECK-NO-MEMTAG %s
+
+#if __has_feature(memtag_sanitizer)
+int MemTagSanitizerEnabled();
+#else
+int MemTagSanitizerDisabled();
+#endif
+
+// CHECK-MEMTAG: MemTagSanitizerEnabled
+// CHECK-NO-MEMTAG: MemTagSanitizerDisabled
index 02bc9a9e7f8f4bffa1f0c320403357e14a4fc530..feff7ef6163dc2095b1de6a5afecdd492c15aa95 100644 (file)
@@ -30,3 +30,8 @@ int f5() __attribute__((no_sanitize("address", "thread", "hwaddress")));
 // DUMP: NoSanitizeAttr {{.*}} unknown
 // PRINT: int f6() __attribute__((no_sanitize("unknown")))
 int f6() __attribute__((no_sanitize("unknown"))); // expected-warning{{unknown sanitizer 'unknown' ignored}}
+
+// DUMP-LABEL: FunctionDecl {{.*}} f7
+// DUMP: NoSanitizeAttr {{.*}} memtag
+// PRINT: int f7() {{\[\[}}clang::no_sanitize("memtag")]]
+[[clang::no_sanitize("memtag")]] int f7();