Skip to content

Commit

Permalink
[lldb] Remove non-address bits from addresses given to memory tag com…
Browse files Browse the repository at this point in the history
…mands

Although the memory tag commands use a memory tag manager to handle
addresses, that only removes the top byte.

That top byte is 4 bits of memory tag and 4 free bits, which is more
than it should strictly remove but that's how it is for now.

There are other non-address bit uses like pointer authentication.
To ensure the memory tag manager only has to deal with memory tags,
use the ABI plugin to remove the rest.

The tag access test has been updated to sign all the relevant pointers
and require that we're running on a system with pointer authentication
in addition to memory tagging.

The pointers will look like:
<4 bit user tag><4 bit memory tag><signature><bit virtual address>

Note that there is currently no API for reading memory tags. It will
also have to consider this when it arrives.

Reviewed By: omjavaid

Differential Revision: https://reviews.llvm.org/D117672
  • Loading branch information
DavidSpickett committed Jan 20, 2022
1 parent 585abe3 commit 787f91b
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 3 deletions.
23 changes: 22 additions & 1 deletion lldb/source/Commands/CommandObjectMemoryTag.cpp
Expand Up @@ -12,6 +12,7 @@
#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Interpreter/OptionGroupFormat.h"
#include "lldb/Interpreter/OptionValueString.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/Process.h"

using namespace lldb;
Expand Down Expand Up @@ -85,6 +86,17 @@ class CommandObjectMemoryTagRead : public CommandObjectParsed {
// If this fails the list of regions is cleared, so we don't need to read
// the return status here.
process->GetMemoryRegions(memory_regions);

lldb::addr_t logical_tag = tag_manager->GetLogicalTag(start_addr);

// The tag manager only removes tag bits. These addresses may include other
// non-address bits that must also be ignored.
ABISP abi = process->GetABI();
if (abi) {
start_addr = abi->FixDataAddress(start_addr);
end_addr = abi->FixDataAddress(end_addr);
}

llvm::Expected<MemoryTagManager::TagRange> tagged_range =
tag_manager->MakeTaggedRange(start_addr, end_addr, memory_regions);

Expand All @@ -101,7 +113,6 @@ class CommandObjectMemoryTagRead : public CommandObjectParsed {
return false;
}

lldb::addr_t logical_tag = tag_manager->GetLogicalTag(start_addr);
result.AppendMessageWithFormatv("Logical tag: {0:x}", logical_tag);
result.AppendMessage("Allocation tags:");

Expand Down Expand Up @@ -231,6 +242,12 @@ class CommandObjectMemoryTagWrite : public CommandObjectParsed {
// the return status here.
process->GetMemoryRegions(memory_regions);

// The tag manager only removes tag bits. These addresses may include other
// non-address bits that must also be ignored.
ABISP abi = process->GetABI();
if (abi)
start_addr = abi->FixDataAddress(start_addr);

// We have to assume start_addr is not granule aligned.
// So if we simply made a range:
// (start_addr, start_addr + (N * granule_size))
Expand All @@ -254,6 +271,10 @@ class CommandObjectMemoryTagWrite : public CommandObjectParsed {
end_addr =
aligned_start_addr + (tags.size() * tag_manager->GetGranuleSize());

// Remove non-address bits that aren't memory tags
if (abi)
end_addr = abi->FixDataAddress(end_addr);

// Now we've aligned the start address so if we ask for another range
// using the number of tags N, we'll get back a range that is also N
// granules in size.
Expand Down
Expand Up @@ -20,6 +20,11 @@ def setup_mte_test(self):
if not self.isAArch64MTE():
self.skipTest('Target must support MTE.')

# Required to check that commands remove non-address bits
# other than the memory tags.
if not self.isAArch64PAuth():
self.skipTest('Target must support pointer authentication')

self.build()
self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)

Expand Down
14 changes: 12 additions & 2 deletions lldb/test/API/linux/aarch64/mte_tag_access/main.c
Expand Up @@ -71,8 +71,9 @@ int main(int argc, char const *argv[]) {
// tag
char *mte_buf_alt_tag = __arm_mte_create_random_tag(mte_buf, ~(1 << 10));

// lldb should be removing the whole top byte, not just the tags.
// So fill 63-60 with something non zero so we'll fail if we only remove tags.
// The memory tag manager should be removing the whole top byte, not just the
// tags. So fill 63-60 with something non zero so we'll fail if we only remove
// tags.
#define SET_TOP_NIBBLE(ptr, value) \
(char *)((size_t)(ptr) | ((size_t)((value)&0xf) << 60))
// mte_buf_alt_tag's nibble > mte_buf to check that lldb isn't just removing
Expand All @@ -82,6 +83,15 @@ int main(int argc, char const *argv[]) {
mte_buf_2 = SET_TOP_NIBBLE(mte_buf_2, 0xC);
mte_read_only = SET_TOP_NIBBLE(mte_read_only, 0xD);

// The top level commands should be removing all non-address bits, including
// pointer signatures. This signs ptr with PAC key A. That signature goes
// in some bits other than the top byte.
#define sign_ptr(ptr) __asm__ __volatile__("pacdza %0" : "=r"(ptr) : "r"(ptr))
sign_ptr(mte_buf);
sign_ptr(mte_buf_alt_tag);
sign_ptr(mte_buf_2);
sign_ptr(mte_read_only);

// Breakpoint here
return 0;
}

0 comments on commit 787f91b

Please sign in to comment.