1*4d495c6eSApple OSS Distributions #if __arm64__ 2*4d495c6eSApple OSS Distributions #include <arm_acle.h> 3*4d495c6eSApple OSS Distributions #include <darwintest.h> 4*4d495c6eSApple OSS Distributions #include <mach/mach.h> 5*4d495c6eSApple OSS Distributions #include <mach/vm_map.h> 6*4d495c6eSApple OSS Distributions #include <mach/mach_vm.h> 7*4d495c6eSApple OSS Distributions #include <sys/mman.h> 8*4d495c6eSApple OSS Distributions #include <spawn.h> 9*4d495c6eSApple OSS Distributions #include <unistd.h> 10*4d495c6eSApple OSS Distributions #include <stdlib.h> 11*4d495c6eSApple OSS Distributions #include <assert.h> 12*4d495c6eSApple OSS Distributions #include <stdio.h> 13*4d495c6eSApple OSS Distributions #include <sys/ptrace.h> 14*4d495c6eSApple OSS Distributions #include <fcntl.h> 15*4d495c6eSApple OSS Distributions 16*4d495c6eSApple OSS Distributions #include "arm_mte_utilities.h" 17*4d495c6eSApple OSS Distributions #include "test_utils.h" 18*4d495c6eSApple OSS Distributions 19*4d495c6eSApple OSS Distributions T_GLOBAL_META( 20*4d495c6eSApple OSS Distributions T_META_NAMESPACE("xnu.vm"), 21*4d495c6eSApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"), 22*4d495c6eSApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("VM"), 23*4d495c6eSApple OSS Distributions T_META_ENABLED(true), 24*4d495c6eSApple OSS Distributions XNU_T_META_SOC_SPECIFIC 25*4d495c6eSApple OSS Distributions ); 26*4d495c6eSApple OSS Distributions 27*4d495c6eSApple OSS Distributions /* 28*4d495c6eSApple OSS Distributions * Processes which explicitly declare themselves as being unsafe to receive untagged aliases to tagged memory 29*4d495c6eSApple OSS Distributions * are killed by the system when the system conspires to grant them an untagged alias. 30*4d495c6eSApple OSS Distributions * This test ensure that processes that opt into restrictions on aliasing tagged memory may not receive aliases: 31*4d495c6eSApple OSS Distributions * we launch a binary signed with an ID hard-coded into AMFI to opt in to this restriction, then attempt 32*4d495c6eSApple OSS Distributions * to remap tagged memory into this target. 33*4d495c6eSApple OSS Distributions */ 34*4d495c6eSApple OSS Distributions T_DECL(process_with_alias_restricted_opt_in_cannot_receive_mte_alias, 35*4d495c6eSApple OSS Distributions "Ensure a process which opts in to alias restrictions may not receive " 36*4d495c6eSApple OSS Distributions "an alias to tagged memory, and that an attempt to do so triggers a fatal guard.", 37*4d495c6eSApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("hw.optional.arm.FEAT_MTE4", 1), 38*4d495c6eSApple OSS Distributions XNU_T_META_SOC_SPECIFIC) { 39*4d495c6eSApple OSS Distributions /* 40*4d495c6eSApple OSS Distributions * Given a binary signed in such a way that it should never be allowed to 41*4d495c6eSApple OSS Distributions * receive aliases to untagged memory from elsewhere on the system. 42*4d495c6eSApple OSS Distributions */ 43*4d495c6eSApple OSS Distributions 44*4d495c6eSApple OSS Distributions /* And we fork() so that we can observe the eventual SIGKILL */ 45*4d495c6eSApple OSS Distributions expect_sigkill(^{ 46*4d495c6eSApple OSS Distributions /* When we create some tagged memory in our context */ 47*4d495c6eSApple OSS Distributions mach_vm_address_t address = 0; 48*4d495c6eSApple OSS Distributions mach_vm_size_t size = PAGE_SIZE; 49*4d495c6eSApple OSS Distributions kern_return_t kr = mach_vm_allocate(mach_task_self(), &address, size, VM_FLAGS_ANYWHERE | VM_FLAGS_MTE); 50*4d495c6eSApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "allocate MTE memory"); 51*4d495c6eSApple OSS Distributions 52*4d495c6eSApple OSS Distributions /* And we spawn the process which is not allowed to receive aliases to tagged memory */ 53*4d495c6eSApple OSS Distributions pid_t target_pid; 54*4d495c6eSApple OSS Distributions char* target_argv[] = {"arm_mte_alias_restriction_helper", NULL}; 55*4d495c6eSApple OSS Distributions int ret = posix_spawn(&target_pid, target_argv[0], NULL, NULL, target_argv, NULL); 56*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_ZERO(ret, "posix_spawn(%s)", target_argv[0]); 57*4d495c6eSApple OSS Distributions T_ASSERT_NE(target_pid, 0, "posix_spawn(%s)", target_argv[0]); 58*4d495c6eSApple OSS Distributions 59*4d495c6eSApple OSS Distributions /* And we fetch a task port for the target */ 60*4d495c6eSApple OSS Distributions task_port_t target_task_port; 61*4d495c6eSApple OSS Distributions kr = task_for_pid(mach_task_self(), target_pid, &target_task_port); 62*4d495c6eSApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "task_for_pid for target"); 63*4d495c6eSApple OSS Distributions 64*4d495c6eSApple OSS Distributions /* When we attempt to remap the tagged memory into the target */ 65*4d495c6eSApple OSS Distributions mach_vm_address_t remap_addr = 0; 66*4d495c6eSApple OSS Distributions vm_prot_t curprot = VM_PROT_WRITE | VM_PROT_READ; 67*4d495c6eSApple OSS Distributions vm_prot_t maxprot = VM_PROT_WRITE | VM_PROT_READ; 68*4d495c6eSApple OSS Distributions kr = mach_vm_remap_new(target_task_port, &remap_addr, size, 69*4d495c6eSApple OSS Distributions /* mask = */ 0, VM_FLAGS_ANYWHERE, mach_task_self(), address, 70*4d495c6eSApple OSS Distributions /* copy = */ FALSE, &curprot, &maxprot, VM_INHERIT_DEFAULT); 71*4d495c6eSApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "remap tagged memory"); 72*4d495c6eSApple OSS Distributions if (kr != KERN_SUCCESS) { 73*4d495c6eSApple OSS Distributions fprintf(stderr, "failed to remap tagged memory\n"); 74*4d495c6eSApple OSS Distributions exit(1); 75*4d495c6eSApple OSS Distributions } 76*4d495c6eSApple OSS Distributions 77*4d495c6eSApple OSS Distributions /* And we wire the memory in the target to trigger the policy check */ 78*4d495c6eSApple OSS Distributions mach_port_t host_priv = HOST_PRIV_NULL; 79*4d495c6eSApple OSS Distributions kr = host_get_host_priv_port(mach_host_self(), &host_priv); \ 80*4d495c6eSApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "host_get_host_priv_port"); 81*4d495c6eSApple OSS Distributions kr = mach_vm_wire(host_priv, target_task_port, remap_addr, size, VM_PROT_READ | VM_PROT_WRITE); 82*4d495c6eSApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "mach_vm_wire in target"); 83*4d495c6eSApple OSS Distributions 84*4d495c6eSApple OSS Distributions /* Then the system should have killed the actor that attempted to enter this memory */ 85*4d495c6eSApple OSS Distributions T_FAIL("Expected the system to prevent us from receiving an alias to tagged memory"); 86*4d495c6eSApple OSS Distributions }, "Attempt to map an untagged alias to tagged memory in a restricted receiver"); 87*4d495c6eSApple OSS Distributions } 88*4d495c6eSApple OSS Distributions 89*4d495c6eSApple OSS Distributions T_DECL(vm_update_pointers_with_remote_tags_without_debugger, 90*4d495c6eSApple OSS Distributions "Ensure mach_vm_update_pointers_with_remote_tags is unusable when not debugged", 91*4d495c6eSApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("hw.optional.arm.FEAT_MTE4", 1), 92*4d495c6eSApple OSS Distributions XNU_T_META_SOC_SPECIFIC) { 93*4d495c6eSApple OSS Distributions /* Given a tagged buffer */ 94*4d495c6eSApple OSS Distributions const mach_vm_size_t alloc_size = PAGE_SIZE; 95*4d495c6eSApple OSS Distributions const mach_vm_size_t halfway = alloc_size / 2; 96*4d495c6eSApple OSS Distributions vm_address_t tagged_addr = allocate_and_tag_range(alloc_size, 0xa); 97*4d495c6eSApple OSS Distributions uint8_t* tagged_ptr = (uint8_t*)((uintptr_t)tagged_addr); 98*4d495c6eSApple OSS Distributions vm_address_t untagged_addr = tagged_addr & ~MTE_TAG_MASK; 99*4d495c6eSApple OSS Distributions uint8_t* untagged_ptr = (uint8_t*)((uintptr_t)untagged_addr); 100*4d495c6eSApple OSS Distributions 101*4d495c6eSApple OSS Distributions mach_vm_offset_t addresses_to_tag[1] = {(mach_vm_offset_t)untagged_ptr}; 102*4d495c6eSApple OSS Distributions 103*4d495c6eSApple OSS Distributions /* And we grab a task port */ 104*4d495c6eSApple OSS Distributions task_port_t target_task_port; 105*4d495c6eSApple OSS Distributions kern_return_t kr = task_for_pid(mach_task_self(), getpid(), &target_task_port); 106*4d495c6eSApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "task_for_pid for target"); 107*4d495c6eSApple OSS Distributions 108*4d495c6eSApple OSS Distributions /* When we request the pointers be rewritten with their MTE tags */ 109*4d495c6eSApple OSS Distributions mach_vm_offset_t resigned_addresses[1] = {0}; 110*4d495c6eSApple OSS Distributions mach_vm_offset_list_t input_list = addresses_to_tag; 111*4d495c6eSApple OSS Distributions mach_vm_offset_list_t output_list = resigned_addresses; 112*4d495c6eSApple OSS Distributions 113*4d495c6eSApple OSS Distributions int count = 1; 114*4d495c6eSApple OSS Distributions kr = mach_vm_update_pointers_with_remote_tags( 115*4d495c6eSApple OSS Distributions target_task_port, 116*4d495c6eSApple OSS Distributions input_list, 117*4d495c6eSApple OSS Distributions count, 118*4d495c6eSApple OSS Distributions output_list, 119*4d495c6eSApple OSS Distributions &count 120*4d495c6eSApple OSS Distributions ); 121*4d495c6eSApple OSS Distributions 122*4d495c6eSApple OSS Distributions /* Then it fails, because the input task wasn't debugged */ 123*4d495c6eSApple OSS Distributions T_ASSERT_EQ(kr, KERN_INVALID_ARGUMENT, "Expected mach_vm_update_pointers_with_remote_tags to fail when map !debugged"); 124*4d495c6eSApple OSS Distributions } 125*4d495c6eSApple OSS Distributions 126*4d495c6eSApple OSS Distributions T_DECL(vm_update_pointers_with_remote_tags_invalid_inputs, 127*4d495c6eSApple OSS Distributions "Ensure mach_vm_update_pointers_with_remote_tags fails when the input sizes don't match", 128*4d495c6eSApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("hw.optional.arm.FEAT_MTE4", 1), 129*4d495c6eSApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("security.mac.amfi.developer_mode_status", 1), 130*4d495c6eSApple OSS Distributions /* It's not straightforward to ptrace on platforms other than macOS, so don't bother */ 131*4d495c6eSApple OSS Distributions T_META_ENABLED(TARGET_CPU_ARM64 && TARGET_OS_OSX), 132*4d495c6eSApple OSS Distributions XNU_T_META_SOC_SPECIFIC) { 133*4d495c6eSApple OSS Distributions /* Given we fork off into a debugger and debugee (and Developer Mode is enabled) */ 134*4d495c6eSApple OSS Distributions /* And we set up a shared comms channel between parent and child */ 135*4d495c6eSApple OSS Distributions int ret; 136*4d495c6eSApple OSS Distributions const char* memory_path = "vm_update_pointers"; 137*4d495c6eSApple OSS Distributions shm_unlink(memory_path); 138*4d495c6eSApple OSS Distributions int shm_fd = shm_open(memory_path, O_RDWR | O_CREAT | O_EXCL); 139*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(shm_fd, "Created shared memory"); 140*4d495c6eSApple OSS Distributions 141*4d495c6eSApple OSS Distributions const mach_msg_type_number_t count = 1; 142*4d495c6eSApple OSS Distributions struct shared_data { 143*4d495c6eSApple OSS Distributions bool has_parent_connected; 144*4d495c6eSApple OSS Distributions bool has_child_populated_pointers; 145*4d495c6eSApple OSS Distributions bool has_parent_finished_inspecting_child; 146*4d495c6eSApple OSS Distributions bool has_child_acked_exit; 147*4d495c6eSApple OSS Distributions uint8_t* tagged_ptr; 148*4d495c6eSApple OSS Distributions uint8_t* differently_tagged_ptr; 149*4d495c6eSApple OSS Distributions mach_vm_offset_t addresses_to_tag[count]; 150*4d495c6eSApple OSS Distributions }; 151*4d495c6eSApple OSS Distributions 152*4d495c6eSApple OSS Distributions ret = ftruncate(shm_fd, sizeof(struct shared_data)); 153*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ftruncate"); 154*4d495c6eSApple OSS Distributions struct shared_data* shm = (struct shared_data*)mmap(NULL, sizeof(struct shared_data), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); 155*4d495c6eSApple OSS Distributions 156*4d495c6eSApple OSS Distributions const mach_vm_size_t alloc_size = PAGE_SIZE; 157*4d495c6eSApple OSS Distributions const mach_vm_size_t halfway = alloc_size / 2; 158*4d495c6eSApple OSS Distributions 159*4d495c6eSApple OSS Distributions pid_t pid = fork(); 160*4d495c6eSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(pid, "fork"); 161*4d495c6eSApple OSS Distributions 162*4d495c6eSApple OSS Distributions if (pid == 0) { 163*4d495c6eSApple OSS Distributions /* Allow the parent to attach */ 164*4d495c6eSApple OSS Distributions while (!shm->has_parent_connected) { 165*4d495c6eSApple OSS Distributions sleep(1); 166*4d495c6eSApple OSS Distributions } 167*4d495c6eSApple OSS Distributions 168*4d495c6eSApple OSS Distributions /* And a tagged buffer */ 169*4d495c6eSApple OSS Distributions vm_address_t tagged_addr = allocate_and_tag_range(alloc_size, 0xa); 170*4d495c6eSApple OSS Distributions shm->tagged_ptr = (uint8_t*)((uintptr_t)tagged_addr); 171*4d495c6eSApple OSS Distributions vm_address_t untagged_addr = tagged_addr & ~MTE_TAG_MASK; 172*4d495c6eSApple OSS Distributions uint8_t* untagged_ptr = (uint8_t*)((uintptr_t)untagged_addr); 173*4d495c6eSApple OSS Distributions 174*4d495c6eSApple OSS Distributions shm->addresses_to_tag[0] = (mach_vm_offset_t)&untagged_ptr[0]; 175*4d495c6eSApple OSS Distributions 176*4d495c6eSApple OSS Distributions /* Let the parent know we're ready to go */ 177*4d495c6eSApple OSS Distributions shm->has_child_populated_pointers = true; 178*4d495c6eSApple OSS Distributions 179*4d495c6eSApple OSS Distributions /* Allow the parent to interrogate our address space */ 180*4d495c6eSApple OSS Distributions while (!shm->has_parent_finished_inspecting_child) { 181*4d495c6eSApple OSS Distributions sleep(1); 182*4d495c6eSApple OSS Distributions } 183*4d495c6eSApple OSS Distributions shm->has_child_acked_exit = true; 184*4d495c6eSApple OSS Distributions exit(0); 185*4d495c6eSApple OSS Distributions } 186*4d495c6eSApple OSS Distributions 187*4d495c6eSApple OSS Distributions /* Attach to the child so it's marked as being debugged */ 188*4d495c6eSApple OSS Distributions ret = ptrace(PT_ATTACHEXC, pid, 0, 0); 189*4d495c6eSApple OSS Distributions T_EXPECT_POSIX_SUCCESS(ret, "ptrace PT_ATTACHEXC"); 190*4d495c6eSApple OSS Distributions 191*4d495c6eSApple OSS Distributions /* And let the child know that it can carry on */ 192*4d495c6eSApple OSS Distributions shm->has_parent_connected = true; 193*4d495c6eSApple OSS Distributions 194*4d495c6eSApple OSS Distributions /* And ensure the child has set up the memory */ 195*4d495c6eSApple OSS Distributions while (!(shm->has_child_populated_pointers)) { 196*4d495c6eSApple OSS Distributions sleep(1); 197*4d495c6eSApple OSS Distributions } 198*4d495c6eSApple OSS Distributions 199*4d495c6eSApple OSS Distributions /* And we grab a task port */ 200*4d495c6eSApple OSS Distributions task_port_t target_task_port; 201*4d495c6eSApple OSS Distributions kern_return_t kr = task_for_pid(mach_task_self(), pid, &target_task_port); 202*4d495c6eSApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "task_for_pid for target"); 203*4d495c6eSApple OSS Distributions 204*4d495c6eSApple OSS Distributions /* When we request the pointers be rewritten with their MTE tags */ 205*4d495c6eSApple OSS Distributions mach_vm_offset_t resigned_addresses[count] = {0}; 206*4d495c6eSApple OSS Distributions mach_vm_offset_list_t input_list = &shm->addresses_to_tag[0]; 207*4d495c6eSApple OSS Distributions mach_vm_offset_list_t output_list = resigned_addresses; 208*4d495c6eSApple OSS Distributions 209*4d495c6eSApple OSS Distributions /* But our output array has a size mismatched from the input array */ 210*4d495c6eSApple OSS Distributions const mach_msg_type_number_t mismatched_count = 2; 211*4d495c6eSApple OSS Distributions 212*4d495c6eSApple OSS Distributions kr = mach_vm_update_pointers_with_remote_tags( 213*4d495c6eSApple OSS Distributions target_task_port, 214*4d495c6eSApple OSS Distributions input_list, 215*4d495c6eSApple OSS Distributions count, 216*4d495c6eSApple OSS Distributions output_list, 217*4d495c6eSApple OSS Distributions &mismatched_count 218*4d495c6eSApple OSS Distributions ); 219*4d495c6eSApple OSS Distributions /* Then it fails, because the input task wasn't debugged */ 220*4d495c6eSApple OSS Distributions T_ASSERT_EQ(kr, KERN_INVALID_ARGUMENT, "Expected mach_vm_update_pointers_with_remote_tags to fail input array sizes mismatch"); 221*4d495c6eSApple OSS Distributions 222*4d495c6eSApple OSS Distributions /* Cleanup: let the child know that it's fine to exit */ 223*4d495c6eSApple OSS Distributions shm->has_parent_finished_inspecting_child = true; 224*4d495c6eSApple OSS Distributions while (!(shm->has_child_acked_exit)) { 225*4d495c6eSApple OSS Distributions sleep(1); 226*4d495c6eSApple OSS Distributions } 227*4d495c6eSApple OSS Distributions 228*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(close(shm_fd), "Closed shm fd"); 229*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(shm_unlink(memory_path), "Unlinked"); 230*4d495c6eSApple OSS Distributions } 231*4d495c6eSApple OSS Distributions 232*4d495c6eSApple OSS Distributions T_DECL(vm_update_pointers_with_remote_tags, 233*4d495c6eSApple OSS Distributions "Validate the behavior of the API that allows reading remote tag info", 234*4d495c6eSApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("hw.optional.arm.FEAT_MTE4", 1), 235*4d495c6eSApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("security.mac.amfi.developer_mode_status", 1), 236*4d495c6eSApple OSS Distributions /* It's not straightforward to ptrace on platforms other than macOS, so don't bother */ 237*4d495c6eSApple OSS Distributions T_META_ENABLED(TARGET_CPU_ARM64 && TARGET_OS_OSX), 238*4d495c6eSApple OSS Distributions XNU_T_META_SOC_SPECIFIC) { 239*4d495c6eSApple OSS Distributions /* Given we fork off into a debugger and debugee (and Developer Mode is enabled) */ 240*4d495c6eSApple OSS Distributions /* And we set up a shared comms channel between parent and child */ 241*4d495c6eSApple OSS Distributions int ret; 242*4d495c6eSApple OSS Distributions const char* memory_path = "vm_update_pointers"; 243*4d495c6eSApple OSS Distributions shm_unlink(memory_path); 244*4d495c6eSApple OSS Distributions int shm_fd = shm_open(memory_path, O_RDWR | O_CREAT | O_EXCL); 245*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(shm_fd, "Created shared memory"); 246*4d495c6eSApple OSS Distributions 247*4d495c6eSApple OSS Distributions const mach_msg_type_number_t count = 4; 248*4d495c6eSApple OSS Distributions struct shared_data { 249*4d495c6eSApple OSS Distributions bool has_parent_connected; 250*4d495c6eSApple OSS Distributions bool has_child_populated_pointers; 251*4d495c6eSApple OSS Distributions bool has_parent_finished_inspecting_child; 252*4d495c6eSApple OSS Distributions bool has_child_acked_exit; 253*4d495c6eSApple OSS Distributions uint8_t* tagged_ptr; 254*4d495c6eSApple OSS Distributions uint8_t* differently_tagged_ptr; 255*4d495c6eSApple OSS Distributions uint8_t* untagged_ptr; 256*4d495c6eSApple OSS Distributions mach_vm_offset_t addresses_to_tag[count]; 257*4d495c6eSApple OSS Distributions }; 258*4d495c6eSApple OSS Distributions 259*4d495c6eSApple OSS Distributions ret = ftruncate(shm_fd, sizeof(struct shared_data)); 260*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ftruncate"); 261*4d495c6eSApple OSS Distributions struct shared_data* shm = (struct shared_data*)mmap(NULL, sizeof(struct shared_data), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); 262*4d495c6eSApple OSS Distributions 263*4d495c6eSApple OSS Distributions const mach_vm_size_t alloc_size = PAGE_SIZE; 264*4d495c6eSApple OSS Distributions const mach_vm_size_t halfway = alloc_size / 2; 265*4d495c6eSApple OSS Distributions 266*4d495c6eSApple OSS Distributions pid_t pid = fork(); 267*4d495c6eSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(pid, "fork"); 268*4d495c6eSApple OSS Distributions 269*4d495c6eSApple OSS Distributions if (pid == 0) { 270*4d495c6eSApple OSS Distributions /* Allow the parent to attach */ 271*4d495c6eSApple OSS Distributions while (!shm->has_parent_connected) { 272*4d495c6eSApple OSS Distributions sleep(1); 273*4d495c6eSApple OSS Distributions } 274*4d495c6eSApple OSS Distributions 275*4d495c6eSApple OSS Distributions /* Given an untagged buffer */ 276*4d495c6eSApple OSS Distributions void* untagged_buffer_addr = allocate_untagged_memory(alloc_size); 277*4d495c6eSApple OSS Distributions shm->untagged_ptr = untagged_buffer_addr; 278*4d495c6eSApple OSS Distributions 279*4d495c6eSApple OSS Distributions /* And a tagged buffer */ 280*4d495c6eSApple OSS Distributions vm_address_t tagged_addr = allocate_and_tag_range(alloc_size, 0xa); 281*4d495c6eSApple OSS Distributions shm->tagged_ptr = (uint8_t*)((uintptr_t)tagged_addr); 282*4d495c6eSApple OSS Distributions vm_address_t untagged_addr = tagged_addr & ~MTE_TAG_MASK; 283*4d495c6eSApple OSS Distributions uint8_t* untagged_ptr = (uint8_t*)((uintptr_t)untagged_addr); 284*4d495c6eSApple OSS Distributions 285*4d495c6eSApple OSS Distributions /* And a different tag is used halfway through the tagged buffer */ 286*4d495c6eSApple OSS Distributions uint64_t different_tag = 0xb; 287*4d495c6eSApple OSS Distributions shm->differently_tagged_ptr = (uint8_t*)((uintptr_t) untagged_ptr | (different_tag << MTE_TAG_SHIFT)); 288*4d495c6eSApple OSS Distributions for (mach_vm_size_t offset = halfway; offset < alloc_size; offset += MTE_GRANULE_SIZE) { 289*4d495c6eSApple OSS Distributions __arm_mte_set_tag(&shm->differently_tagged_ptr[offset]); 290*4d495c6eSApple OSS Distributions } 291*4d495c6eSApple OSS Distributions 292*4d495c6eSApple OSS Distributions /* And a pointer to a bogus address */ 293*4d495c6eSApple OSS Distributions mach_vm_offset_t bogus_pointer = 0xaaaaaaaa; 294*4d495c6eSApple OSS Distributions /* And one of the pointers points to a region that we try ensure isn't resident */ 295*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_ZERO(madvise(untagged_buffer_addr, alloc_size, MADV_DONTNEED), "madvise(DONTNEED)"); 296*4d495c6eSApple OSS Distributions 297*4d495c6eSApple OSS Distributions shm->addresses_to_tag[0] = (mach_vm_offset_t)&untagged_ptr[0]; 298*4d495c6eSApple OSS Distributions shm->addresses_to_tag[1] = (mach_vm_offset_t)&untagged_ptr[halfway]; 299*4d495c6eSApple OSS Distributions shm->addresses_to_tag[2] = (mach_vm_offset_t)untagged_buffer_addr; 300*4d495c6eSApple OSS Distributions shm->addresses_to_tag[3] = (mach_vm_offset_t)bogus_pointer; 301*4d495c6eSApple OSS Distributions 302*4d495c6eSApple OSS Distributions /* Let the parent know we're ready to go */ 303*4d495c6eSApple OSS Distributions shm->has_child_populated_pointers = true; 304*4d495c6eSApple OSS Distributions 305*4d495c6eSApple OSS Distributions /* Allow the parent to interrogate our address space */ 306*4d495c6eSApple OSS Distributions while (!shm->has_parent_finished_inspecting_child) { 307*4d495c6eSApple OSS Distributions sleep(1); 308*4d495c6eSApple OSS Distributions } 309*4d495c6eSApple OSS Distributions shm->has_child_acked_exit = true; 310*4d495c6eSApple OSS Distributions exit(0); 311*4d495c6eSApple OSS Distributions } 312*4d495c6eSApple OSS Distributions 313*4d495c6eSApple OSS Distributions /* Attach to the child so it's marked as being debugged */ 314*4d495c6eSApple OSS Distributions ret = ptrace(PT_ATTACHEXC, pid, 0, 0); 315*4d495c6eSApple OSS Distributions T_EXPECT_POSIX_SUCCESS(ret, "ptrace PT_ATTACHEXC"); 316*4d495c6eSApple OSS Distributions 317*4d495c6eSApple OSS Distributions /* And let the child know that it can carry on */ 318*4d495c6eSApple OSS Distributions shm->has_parent_connected = true; 319*4d495c6eSApple OSS Distributions 320*4d495c6eSApple OSS Distributions /* And ensure the child has set up the memory */ 321*4d495c6eSApple OSS Distributions while (!(shm->has_child_populated_pointers)) { 322*4d495c6eSApple OSS Distributions sleep(1); 323*4d495c6eSApple OSS Distributions } 324*4d495c6eSApple OSS Distributions 325*4d495c6eSApple OSS Distributions /* And we grab a task port */ 326*4d495c6eSApple OSS Distributions task_port_t target_task_port; 327*4d495c6eSApple OSS Distributions kern_return_t kr = task_for_pid(mach_task_self(), pid, &target_task_port); 328*4d495c6eSApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "task_for_pid for target"); 329*4d495c6eSApple OSS Distributions 330*4d495c6eSApple OSS Distributions /* When we request the pointers be rewritten with their MTE tags */ 331*4d495c6eSApple OSS Distributions mach_vm_offset_t resigned_addresses[count] = {0}; 332*4d495c6eSApple OSS Distributions mach_vm_offset_list_t input_list = &shm->addresses_to_tag[0]; 333*4d495c6eSApple OSS Distributions mach_vm_offset_list_t output_list = resigned_addresses; 334*4d495c6eSApple OSS Distributions 335*4d495c6eSApple OSS Distributions kr = mach_vm_update_pointers_with_remote_tags( 336*4d495c6eSApple OSS Distributions target_task_port, 337*4d495c6eSApple OSS Distributions input_list, 338*4d495c6eSApple OSS Distributions count, 339*4d495c6eSApple OSS Distributions output_list, 340*4d495c6eSApple OSS Distributions &count 341*4d495c6eSApple OSS Distributions ); 342*4d495c6eSApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "mach_vm_update_pointers_with_remote_tags"); 343*4d495c6eSApple OSS Distributions 344*4d495c6eSApple OSS Distributions /* Then the pointers have been rewritten as expected */ 345*4d495c6eSApple OSS Distributions T_ASSERT_EQ_ULONG((unsigned long)output_list[0], (unsigned long)&(shm->tagged_ptr)[0], "Expected pointer 1 to be correctly rewritten"); 346*4d495c6eSApple OSS Distributions T_ASSERT_EQ_ULONG((unsigned long)output_list[1], (unsigned long)&(shm->differently_tagged_ptr)[halfway], "Expected pointer 2 to be correctly rewritten"); 347*4d495c6eSApple OSS Distributions /* A non-MTE-enabled object is returned as-is in the output list */ 348*4d495c6eSApple OSS Distributions T_ASSERT_EQ_ULONG((unsigned long)output_list[2], shm->untagged_ptr, "Expected a non-MTE address to be returned as-is"); 349*4d495c6eSApple OSS Distributions /* An invalid input pointer is returned as zero in the output list */ 350*4d495c6eSApple OSS Distributions T_ASSERT_EQ_ULONG((unsigned long)output_list[3], 0, "Expected an unmapped address to be transformed to 0"); 351*4d495c6eSApple OSS Distributions 352*4d495c6eSApple OSS Distributions /* And let the child know that it's fine to exit */ 353*4d495c6eSApple OSS Distributions shm->has_parent_finished_inspecting_child = true; 354*4d495c6eSApple OSS Distributions while (!(shm->has_child_acked_exit)) { 355*4d495c6eSApple OSS Distributions sleep(1); 356*4d495c6eSApple OSS Distributions } 357*4d495c6eSApple OSS Distributions 358*4d495c6eSApple OSS Distributions /* Cleanup */ 359*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(close(shm_fd), "Closed shm fd"); 360*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(shm_unlink(memory_path), "Unlinked"); 361*4d495c6eSApple OSS Distributions } 362*4d495c6eSApple OSS Distributions #endif /* __arm64__ */ 363