[MTE] Add NT_ANDROID_TYPE_MEMTAG

This ELF note is aarch64 and Android-specific. It specifies to the
dynamic loader that specific work should be scheduled to enable MTE
protection of stack and heap regions.

Current synthesis of the ".note.android.memtag" ELF note is done in the
Android build system. We'd like to move that to the compiler, and this
is the first step.

Reviewed By: MaskRay, jhenderson

Differential Revision: https://reviews.llvm.org/D119381
This commit is contained in:
Mitch Phillips 2022-03-03 10:48:05 -08:00
parent 845bfcede1
commit 73df82572a
5 changed files with 223 additions and 0 deletions

View File

@ -1559,6 +1559,31 @@ enum {
NT_GNU_PROPERTY_TYPE_0 = 5,
};
// Android note types.
enum {
NT_ANDROID_TYPE_IDENT = 1,
NT_ANDROID_TYPE_KUSER = 3,
NT_ANDROID_TYPE_MEMTAG = 4,
};
// Memory tagging values used in NT_ANDROID_TYPE_MEMTAG notes.
enum {
// Enumeration to determine the tagging mode. In Android-land, 'SYNC' means
// running all threads in MTE Synchronous mode, and 'ASYNC' means to use the
// kernels auto-upgrade feature to allow for either MTE Asynchronous,
// Asymmetric, or Synchronous mode. This allows silicon vendors to specify, on
// a per-cpu basis what 'ASYNC' should mean. Generally, the expectation is
// "pick the most precise mode that's very fast".
NT_MEMTAG_LEVEL_NONE = 0,
NT_MEMTAG_LEVEL_ASYNC = 1,
NT_MEMTAG_LEVEL_SYNC = 2,
NT_MEMTAG_LEVEL_MASK = 3,
// Bits indicating whether the loader should prepare for MTE to be enabled on
// the heap and/or stack.
NT_MEMTAG_HEAP = 4,
NT_MEMTAG_STACK = 8,
};
// Property types used in GNU_PROPERTY_TYPE_0 notes.
enum : unsigned {
GNU_PROPERTY_STACK_SIZE = 1,

View File

@ -177,6 +177,10 @@ void ScalarEnumerationTraits<ELFYAML::ELF_NT>::enumeration(
ECase(NT_AMD_PAL_METADATA);
// AMDGPU specific notes. (Code Object V3)
ECase(NT_AMDGPU_METADATA);
// Android specific notes.
ECase(NT_ANDROID_TYPE_IDENT);
ECase(NT_ANDROID_TYPE_KUSER);
ECase(NT_ANDROID_TYPE_MEMTAG);
#undef ECase
IO.enumFallback<Hex32>(Value);
}

View File

@ -0,0 +1,80 @@
# RUN: yaml2obj -D DESC='0d000000' %s -o %t
# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-OK,ASYNC,HEAP,STACK
# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,ASYNC,HEAP,STACK
# RUN: yaml2obj -D DESC='0e000000' %s -o %t
# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-OK,SYNC,HEAP,STACK
# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,SYNC,HEAP,STACK
# RUN: yaml2obj -D DESC='05000000' %s -o %t
# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-OK,ASYNC,HEAP,NOSTACK
# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,ASYNC,HEAP,NOSTACK
# RUN: yaml2obj -D DESC='06000000' %s -o %t
# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-OK,SYNC,HEAP,NOSTACK
# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,SYNC,HEAP,NOSTACK
# RUN: yaml2obj -D DESC='09000000' %s -o %t
# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-OK,ASYNC,NOHEAP,STACK
# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,ASYNC,NOHEAP,STACK
# RUN: yaml2obj -D DESC='0a000000' %s -o %t
# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-OK,SYNC,NOHEAP,STACK
# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,SYNC,NOHEAP,STACK
# RUN: yaml2obj -D DESC='03000000' %s -o %t
# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-OK,UNKNOWN,NOHEAP,NOSTACK
# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,UNKNOWN,NOHEAP,NOSTACK
# RUN: yaml2obj -D DESC='00000000' %s -o %t
# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-OK,NONE,NOHEAP,NOSTACK
# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,NONE,NOHEAP,NOSTACK
# RUN: yaml2obj -D DESC='""' %s -o %t
# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-BAD,INVALID
# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-BAD,INVALID
# GNU: Displaying notes found in: .note.android.memtag
# GNU-NEXT: Owner Data size Description
# GNU-OK-NEXT: Android 0x00000004 NT_ANDROID_TYPE_MEMTAG (Android memory tagging information)
# GNU-BAD-NEXT: Android 0x00000000 NT_ANDROID_TYPE_MEMTAG (Android memory tagging information)
# LLVM: Notes [
# LLVM-NEXT: NoteSection {
# LLVM-NEXT: Name: .note.android.memtag
# LLVM-NEXT: Offset: 0x40
# LLVM-OK-NEXT: Size: 0x18
# LLVM-BAD-NEXT: Size: 0x14
# LLVM-NEXT: Note {
# LLVM-NEXT: Owner: Android
# LLVM-OK-NEXT: Data size: 0x4
# LLVM-BAD-NEXT: Data size: 0x0
# LLVM-NEXT: Type: NT_ANDROID_TYPE_MEMTAG (Android memory tagging information)
## Hint: Also used for the GNU tests.
# INVALID-NEXT: Invalid .note.android.memtag
# NONE-NEXT: Tagging Mode: NONE
# ASYNC-NEXT: Tagging Mode: ASYNC
# SYNC-NEXT: Tagging Mode: SYNC
# UNKNOWN-NEXT: Tagging Mode: Unknown (3)
# HEAP-NEXT: Heap: Enabled
# NOHEAP-NEXT: Heap: Disabled
# STACK-NEXT: Stack: Enabled
# NOSTACK-NEXT: Stack: Disabled
# LLVM-NEXT: }
# LLVM-NEXT: }
# LLVM-NEXT: ]
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Sections:
- Name: .note.android.memtag
Type: SHT_NOTE
Notes:
- Name: Android
Type: NT_ANDROID_TYPE_MEMTAG
Desc: [[DESC]]

View File

@ -0,0 +1,37 @@
# RUN: yaml2obj %s -o %t
# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU
# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM
# GNU: Displaying notes found in: .note.android.unknown
# GNU-NEXT: Owner Data size Description
# GNU-NEXT: Android 0x00000005 Unknown note type: (0x00001337)
# GNU-NEXT: description data: 01 23 45 67 89
# LLVM: Notes [
# LLVM-NEXT: NoteSection {
# LLVM-NEXT: Name: .note.android.unknown
# LLVM-NEXT: Offset: 0x40
# LLVM-NEXT: Size: 0x1C
# LLVM-NEXT: Note {
# LLVM-NEXT: Owner: Android
# LLVM-NEXT: Data size: 0x5
# LLVM-NEXT: Type: Unknown (0x00001337)
# LLVM-NEXT: Description data (
# LLVM-NEXT: 0000: 01234567 89
# LLVM-NEXT: )
# LLVM-NEXT: }
# LLVM-NEXT: }
# LLVM-NEXT: ]
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Sections:
- Name: .note.android.unknown
Type: SHT_NOTE
Notes:
- Name: Android
Type: 0x1337
Desc: 0123456789

View File

@ -5066,6 +5066,57 @@ static bool printGNUNote(raw_ostream &OS, uint32_t NoteType,
return true;
}
using AndroidNoteProperties = std::vector<std::pair<StringRef, std::string>>;
static AndroidNoteProperties getAndroidNoteProperties(uint32_t NoteType,
ArrayRef<uint8_t> Desc) {
AndroidNoteProperties Props;
switch (NoteType) {
case ELF::NT_ANDROID_TYPE_MEMTAG:
if (Desc.empty()) {
Props.emplace_back("Invalid .note.android.memtag", "");
return Props;
}
switch (Desc[0] & NT_MEMTAG_LEVEL_MASK) {
case NT_MEMTAG_LEVEL_NONE:
Props.emplace_back("Tagging Mode", "NONE");
break;
case NT_MEMTAG_LEVEL_ASYNC:
Props.emplace_back("Tagging Mode", "ASYNC");
break;
case NT_MEMTAG_LEVEL_SYNC:
Props.emplace_back("Tagging Mode", "SYNC");
break;
default:
Props.emplace_back(
"Tagging Mode",
("Unknown (" + Twine::utohexstr(Desc[0] & NT_MEMTAG_LEVEL_MASK) + ")")
.str());
break;
}
Props.emplace_back("Heap",
(Desc[0] & NT_MEMTAG_HEAP) ? "Enabled" : "Disabled");
Props.emplace_back("Stack",
(Desc[0] & NT_MEMTAG_STACK) ? "Enabled" : "Disabled");
break;
default:
return Props;
}
return Props;
}
static bool printAndroidNote(raw_ostream &OS, uint32_t NoteType,
ArrayRef<uint8_t> Desc) {
// Return true if we were able to pretty-print the note, false otherwise.
AndroidNoteProperties Props = getAndroidNoteProperties(NoteType, Desc);
if (Props.empty())
return false;
for (const auto &KV : Props)
OS << " " << KV.first << ": " << KV.second << '\n';
OS << '\n';
return true;
}
template <typename ELFT>
static bool printLLVMOMPOFFLOADNote(raw_ostream &OS, uint32_t NoteType,
ArrayRef<uint8_t> Desc) {
@ -5425,6 +5476,13 @@ const NoteType LLVMOMPOFFLOADNoteTypes[] = {
"NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION (producing toolchain version)"},
};
const NoteType AndroidNoteTypes[] = {
{ELF::NT_ANDROID_TYPE_IDENT, "NT_ANDROID_TYPE_IDENT"},
{ELF::NT_ANDROID_TYPE_KUSER, "NT_ANDROID_TYPE_KUSER"},
{ELF::NT_ANDROID_TYPE_MEMTAG,
"NT_ANDROID_TYPE_MEMTAG (Android memory tagging information)"},
};
const NoteType CoreNoteTypes[] = {
{ELF::NT_PRSTATUS, "NT_PRSTATUS (prstatus structure)"},
{ELF::NT_FPREGSET, "NT_FPREGSET (floating point registers)"},
@ -5533,6 +5591,8 @@ StringRef getNoteTypeName(const typename ELFT::Note &Note, unsigned ELFType) {
return FindNote(AMDGPUNoteTypes);
if (Name == "LLVMOMPOFFLOAD")
return FindNote(LLVMOMPOFFLOADNoteTypes);
if (Name == "Android")
return FindNote(AndroidNoteTypes);
if (ELFType == ELF::ET_CORE)
return FindNote(CoreNoteTypes);
@ -5683,6 +5743,9 @@ template <class ELFT> void GNUELFDumper<ELFT>::printNotes() {
return NoteOrErr.takeError();
}
}
} else if (Name == "Android") {
if (printAndroidNote(OS, Type, Descriptor))
return Error::success();
}
if (!Descriptor.empty()) {
OS << " description data:";
@ -7050,6 +7113,17 @@ static bool printGNUNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc,
return true;
}
static bool printAndroidNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc,
ScopedPrinter &W) {
// Return true if we were able to pretty-print the note, false otherwise.
AndroidNoteProperties Props = getAndroidNoteProperties(NoteType, Desc);
if (Props.empty())
return false;
for (const auto &KV : Props)
W.printString(KV.first, KV.second);
return true;
}
template <typename ELFT>
static bool printLLVMOMPOFFLOADNoteLLVMStyle(uint32_t NoteType,
ArrayRef<uint8_t> Desc,
@ -7152,6 +7226,9 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printNotes() {
return N.takeError();
}
}
} else if (Name == "Android") {
if (printAndroidNoteLLVMStyle(Type, Descriptor, W))
return Error::success();
}
if (!Descriptor.empty()) {
W.printBinaryBlock("Description data", Descriptor);