]> granicus.if.org Git - llvm/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/llvm/trunk@366123 91177308-0d34-0410-b5e6-96231b3b80d8

16 files changed:
docs/BitCodeFormat.rst
docs/LangRef.rst
include/llvm/Bitcode/LLVMBitCodes.h
include/llvm/IR/Attributes.td
lib/AsmParser/LLLexer.cpp
lib/AsmParser/LLParser.cpp
lib/AsmParser/LLToken.h
lib/Bitcode/Reader/BitcodeReader.cpp
lib/Bitcode/Writer/BitcodeWriter.cpp
lib/IR/Attributes.cpp
lib/IR/Verifier.cpp
lib/Transforms/IPO/ForceFunctionAttrs.cpp
lib/Transforms/Utils/CodeExtractor.cpp
test/Bitcode/attributes.ll
test/Transforms/Inline/attributes.ll
utils/emacs/llvm-mode.el

index 5e1c5cacb439cbc9aa6d88dc2921a98fe5e0c156..4e653ae55d5359f498f59d69a422f0d409fabe49 100644 (file)
@@ -1057,6 +1057,7 @@ The integer codes are mapped to well-known attributes as follows.
 * code 56: ``nocf_check``
 * code 57: ``optforfuzzing``
 * code 58: ``shadowcallstack``
+* code 64: ``sanitize_memtag``
 
 .. note::
   The ``allocsize`` attribute has a special encoding for its arguments. Its two
index 18f760d9b05001f0f807bf735a8f6b048794e570..87e8a557504a28da65bc7413f39f599b2137cd9e 100644 (file)
@@ -1681,6 +1681,10 @@ example:
     This attribute indicates that HWAddressSanitizer checks
     (dynamic address safety analysis based on tagged pointers) are enabled for
     this function.
+``sanitize_memtag``
+    This attribute indicates that MemTagSanitizer checks
+    (dynamic address safety analysis based on Armv8 MTE) are enabled for
+    this function.
 ``speculative_load_hardening``
     This attribute indicates that
     `Speculative Load Hardening <https://llvm.org/docs/SpeculativeLoadHardening.html>`_
index 4582a6a4d83d66e82f8f5ea0964a52173958317f..decd4dd3a9659621b4be6c28ae78ee26c631e3b5 100644 (file)
@@ -630,7 +630,8 @@ enum AttributeKindCodes {
   ATTR_KIND_IMMARG = 60,
   ATTR_KIND_WILLRETURN = 61,
   ATTR_KIND_NOFREE = 62,
-  ATTR_KIND_NOSYNC = 63
+  ATTR_KIND_NOSYNC = 63,
+  ATTR_KIND_SANITIZE_MEMTAG = 64,
 };
 
 enum ComdatSelectionKindCodes {
index a549f3059002870e8e1222ea8b130a9facb7b3cc..153046d2311c85fed8d7b7d5bcf5ca0cdfb5c6d6 100644 (file)
@@ -185,6 +185,9 @@ def SanitizeMemory : EnumAttr<"sanitize_memory">;
 /// HWAddressSanitizer is on.
 def SanitizeHWAddress : EnumAttr<"sanitize_hwaddress">;
 
+/// MemTagSanitizer is on.
+def SanitizeMemTag : EnumAttr<"sanitize_memtag">;
+
 /// Speculative Load Hardening is enabled.
 ///
 /// Note that this uses the default compatibility (always compatible during
@@ -233,6 +236,7 @@ def : CompatRule<"isEqual<SanitizeAddressAttr>">;
 def : CompatRule<"isEqual<SanitizeThreadAttr>">;
 def : CompatRule<"isEqual<SanitizeMemoryAttr>">;
 def : CompatRule<"isEqual<SanitizeHWAddressAttr>">;
+def : CompatRule<"isEqual<SanitizeMemTagAttr>">;
 def : CompatRule<"isEqual<SafeStackAttr>">;
 def : CompatRule<"isEqual<ShadowCallStackAttr>">;
 
index 2c2361a6abc617f40f96f7d21e0c32d03d84c339..72d2357c293338dfdc7eb444ecfbe8eb14745611 100644 (file)
@@ -679,6 +679,7 @@ lltok::Kind LLLexer::LexIdentifier() {
   KEYWORD(shadowcallstack);
   KEYWORD(sanitize_address);
   KEYWORD(sanitize_hwaddress);
+  KEYWORD(sanitize_memtag);
   KEYWORD(sanitize_thread);
   KEYWORD(sanitize_memory);
   KEYWORD(speculative_load_hardening);
index ce8c1c4fc81888eb599868a9e51590a2ec0b4faf..87dff6468f2d065acea967f1408d64218d829f07 100644 (file)
@@ -1311,6 +1311,8 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
       B.addAttribute(Attribute::SanitizeAddress); break;
     case lltok::kw_sanitize_hwaddress:
       B.addAttribute(Attribute::SanitizeHWAddress); break;
+    case lltok::kw_sanitize_memtag:
+      B.addAttribute(Attribute::SanitizeMemTag); break;
     case lltok::kw_sanitize_thread:
       B.addAttribute(Attribute::SanitizeThread); break;
     case lltok::kw_sanitize_memory:
@@ -1668,6 +1670,7 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
     case lltok::kw_returns_twice:
     case lltok::kw_sanitize_address:
     case lltok::kw_sanitize_hwaddress:
+    case lltok::kw_sanitize_memtag:
     case lltok::kw_sanitize_memory:
     case lltok::kw_sanitize_thread:
     case lltok::kw_speculative_load_hardening:
@@ -1766,6 +1769,7 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) {
     case lltok::kw_returns_twice:
     case lltok::kw_sanitize_address:
     case lltok::kw_sanitize_hwaddress:
+    case lltok::kw_sanitize_memtag:
     case lltok::kw_sanitize_memory:
     case lltok::kw_sanitize_thread:
     case lltok::kw_speculative_load_hardening:
index 4afe8a6c084c159e9edd8c85c575d615d97531a7..0e9ba4db474276954104155add72b391d918f334 100644 (file)
@@ -176,6 +176,7 @@ enum Kind {
   kw_argmemonly,
   kw_sanitize_address,
   kw_sanitize_hwaddress,
+  kw_sanitize_memtag,
   kw_builtin,
   kw_byval,
   kw_inalloca,
index 6cad3b94e5e74b67ad92e16abf6e92966c3fea96..29dc7f616392907bd7ebe68ba99f79e26e03cab4 100644 (file)
@@ -1296,6 +1296,9 @@ static uint64_t getRawAttributeMask(Attribute::AttrKind Val) {
   case Attribute::AllocSize:
     llvm_unreachable("allocsize not supported in raw format");
     break;
+  case Attribute::SanitizeMemTag:
+    llvm_unreachable("sanitize_memtag attribute not supported in raw format");
+    break;
   }
   llvm_unreachable("Unsupported attribute type");
 }
@@ -1305,7 +1308,8 @@ static void addRawAttributeValue(AttrBuilder &B, uint64_t Val) {
 
   for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds;
        I = Attribute::AttrKind(I + 1)) {
-    if (I == Attribute::Dereferenceable ||
+    if (I == Attribute::SanitizeMemTag ||
+        I == Attribute::Dereferenceable ||
         I == Attribute::DereferenceableOrNull ||
         I == Attribute::ArgMemOnly ||
         I == Attribute::AllocSize ||
@@ -1534,6 +1538,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
     return Attribute::ZExt;
   case bitc::ATTR_KIND_IMMARG:
     return Attribute::ImmArg;
+  case bitc::ATTR_KIND_SANITIZE_MEMTAG:
+    return Attribute::SanitizeMemTag;
   }
 }
 
index a23b44f4751613bb29a8084908ae057fd328378c..5c7b970a3a751d6e57d01491ecf9c46771ff7360 100644 (file)
@@ -723,6 +723,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
     return bitc::ATTR_KIND_Z_EXT;
   case Attribute::ImmArg:
     return bitc::ATTR_KIND_IMMARG;
+  case Attribute::SanitizeMemTag:
+    return bitc::ATTR_KIND_SANITIZE_MEMTAG;
   case Attribute::EndAttrKinds:
     llvm_unreachable("Can not encode end-attribute kinds marker.");
   case Attribute::None:
index 1ba703bb14c7628bba69fdd776447521ba29581a..bb90bcd7dd7482b39a17136435dec7963d708264 100644 (file)
@@ -283,6 +283,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
     return "sanitize_address";
   if (hasAttribute(Attribute::SanitizeHWAddress))
     return "sanitize_hwaddress";
+  if (hasAttribute(Attribute::SanitizeMemTag))
+    return "sanitize_memtag";
   if (hasAttribute(Attribute::AlwaysInline))
     return "alwaysinline";
   if (hasAttribute(Attribute::ArgMemOnly))
index cee5bf7dc8dd4144fcb25b4dca6175724f7120bb..9346c8bda75dd64c1ddec372be9d614de3eb0ff0 100644 (file)
@@ -1516,6 +1516,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) {
   case Attribute::ReturnsTwice:
   case Attribute::SanitizeAddress:
   case Attribute::SanitizeHWAddress:
+  case Attribute::SanitizeMemTag:
   case Attribute::SanitizeThread:
   case Attribute::SanitizeMemory:
   case Attribute::MinSize:
index cd1fc3798201fb465df2e7a0eb13e35115409c8d..b38cb6d0ed3f94a5fb108f597c71ee18a4f11ab2 100644 (file)
@@ -57,6 +57,7 @@ static Attribute::AttrKind parseAttrKind(StringRef Kind) {
       .Case("sanitize_hwaddress", Attribute::SanitizeHWAddress)
       .Case("sanitize_memory", Attribute::SanitizeMemory)
       .Case("sanitize_thread", Attribute::SanitizeThread)
+      .Case("sanitize_memtag", Attribute::SanitizeMemTag)
       .Case("speculative_load_hardening", Attribute::SpeculativeLoadHardening)
       .Case("ssp", Attribute::StackProtect)
       .Case("sspreq", Attribute::StackProtectReq)
index da137da8f7b157d39435ba204d25fb3bc9aa861a..fa6d3f8ae8738042f4414a3e02c9277a64026d71 100644 (file)
@@ -850,6 +850,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
       case Attribute::SanitizeMemory:
       case Attribute::SanitizeThread:
       case Attribute::SanitizeHWAddress:
+      case Attribute::SanitizeMemTag:
       case Attribute::SpeculativeLoadHardening:
       case Attribute::StackProtect:
       case Attribute::StackProtectReq:
index c6e146791d89899b8b887e02476e545ff71b10b9..03a98a58ef0eed3a0c64b3e76603f971f19d0971 100644 (file)
@@ -204,7 +204,7 @@ define void @f34()
 ; CHECK: define void @f34()
 {
   call void @nobuiltin() nobuiltin
-; CHECK: call void @nobuiltin() #39
+; CHECK: call void @nobuiltin() #40
         ret void;
 }
 
@@ -368,6 +368,12 @@ define void @f62() nosync
   ret void
 }
 
+; CHECK: define void @f63() #39
+define void @f63() sanitize_memtag
+{
+  ret void;
+}
+
 ; CHECK: attributes #0 = { noreturn }
 ; CHECK: attributes #1 = { nounwind }
 ; CHECK: attributes #2 = { readnone }
@@ -407,4 +413,5 @@ define void @f62() nosync
 ; CHECK: attributes #36 = { willreturn }
 ; CHECK: attributes #37 = { nofree }
 ; CHECK: attributes #38 = { nosync }
-; CHECK: attributes #39 = { nobuiltin }
+; CHECK: attributes #39 = { sanitize_memtag }
+; CHECK: attributes #40 = { nobuiltin }
index 028f3b0f1978368c8b2c3e239b485f38ce665ea7..81c189a3c7a70f34b324e2956f9ef85969484081 100644 (file)
@@ -22,6 +22,10 @@ define i32 @sanitize_memory_callee(i32 %i) sanitize_memory {
   ret i32 %i
 }
 
+define i32 @sanitize_memtag_callee(i32 %i) sanitize_memtag {
+  ret i32 %i
+}
+
 define i32 @safestack_callee(i32 %i) safestack {
   ret i32 %i
 }
@@ -50,6 +54,10 @@ define i32 @alwaysinline_sanitize_memory_callee(i32 %i) alwaysinline sanitize_me
   ret i32 %i
 }
 
+define i32 @alwaysinline_sanitize_memtag_callee(i32 %i) alwaysinline sanitize_memtag {
+  ret i32 %i
+}
+
 define i32 @alwaysinline_safestack_callee(i32 %i) alwaysinline safestack {
   ret i32 %i
 }
@@ -104,6 +112,17 @@ define i32 @test_no_sanitize_thread(i32 %arg) {
 ; CHECK-NEXT: ret i32
 }
 
+define i32 @test_no_sanitize_memtag(i32 %arg) {
+  %x1 = call i32 @noattr_callee(i32 %arg)
+  %x2 = call i32 @sanitize_memtag_callee(i32 %x1)
+  %x3 = call i32 @alwaysinline_callee(i32 %x2)
+  %x4 = call i32 @alwaysinline_sanitize_memtag_callee(i32 %x3)
+  ret i32 %x4
+; CHECK-LABEL: @test_no_sanitize_memtag(
+; CHECK-NEXT: @sanitize_memtag_callee
+; CHECK-NEXT: ret i32
+}
+
 
 ; Check that:
 ;  * noattr callee is not inlined into sanitize_(address|memory|thread) caller,
@@ -154,6 +173,17 @@ define i32 @test_sanitize_thread(i32 %arg) sanitize_thread {
 ; CHECK-NEXT: ret i32
 }
 
+define i32 @test_sanitize_memtag(i32 %arg) sanitize_memtag {
+  %x1 = call i32 @noattr_callee(i32 %arg)
+  %x2 = call i32 @sanitize_memtag_callee(i32 %x1)
+  %x3 = call i32 @alwaysinline_callee(i32 %x2)
+  %x4 = call i32 @alwaysinline_sanitize_memtag_callee(i32 %x3)
+  ret i32 %x4
+; CHECK-LABEL: @test_sanitize_memtag(
+; CHECK-NEXT: @noattr_callee
+; CHECK-NEXT: ret i32
+}
+
 define i32 @test_safestack(i32 %arg) safestack {
   %x1 = call i32 @noattr_callee(i32 %arg)
   %x2 = call i32 @safestack_callee(i32 %x1)
index c4a1b1f02bfa7c08ac5880e78c6020282f2d4880..73b02763d0166d3aa6d08d2766768f05bd4ef8c5 100644 (file)
@@ -26,7 +26,7 @@
          "inaccessiblemem_or_argmemonly" "inlinehint" "jumptable" "minsize" "naked" "nobuiltin"
          "noduplicate" "noimplicitfloat" "noinline" "nonlazybind" "noredzone" "noreturn"
          "norecurse" "nounwind" "optnone" "optsize" "readnone" "readonly" "returns_twice"
-         "speculatable" "ssp" "sspreq" "sspstrong" "safestack" "sanitize_address" "sanitize_hwaddress"
+         "speculatable" "ssp" "sspreq" "sspstrong" "safestack" "sanitize_address" "sanitize_hwaddress" "sanitize_memtag"
          "sanitize_thread" "sanitize_memory" "strictfp" "uwtable" "writeonly" "immarg") 'symbols) . font-lock-constant-face)
    ;; Variables
    '("%[-a-zA-Z$._][-a-zA-Z$._0-9]*" . font-lock-variable-name-face)