Skip to content

Commit

Permalink
ARM MTE stack sanitizer.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
eugenis committed Jul 15, 2019
1 parent 46513b5 commit 8060f84
Show file tree
Hide file tree
Showing 16 changed files with 71 additions and 5 deletions.
1 change: 1 addition & 0 deletions docs/BitCodeFormat.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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>`_
Expand Down
3 changes: 2 additions & 1 deletion include/llvm/Bitcode/LLVMBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 4 additions & 0 deletions include/llvm/IR/Attributes.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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>">;

Expand Down
1 change: 1 addition & 0 deletions lib/AsmParser/LLLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions lib/AsmParser/LLToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ enum Kind {
kw_argmemonly,
kw_sanitize_address,
kw_sanitize_hwaddress,
kw_sanitize_memtag,
kw_builtin,
kw_byval,
kw_inalloca,
Expand Down
8 changes: 7 additions & 1 deletion lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand All @@ -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 ||
Expand Down Expand Up @@ -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;
}
}

Expand Down
2 changes: 2 additions & 0 deletions lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions lib/IR/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
1 change: 1 addition & 0 deletions lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions lib/Transforms/IPO/ForceFunctionAttrs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions lib/Transforms/Utils/CodeExtractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
11 changes: 9 additions & 2 deletions test/Bitcode/attributes.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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 }
Expand Down Expand Up @@ -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 }
30 changes: 30 additions & 0 deletions test/Transforms/Inline/attributes.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion utils/emacs/llvm-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 8060f84

Please sign in to comment.