This is an archive of the discontinued LLVM Phabricator instance.

[MTE] Add NT_ANDROID_TYPE_MEMTAG
ClosedPublic

Authored by hctim on Feb 9 2022, 3:26 PM.

Details

Summary

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.

Diff Detail

Event Timeline

hctim created this revision.Feb 9 2022, 3:26 PM
hctim requested review of this revision.Feb 9 2022, 3:26 PM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 9 2022, 3:26 PM
hctim updated this revision to Diff 407326.Feb 9 2022, 3:46 PM

Buggered up the endianness.

jhenderson added inline comments.Feb 10 2022, 12:54 AM
llvm/include/llvm/BinaryFormat/ELF.h
1564–1565

I guess the 2 value isn't used?

1574–1575

I guess values 5-7 aren't used?

llvm/test/tools/llvm-readobj/ELF/AArch64/memtag/aarch64-note-memtag-all-async.test
1 ↗(On Diff #407326)

Up to you, but I think it would be better to fold these tests into a single test case. You can then reduce duplication of the YAML in one of two ways - either by just having one of each note in the note section, or by using yaml2obj -D options to parameterise the YAML doc. There are plenty of examples of the latter in the llvm-readobj tests.

My comments in this test file also apply to the other files, if there's a strong motivation to keep them separate.

5 ↗(On Diff #407326)

Nit: make things line up neatly to slightly improve readability.

34–35 ↗(On Diff #407326)

We tend to remove excessive spacing in YAML, keeping values within the same block lined up vertically, at the minimum indentation.

llvm/tools/llvm-readobj/ELFDumper.cpp
5074–5075

It's probably necessary to have a test case that triggers this return false.

5077–5078

Ditto.

5091–5094

Needs test case for this label.

7117–7118

This and the GNU function are very similar structurally, which makes me think there's an opportunity for some code reuse here. If I'm not mistaken, the only difference is how these strings are printed? Could you have a helper function which returns a set of strings that are then passed to the corresponding print functions? I'm thinking something like the following sketch:

using std::unordered_map<StringRef, std::string> AndroidNoteProperties;
static Optional<AndroidNoteProperties> getAndroidNoteProperties(uint32_t NoteType, ArrayRef<uint8_t> Desc) {
  // Return None if we were unable to get the note properties.
  AndroidNoteProperties Props;
  switch (NoteType) {
  default:
     return None;
  case ELF::NT_ANDROID_TYPE_MEMTAG:
    if (Desc.empty())
      return None;

    switch (Desc[0] & NT_MEMTAG_LEVEL_MASK) {
    case NT_MEMTAG_LEVEL_NONE:
      Props["Tagging Mode"] = "NONE";
      break;
    case NT_MEMTAG_LEVEL_ASYNC:
      Props["Tagging Mode"] = "ASYNC";
      break;
    case NT_MEMTAG_LEVEL_SYNC:
      Props["Tagging Mode"] = "SYNC";
      break;
    default:
      Props["Tagging Mode"] =
          ("Unknown (" + Twine::utohexstr(Desc[0] & NT_MEMTAG_LEVEL_MASK) + ")")
              .str();
      break;
    }
    Props["Heap"] = (Desc[0] & NT_MEMTAG_HEAP) ? "Enabled" : "Disabled");
    Props["Stack"] = (Desc[0] & NT_MEMTAG_STACK) ? "Enabled" : "Disabled");
  }
  return Props;
}

template <typename ELFT>
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.
  Optional<AndroidNoteProperties> Props = getAndroidNoteProperties(NoteType, Desc);
  if (!Props)
    return false;
  for(const auto &KV : Props)
    W.printString(KV.first, KV.second);
}

I don't know if the map will be general enough for future notes, but at least for this memtag note it certainly is. If we need to support other types, there may be a better structure, but I suggest waiting until then to worry about it.

hctim marked 9 inline comments as done.Feb 14 2022, 11:14 AM
hctim added inline comments.
llvm/include/llvm/BinaryFormat/ELF.h
1564–1565
1574–1575

NT_MEMTAG_LEVEL_* are enum values, any NT_MEMTAG_HEAP/STACK are bitsets. Added some clarifying comments.

hctim updated this revision to Diff 408521.Feb 14 2022, 11:17 AM
hctim marked 2 inline comments as done.

Addressing comments.

jhenderson added inline comments.Feb 15 2022, 12:00 AM
llvm/test/tools/llvm-readobj/ELF/AArch64/memtag/aarch64-note-android-memtag.test
1 ↗(On Diff #408521)

You can drop "aarch64" from the test file names, since you're in the AArch64 folder. Probably also can drop "memtag", although I'd be more inclined to get rid of the subdirectory now, as there aren't that many(?) memtag tests now.

80 ↗(On Diff #408521)

You should be able to do this and then omit "Desc: " from the -D values in the yaml2obj runs.

hctim marked 2 inline comments as done.Feb 15 2022, 11:25 AM
hctim added inline comments.
llvm/test/tools/llvm-readobj/ELF/AArch64/memtag/aarch64-note-android-memtag.test
80 ↗(On Diff #408521)

yaml2obj complained about Desc: \n when testing for INVALID (i.e. we don't want any description bytes), so I materialized the entire line as a -D parameter instead :).

hctim updated this revision to Diff 408976.Feb 15 2022, 11:25 AM
hctim marked an inline comment as done.

Changed paths for tests.

jhenderson added inline comments.Feb 16 2022, 12:23 AM
llvm/test/tools/llvm-readobj/ELF/AArch64/memtag/aarch64-note-android-memtag.test
80 ↗(On Diff #408521)

yaml2obj complained about Desc: \n when testing for INVALID (i.e. we don't want any description bytes), so I materialized the entire line as a -D parameter instead :).

llvm/test/tools/llvm-readobj/ELF/AArch64/note-android-memtag.test
81

yaml2obj complained about Desc: \n when testing for INVALID (i.e. we don't want any description bytes), so I materialized the entire line as a -D parameter instead :).

Ah, I missed that you omitted Desc entirely in the last case. For that case, you just need to provide empty quotes, I believe. The final YAML would look like Desc: ''. Of course, this means you'll need to do something about escaping the quotes on the lit commandline. An alternative approach is using the "<none>" approach, although I don't know if that works for the Desc field. See llvm/test/tools/yaml2obj/ELF/none-value.yaml for example usage: essentially, "<none>" set as the default value (i.e. [[DESC=<none>]]) means that the field is treated as not specified if a macro value is not provided on the command-line.

hctim marked an inline comment as done.Feb 16 2022, 9:28 AM
hctim added inline comments.
llvm/test/tools/llvm-readobj/ELF/AArch64/note-android-memtag.test
81

done, thanks for the "" pointer

hctim updated this revision to Diff 409298.Feb 16 2022, 9:28 AM
hctim marked an inline comment as done.

~

jhenderson accepted this revision.Feb 16 2022, 9:30 AM

Looks good from my point of view, but it might be worth seeing if someone with Android experience is able to review those details.

This revision is now accepted and ready to land.Feb 16 2022, 9:30 AM

(+rprichard for android)

MaskRay accepted this revision.Feb 16 2022, 11:45 AM

Let's wait for @rprichard.

llvm/tools/llvm-readobj/ELFDumper.cpp
5116

operator<<(char) compiles to less code.

hctim updated this revision to Diff 410658.Feb 22 2022, 3:16 PM
hctim marked an inline comment as done.

Use operator<<(char)

hctim added a comment.Feb 22 2022, 3:17 PM

Friendly ping @rprichard. For reference, I've been using this during development of MTE globals, and it synthesizes notes correctly for the (still WIP) patches: https://android-review.googlesource.com/c/platform/bionic/+/1845896

llvm/tools/llvm-readobj/ELFDumper.cpp
5116

neat trick!

Yeah, I'm OK with this change. (I'm not really familiar with the MTE stuff.)

Herald added a project: Restricted Project. · View Herald TranscriptMar 2 2022, 3:37 PM
This revision was landed with ongoing or failed builds.Mar 7 2022, 11:29 AM
This revision was automatically updated to reflect the committed changes.