Skip to content

Commit 433c820

Browse files
committed
Add test for Darwin MTE support
Add test for Darwin MTE support which covers support for custom tag fault message and reading memory tags via `memory tag read`.
1 parent 5927388 commit 433c820

File tree

5 files changed

+142
-1
lines changed

5 files changed

+142
-1
lines changed

lldb/packages/Python/lldbsuite/test/cpu_feature.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def _is_supported_darwin(self, cmd_runner):
6262
class AArch64:
6363
FPMR = CPUFeature("fpmr")
6464
GCS = CPUFeature("gcs")
65-
MTE = CPUFeature("mte")
65+
MTE = CPUFeature("mte", "hw.optional.arm.FEAT_MTE4")
6666
MTE_STORE_ONLY = CPUFeature("mtestoreonly")
6767
PTR_AUTH = CPUFeature("paca", "hw.optional.arm.FEAT_PAuth2")
6868
SME = CPUFeature("sme", "hw.optional.arm.FEAT_SME")

lldb/test/API/macosx/mte/Makefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
C_SOURCES := main.c
2+
3+
EXE := uaf_mte
4+
5+
all: uaf_mte sign
6+
7+
include Makefile.rules
8+
9+
sign: mte-entitlements.plist uaf_mte
10+
ifeq ($(OS),Darwin)
11+
codesign -s - -f --entitlements $^
12+
endif
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"""Test MTE Memory Tagging on Apple platforms"""
2+
3+
import lldb
4+
import re
5+
from lldbsuite.test.decorators import *
6+
from lldbsuite.test.lldbtest import *
7+
from lldbsuite.test import lldbutil
8+
import lldbsuite.test.cpu_feature as cpu_feature
9+
10+
exe_name = "uaf_mte" # Must match Makefile
11+
12+
13+
class TestDarwinMTE(TestBase):
14+
NO_DEBUG_INFO_TESTCASE = True
15+
16+
@skipUnlessFeature(cpu_feature.AArch64.MTE)
17+
def test_tag_fault(self):
18+
self.build()
19+
exe = self.getBuildArtifact(exe_name)
20+
21+
target = self.dbg.CreateTarget(exe)
22+
self.assertTrue(target, VALID_TARGET)
23+
24+
process = target.LaunchSimple(None, None, None)
25+
self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
26+
27+
self.expect(
28+
"thread info",
29+
substrs=["stop reason = EXC_ARM_MTE_TAG_FAULT", "MTE tag mismatch detected"],
30+
)
31+
32+
@skipUnlessFeature(cpu_feature.AArch64.MTE)
33+
def test_memory_read_with_tags(self):
34+
self.build()
35+
lldbutil.run_to_source_breakpoint(
36+
self, "// before free", lldb.SBFileSpec("main.c"), exe_name=exe_name
37+
)
38+
39+
# (lldb) memory read ptr-16 ptr+48 --show-tags
40+
# 0x7d2c00930: 00 00 00 00 00 00 00 00 d0 e3 a5 0a 02 00 00 00 ................ (tag: 0x3)
41+
# 0x7d2c00940: 48 65 6c 6c 6f 00 00 00 00 00 00 00 00 00 00 00 Hello........... (tag: 0xb)
42+
# 0x7d2c00950: 57 6f 72 6c 64 00 00 00 00 00 00 00 00 00 00 00 World........... (tag: 0xb)
43+
# 0x7d2c00960: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ (tag: 0x9)
44+
self.expect(
45+
"memory read ptr-16 ptr+48 --show-tags",
46+
substrs=[" Hello...........", " World..........."],
47+
patterns=[r"(.*\(tag: 0x[0-9a-f]\)\n){4}"])
48+
49+
def _parse_pointer_tag(self):
50+
return re.search(r"Logical tag: (0x[0-9a-f])", self.res.GetOutput()).group(1)
51+
52+
def _parse_memory_tags(self, expected_tag_count):
53+
tags = re.findall(r"\): (0x[0-9a-f])", self.res.GetOutput())
54+
self.assertEqual(len(tags), expected_tag_count)
55+
return tags
56+
57+
@skipUnlessFeature(cpu_feature.AArch64.MTE)
58+
def test_memory_tag_read(self):
59+
self.build()
60+
lldbutil.run_to_source_breakpoint(
61+
self, "// before free", lldb.SBFileSpec("main.c"), exe_name=exe_name
62+
)
63+
64+
# (lldb) memory tag read ptr-1 ptr+33
65+
# Logical tag: 0x5
66+
# Allocation tags:
67+
# [0x100a65a40, 0x100a65a50): 0xf (mismatch)
68+
# [0x100a65a50, 0x100a65a60): 0x5
69+
# [0x100a65a60, 0x100a65a70): 0x5
70+
# [0x100a65a70, 0x100a65a80): 0x2 (mismatch)
71+
self.expect(
72+
"memory tag read ptr-1 ptr+33",
73+
substrs=["Logical tag: 0x", "Allocation tags:", "(mismatch)"],
74+
patterns=[r"(\[.*\): 0x[0-9a-f].*\n){4}"]
75+
)
76+
self.assertEqual(self.res.GetOutput().count("(mismatch)"), 2)
77+
ptr_tag = self._parse_pointer_tag()
78+
tags = self._parse_memory_tags(4)
79+
self.assertEqual(tags[1], ptr_tag)
80+
self.assertEqual(tags[2], ptr_tag)
81+
self.assertNotEqual(tags[0], ptr_tag)
82+
self.assertNotEqual(tags[3], ptr_tag)
83+
84+
# Continue running until MTE fault
85+
self.runCmd("process continue")
86+
87+
self.runCmd("memory tag read ptr-1 ptr+33")
88+
self.assertEqual(self.res.GetOutput().count("(mismatch)"), 4)
89+
tags = self._parse_memory_tags(4)
90+
self.assertTrue(all(t != ptr_tag for t in tags))

lldb/test/API/macosx/mte/main.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <malloc/malloc.h>
2+
#include <stdio.h>
3+
#include <stdlib.h>
4+
#include <string.h>
5+
6+
// Produce some names on the trace
7+
const size_t tag_granule = 16;
8+
uint8_t *my_malloc(void) { return malloc(2 * tag_granule); }
9+
uint8_t *allocate(void) { return my_malloc(); }
10+
11+
void my_free(void *ptr) { free(ptr); }
12+
void deallocate(void *ptr) { my_free(ptr); }
13+
14+
void touch_memory(uint8_t *ptr) { ptr[7] = 1; } // invalid access
15+
void modify(uint8_t *ptr) { touch_memory(ptr); }
16+
17+
int main() {
18+
uint8_t *ptr = allocate();
19+
printf("ptr: %p\n", ptr);
20+
21+
strcpy((char *)ptr, "Hello");
22+
strcpy((char *)ptr+16, "World");
23+
24+
deallocate(ptr); // before free
25+
26+
modify(ptr); // use-after-free
27+
28+
return 0;
29+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>com.apple.security.hardened-process</key>
6+
<true/>
7+
<key>com.apple.security.hardened-process.checked-allocations</key>
8+
<true/>
9+
</dict>
10+
</plist>

0 commit comments

Comments
 (0)