1 | #include <arm_acle.h> |
2 | #include <asm/hwcap.h> |
3 | #include <linux/mman.h> |
4 | #include <stdio.h> |
5 | #include <sys/auxv.h> |
6 | #include <sys/mman.h> |
7 | #include <sys/prctl.h> |
8 | #include <unistd.h> |
9 | |
10 | int print_result(char *ptr) { |
11 | // Page size allows the test to try reading off of the end of the page |
12 | printf(format: "buffer: %p page_size: 0x%x\n" , ptr, sysconf(_SC_PAGESIZE)); |
13 | |
14 | // Exit after some time, so we don't leave a zombie process |
15 | // if the test framework lost track of us. |
16 | sleep(seconds: 60); |
17 | return 0; |
18 | } |
19 | |
20 | int main(int argc, char const *argv[]) { |
21 | if (prctl(PR_SET_TAGGED_ADDR_CTRL, |
22 | PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC | |
23 | // Allow all tags to be generated by the addg |
24 | // instruction __arm_mte_increment_tag produces. |
25 | (0xffff << PR_MTE_TAG_SHIFT), |
26 | 0, 0, 0)) { |
27 | return print_result(NULL); |
28 | } |
29 | |
30 | size_t page_size = sysconf(_SC_PAGESIZE); |
31 | char *buf = mmap(addr: 0, len: page_size, PROT_READ | PROT_WRITE | PROT_MTE, |
32 | MAP_PRIVATE | MAP_ANONYMOUS, fd: -1, offset: 0); |
33 | if (buf == MAP_FAILED) |
34 | return print_result(NULL); |
35 | |
36 | // Set incrementing tags until end of the page |
37 | char *tagged_ptr = buf; |
38 | // This intrinsic treats the addresses as if they were untagged |
39 | while (__arm_mte_ptrdiff(tagged_ptr, buf) < page_size) { |
40 | // This sets the allocation tag |
41 | __arm_mte_set_tag(tagged_ptr); |
42 | // Set the tag of the next granule (hence +16) to the next |
43 | // tag value. Returns a new pointer with the new logical tag. |
44 | // Tag values wrap at 0xF so it'll cycle. |
45 | tagged_ptr = __arm_mte_increment_tag(tagged_ptr + 16, 1); |
46 | } |
47 | |
48 | // lldb-server should be removing the top byte from addresses passed |
49 | // to ptrace. So put some random bits in there. |
50 | // ptrace expects you to remove them but it can still succeed if you |
51 | // don't. So this isn't proof that we're removing them, it's just a |
52 | // smoke test in case something didn't account for them. |
53 | buf = (char *)((size_t)buf | ((size_t)0xAA << 56)); |
54 | return print_result(ptr: buf); |
55 | } |
56 | |