diff options
Diffstat (limited to 'lldb/test/API/macosx')
-rw-r--r-- | lldb/test/API/macosx/mte/Makefile | 12 | ||||
-rw-r--r-- | lldb/test/API/macosx/mte/TestDarwinMTE.py | 110 | ||||
-rw-r--r-- | lldb/test/API/macosx/mte/main.c | 28 | ||||
-rw-r--r-- | lldb/test/API/macosx/mte/mte-entitlements.plist | 10 |
4 files changed, 160 insertions, 0 deletions
diff --git a/lldb/test/API/macosx/mte/Makefile b/lldb/test/API/macosx/mte/Makefile new file mode 100644 index 0000000..cb20942 --- /dev/null +++ b/lldb/test/API/macosx/mte/Makefile @@ -0,0 +1,12 @@ +C_SOURCES := main.c + +EXE := uaf_mte + +all: uaf_mte sign + +include Makefile.rules + +sign: mte-entitlements.plist uaf_mte +ifeq ($(OS),Darwin) + codesign -s - -f --entitlements $^ +endif diff --git a/lldb/test/API/macosx/mte/TestDarwinMTE.py b/lldb/test/API/macosx/mte/TestDarwinMTE.py new file mode 100644 index 0000000..ef858b1 --- /dev/null +++ b/lldb/test/API/macosx/mte/TestDarwinMTE.py @@ -0,0 +1,110 @@ +"""Test MTE Memory Tagging on Apple platforms""" + +import lldb +import re +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import lldbsuite.test.cpu_feature as cpu_feature + +exe_name = "uaf_mte" # Must match Makefile + + +class TestDarwinMTE(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + @skipUnlessFeature(cpu_feature.AArch64.MTE) + def test_tag_fault(self): + self.build() + exe = self.getBuildArtifact(exe_name) + + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + process = target.LaunchSimple(None, None, None) + self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED) + + self.expect( + "thread info", + substrs=[ + "stop reason = EXC_ARM_MTE_TAG_FAULT", + "MTE tag mismatch detected", + ], + ) + + @skipUnlessFeature(cpu_feature.AArch64.MTE) + def test_memory_region(self): + self.build() + lldbutil.run_to_source_breakpoint( + self, "// before free", lldb.SBFileSpec("main.c"), exe_name=exe_name + ) + + # (lldb) memory region ptr + # [0x00000001005ec000-0x00000001009ec000) rw- + # memory tagging: enabled + # Modified memory (dirty) page list provided, 2 entries. + # Dirty pages: 0x1005ec000, 0x1005fc000. + self.expect("memory region ptr", substrs=["memory tagging: enabled"]) + + @skipUnlessFeature(cpu_feature.AArch64.MTE) + def test_memory_read_with_tags(self): + self.build() + lldbutil.run_to_source_breakpoint( + self, "// before free", lldb.SBFileSpec("main.c"), exe_name=exe_name + ) + + # (lldb) memory read ptr-16 ptr+48 --show-tags + # 0x7d2c00930: 00 00 00 00 00 00 00 00 d0 e3 a5 0a 02 00 00 00 ................ (tag: 0x3) + # 0x7d2c00940: 48 65 6c 6c 6f 00 00 00 00 00 00 00 00 00 00 00 Hello........... (tag: 0xb) + # 0x7d2c00950: 57 6f 72 6c 64 00 00 00 00 00 00 00 00 00 00 00 World........... (tag: 0xb) + # 0x7d2c00960: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ (tag: 0x9) + self.expect( + "memory read ptr-16 ptr+48 --show-tags", + substrs=[" Hello...........", " World..........."], + patterns=[r"(.*\(tag: 0x[0-9a-f]\)\n){4}"], + ) + + def _parse_pointer_tag(self, output): + return re.search(r"Logical tag: (0x[0-9a-f])", output).group(1) + + def _parse_memory_tags(self, output, expected_tag_count): + tags = re.findall(r"\): (0x[0-9a-f])", output) + self.assertEqual(len(tags), expected_tag_count) + return tags + + @skipUnlessFeature(cpu_feature.AArch64.MTE) + def test_memory_tag_read(self): + self.build() + lldbutil.run_to_source_breakpoint( + self, "// before free", lldb.SBFileSpec("main.c"), exe_name=exe_name + ) + + # (lldb) memory tag read ptr-1 ptr+33 + # Logical tag: 0x5 + # Allocation tags: + # [0x100a65a40, 0x100a65a50): 0xf (mismatch) + # [0x100a65a50, 0x100a65a60): 0x5 + # [0x100a65a60, 0x100a65a70): 0x5 + # [0x100a65a70, 0x100a65a80): 0x2 (mismatch) + self.expect( + "memory tag read ptr-1 ptr+33", + substrs=["Logical tag: 0x", "Allocation tags:", "(mismatch)"], + patterns=[r"(\[.*\): 0x[0-9a-f].*\n){4}"], + ) + output = self.res.GetOutput() + self.assertEqual(output.count("(mismatch)"), 2) + ptr_tag = self._parse_pointer_tag(output) + tags = self._parse_memory_tags(output, 4) + self.assertEqual(tags[1], ptr_tag) + self.assertEqual(tags[2], ptr_tag) + self.assertNotEqual(tags[0], ptr_tag) # Memory that comes before/after + self.assertNotEqual(tags[3], ptr_tag) # allocation has different tag. + + # Continue running until MTE fault + self.expect("process continue", substrs=["stop reason = EXC_ARM_MTE_TAG_FAULT"]) + + self.runCmd("memory tag read ptr-1 ptr+33") + output = self.res.GetOutput() + self.assertEqual(output.count("(mismatch)"), 4) + tags = self._parse_memory_tags(output, 4) + self.assertTrue(all(t != ptr_tag for t in tags)) diff --git a/lldb/test/API/macosx/mte/main.c b/lldb/test/API/macosx/mte/main.c new file mode 100644 index 0000000..f9f6b15 --- /dev/null +++ b/lldb/test/API/macosx/mte/main.c @@ -0,0 +1,28 @@ +#include <malloc/malloc.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// Produce some names on the trace +const size_t tag_granule = 16; +static uint8_t *my_malloc(void) { return malloc(2 * tag_granule); } +static uint8_t *allocate(void) { return my_malloc(); } + +static void my_free(void *ptr) { free(ptr); } +static void deallocate(void *ptr) { my_free(ptr); } + +static void touch_memory(uint8_t *ptr) { ptr[7] = 1; } // invalid access +static void modify(uint8_t *ptr) { touch_memory(ptr); } + +int main() { + uint8_t *ptr = allocate(); + + strncpy((char *)ptr, "Hello", 16); + strncpy((char *)ptr + 16, "World", 16); + + deallocate(ptr); // before free + + modify(ptr); // use-after-free + + return 0; +} diff --git a/lldb/test/API/macosx/mte/mte-entitlements.plist b/lldb/test/API/macosx/mte/mte-entitlements.plist new file mode 100644 index 0000000..6de5d56 --- /dev/null +++ b/lldb/test/API/macosx/mte/mte-entitlements.plist @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>com.apple.security.hardened-process</key> + <true/> + <key>com.apple.security.hardened-process.checked-allocations</key> + <true/> +</dict> +</plist> |