1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

ARM MTE stack sanitizer.

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

llvm-svn: 366123
This commit is contained in:
Evgeniy Stepanov 2019-07-15 20:02:23 +00:00
parent d2c4211aac
commit e8363137ea
16 changed files with 71 additions and 5 deletions

View File

@ -1057,6 +1057,7 @@ The integer codes are mapped to well-known attributes as follows.
* code 56: ``nocf_check`` * code 56: ``nocf_check``
* code 57: ``optforfuzzing`` * code 57: ``optforfuzzing``
* code 58: ``shadowcallstack`` * code 58: ``shadowcallstack``
* code 64: ``sanitize_memtag``
.. note:: .. note::
The ``allocsize`` attribute has a special encoding for its arguments. Its two The ``allocsize`` attribute has a special encoding for its arguments. Its two

View File

@ -1681,6 +1681,10 @@ example:
This attribute indicates that HWAddressSanitizer checks This attribute indicates that HWAddressSanitizer checks
(dynamic address safety analysis based on tagged pointers) are enabled for (dynamic address safety analysis based on tagged pointers) are enabled for
this function. 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`` ``speculative_load_hardening``
This attribute indicates that This attribute indicates that
`Speculative Load Hardening <https://llvm.org/docs/SpeculativeLoadHardening.html>`_ `Speculative Load Hardening <https://llvm.org/docs/SpeculativeLoadHardening.html>`_

View File

@ -630,7 +630,8 @@ enum AttributeKindCodes {
ATTR_KIND_IMMARG = 60, ATTR_KIND_IMMARG = 60,
ATTR_KIND_WILLRETURN = 61, ATTR_KIND_WILLRETURN = 61,
ATTR_KIND_NOFREE = 62, ATTR_KIND_NOFREE = 62,
ATTR_KIND_NOSYNC = 63 ATTR_KIND_NOSYNC = 63,
ATTR_KIND_SANITIZE_MEMTAG = 64,
}; };
enum ComdatSelectionKindCodes { enum ComdatSelectionKindCodes {

View File

@ -185,6 +185,9 @@ def SanitizeMemory : EnumAttr<"sanitize_memory">;
/// HWAddressSanitizer is on. /// HWAddressSanitizer is on.
def SanitizeHWAddress : EnumAttr<"sanitize_hwaddress">; def SanitizeHWAddress : EnumAttr<"sanitize_hwaddress">;
/// MemTagSanitizer is on.
def SanitizeMemTag : EnumAttr<"sanitize_memtag">;
/// Speculative Load Hardening is enabled. /// Speculative Load Hardening is enabled.
/// ///
/// Note that this uses the default compatibility (always compatible during /// 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<SanitizeThreadAttr>">;
def : CompatRule<"isEqual<SanitizeMemoryAttr>">; def : CompatRule<"isEqual<SanitizeMemoryAttr>">;
def : CompatRule<"isEqual<SanitizeHWAddressAttr>">; def : CompatRule<"isEqual<SanitizeHWAddressAttr>">;
def : CompatRule<"isEqual<SanitizeMemTagAttr>">;
def : CompatRule<"isEqual<SafeStackAttr>">; def : CompatRule<"isEqual<SafeStackAttr>">;
def : CompatRule<"isEqual<ShadowCallStackAttr>">; def : CompatRule<"isEqual<ShadowCallStackAttr>">;

View File

@ -679,6 +679,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(shadowcallstack); KEYWORD(shadowcallstack);
KEYWORD(sanitize_address); KEYWORD(sanitize_address);
KEYWORD(sanitize_hwaddress); KEYWORD(sanitize_hwaddress);
KEYWORD(sanitize_memtag);
KEYWORD(sanitize_thread); KEYWORD(sanitize_thread);
KEYWORD(sanitize_memory); KEYWORD(sanitize_memory);
KEYWORD(speculative_load_hardening); KEYWORD(speculative_load_hardening);

View File

@ -1311,6 +1311,8 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
B.addAttribute(Attribute::SanitizeAddress); break; B.addAttribute(Attribute::SanitizeAddress); break;
case lltok::kw_sanitize_hwaddress: case lltok::kw_sanitize_hwaddress:
B.addAttribute(Attribute::SanitizeHWAddress); break; B.addAttribute(Attribute::SanitizeHWAddress); break;
case lltok::kw_sanitize_memtag:
B.addAttribute(Attribute::SanitizeMemTag); break;
case lltok::kw_sanitize_thread: case lltok::kw_sanitize_thread:
B.addAttribute(Attribute::SanitizeThread); break; B.addAttribute(Attribute::SanitizeThread); break;
case lltok::kw_sanitize_memory: case lltok::kw_sanitize_memory:
@ -1668,6 +1670,7 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
case lltok::kw_returns_twice: case lltok::kw_returns_twice:
case lltok::kw_sanitize_address: case lltok::kw_sanitize_address:
case lltok::kw_sanitize_hwaddress: case lltok::kw_sanitize_hwaddress:
case lltok::kw_sanitize_memtag:
case lltok::kw_sanitize_memory: case lltok::kw_sanitize_memory:
case lltok::kw_sanitize_thread: case lltok::kw_sanitize_thread:
case lltok::kw_speculative_load_hardening: case lltok::kw_speculative_load_hardening:
@ -1766,6 +1769,7 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) {
case lltok::kw_returns_twice: case lltok::kw_returns_twice:
case lltok::kw_sanitize_address: case lltok::kw_sanitize_address:
case lltok::kw_sanitize_hwaddress: case lltok::kw_sanitize_hwaddress:
case lltok::kw_sanitize_memtag:
case lltok::kw_sanitize_memory: case lltok::kw_sanitize_memory:
case lltok::kw_sanitize_thread: case lltok::kw_sanitize_thread:
case lltok::kw_speculative_load_hardening: case lltok::kw_speculative_load_hardening:

View File

@ -176,6 +176,7 @@ enum Kind {
kw_argmemonly, kw_argmemonly,
kw_sanitize_address, kw_sanitize_address,
kw_sanitize_hwaddress, kw_sanitize_hwaddress,
kw_sanitize_memtag,
kw_builtin, kw_builtin,
kw_byval, kw_byval,
kw_inalloca, kw_inalloca,

View File

@ -1296,6 +1296,9 @@ static uint64_t getRawAttributeMask(Attribute::AttrKind Val) {
case Attribute::AllocSize: case Attribute::AllocSize:
llvm_unreachable("allocsize not supported in raw format"); llvm_unreachable("allocsize not supported in raw format");
break; break;
case Attribute::SanitizeMemTag:
llvm_unreachable("sanitize_memtag attribute not supported in raw format");
break;
} }
llvm_unreachable("Unsupported attribute type"); 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; for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds;
I = Attribute::AttrKind(I + 1)) { I = Attribute::AttrKind(I + 1)) {
if (I == Attribute::Dereferenceable || if (I == Attribute::SanitizeMemTag ||
I == Attribute::Dereferenceable ||
I == Attribute::DereferenceableOrNull || I == Attribute::DereferenceableOrNull ||
I == Attribute::ArgMemOnly || I == Attribute::ArgMemOnly ||
I == Attribute::AllocSize || I == Attribute::AllocSize ||
@ -1534,6 +1538,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::ZExt; return Attribute::ZExt;
case bitc::ATTR_KIND_IMMARG: case bitc::ATTR_KIND_IMMARG:
return Attribute::ImmArg; return Attribute::ImmArg;
case bitc::ATTR_KIND_SANITIZE_MEMTAG:
return Attribute::SanitizeMemTag;
} }
} }

View File

@ -723,6 +723,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_Z_EXT; return bitc::ATTR_KIND_Z_EXT;
case Attribute::ImmArg: case Attribute::ImmArg:
return bitc::ATTR_KIND_IMMARG; return bitc::ATTR_KIND_IMMARG;
case Attribute::SanitizeMemTag:
return bitc::ATTR_KIND_SANITIZE_MEMTAG;
case Attribute::EndAttrKinds: case Attribute::EndAttrKinds:
llvm_unreachable("Can not encode end-attribute kinds marker."); llvm_unreachable("Can not encode end-attribute kinds marker.");
case Attribute::None: case Attribute::None:

View File

@ -283,6 +283,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return "sanitize_address"; return "sanitize_address";
if (hasAttribute(Attribute::SanitizeHWAddress)) if (hasAttribute(Attribute::SanitizeHWAddress))
return "sanitize_hwaddress"; return "sanitize_hwaddress";
if (hasAttribute(Attribute::SanitizeMemTag))
return "sanitize_memtag";
if (hasAttribute(Attribute::AlwaysInline)) if (hasAttribute(Attribute::AlwaysInline))
return "alwaysinline"; return "alwaysinline";
if (hasAttribute(Attribute::ArgMemOnly)) if (hasAttribute(Attribute::ArgMemOnly))

View File

@ -1516,6 +1516,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) {
case Attribute::ReturnsTwice: case Attribute::ReturnsTwice:
case Attribute::SanitizeAddress: case Attribute::SanitizeAddress:
case Attribute::SanitizeHWAddress: case Attribute::SanitizeHWAddress:
case Attribute::SanitizeMemTag:
case Attribute::SanitizeThread: case Attribute::SanitizeThread:
case Attribute::SanitizeMemory: case Attribute::SanitizeMemory:
case Attribute::MinSize: case Attribute::MinSize:

View File

@ -57,6 +57,7 @@ static Attribute::AttrKind parseAttrKind(StringRef Kind) {
.Case("sanitize_hwaddress", Attribute::SanitizeHWAddress) .Case("sanitize_hwaddress", Attribute::SanitizeHWAddress)
.Case("sanitize_memory", Attribute::SanitizeMemory) .Case("sanitize_memory", Attribute::SanitizeMemory)
.Case("sanitize_thread", Attribute::SanitizeThread) .Case("sanitize_thread", Attribute::SanitizeThread)
.Case("sanitize_memtag", Attribute::SanitizeMemTag)
.Case("speculative_load_hardening", Attribute::SpeculativeLoadHardening) .Case("speculative_load_hardening", Attribute::SpeculativeLoadHardening)
.Case("ssp", Attribute::StackProtect) .Case("ssp", Attribute::StackProtect)
.Case("sspreq", Attribute::StackProtectReq) .Case("sspreq", Attribute::StackProtectReq)

View File

@ -850,6 +850,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
case Attribute::SanitizeMemory: case Attribute::SanitizeMemory:
case Attribute::SanitizeThread: case Attribute::SanitizeThread:
case Attribute::SanitizeHWAddress: case Attribute::SanitizeHWAddress:
case Attribute::SanitizeMemTag:
case Attribute::SpeculativeLoadHardening: case Attribute::SpeculativeLoadHardening:
case Attribute::StackProtect: case Attribute::StackProtect:
case Attribute::StackProtectReq: case Attribute::StackProtectReq:

View File

@ -204,7 +204,7 @@ define void @f34()
; CHECK: define void @f34() ; CHECK: define void @f34()
{ {
call void @nobuiltin() nobuiltin call void @nobuiltin() nobuiltin
; CHECK: call void @nobuiltin() #39 ; CHECK: call void @nobuiltin() #40
ret void; ret void;
} }
@ -368,6 +368,12 @@ define void @f62() nosync
ret void ret void
} }
; CHECK: define void @f63() #39
define void @f63() sanitize_memtag
{
ret void;
}
; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #0 = { noreturn }
; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #1 = { nounwind }
; CHECK: attributes #2 = { readnone } ; CHECK: attributes #2 = { readnone }
@ -407,4 +413,5 @@ define void @f62() nosync
; CHECK: attributes #36 = { willreturn } ; CHECK: attributes #36 = { willreturn }
; CHECK: attributes #37 = { nofree } ; CHECK: attributes #37 = { nofree }
; CHECK: attributes #38 = { nosync } ; CHECK: attributes #38 = { nosync }
; CHECK: attributes #39 = { nobuiltin } ; CHECK: attributes #39 = { sanitize_memtag }
; CHECK: attributes #40 = { nobuiltin }

View File

@ -22,6 +22,10 @@ define i32 @sanitize_memory_callee(i32 %i) sanitize_memory {
ret i32 %i ret i32 %i
} }
define i32 @sanitize_memtag_callee(i32 %i) sanitize_memtag {
ret i32 %i
}
define i32 @safestack_callee(i32 %i) safestack { define i32 @safestack_callee(i32 %i) safestack {
ret i32 %i ret i32 %i
} }
@ -50,6 +54,10 @@ define i32 @alwaysinline_sanitize_memory_callee(i32 %i) alwaysinline sanitize_me
ret i32 %i 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 { define i32 @alwaysinline_safestack_callee(i32 %i) alwaysinline safestack {
ret i32 %i ret i32 %i
} }
@ -104,6 +112,17 @@ define i32 @test_no_sanitize_thread(i32 %arg) {
; CHECK-NEXT: ret i32 ; 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: ; Check that:
; * noattr callee is not inlined into sanitize_(address|memory|thread) caller, ; * 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 ; 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 { define i32 @test_safestack(i32 %arg) safestack {
%x1 = call i32 @noattr_callee(i32 %arg) %x1 = call i32 @noattr_callee(i32 %arg)
%x2 = call i32 @safestack_callee(i32 %x1) %x2 = call i32 @safestack_callee(i32 %x1)

View File

@ -26,7 +26,7 @@
"inaccessiblemem_or_argmemonly" "inlinehint" "jumptable" "minsize" "naked" "nobuiltin" "inaccessiblemem_or_argmemonly" "inlinehint" "jumptable" "minsize" "naked" "nobuiltin"
"noduplicate" "noimplicitfloat" "noinline" "nonlazybind" "noredzone" "noreturn" "noduplicate" "noimplicitfloat" "noinline" "nonlazybind" "noredzone" "noreturn"
"norecurse" "nounwind" "optnone" "optsize" "readnone" "readonly" "returns_twice" "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) "sanitize_thread" "sanitize_memory" "strictfp" "uwtable" "writeonly" "immarg") 'symbols) . font-lock-constant-face)
;; Variables ;; Variables
'("%[-a-zA-Z$._][-a-zA-Z$._0-9]*" . font-lock-variable-name-face) '("%[-a-zA-Z$._][-a-zA-Z$._0-9]*" . font-lock-variable-name-face)