1 /* 2 * Copyright (c) 2024 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29 #if __arm64__ 30 #include <arm_acle.h> 31 #include <darwintest.h> 32 #include <fcntl.h> 33 #include <libproc.h> 34 #include <mach/mach.h> 35 #include <mach/mach_vm.h> 36 #include <mach/vm_map.h> 37 #include <signal.h> 38 #include <spawn.h> 39 #include <spawn_private.h> 40 #include <sys/mman.h> 41 42 #include "arm_mte_utilities.h" 43 #include "test_utils.h" 44 45 T_DECL(mte_alloc_from_unentitled, 46 "Attempt to allocate tagged memory from MTE-disabled process", 47 T_META_REQUIRES_SYSCTL_EQ("hw.optional.arm.FEAT_MTE2", 1), 48 XNU_T_META_SOC_SPECIFIC) 49 { 50 vm_address_t address = 0; 51 vm_size_t alloc_size = 16 * 1024; 52 53 kern_return_t kr = vm_allocate(mach_task_self(), &address, alloc_size, VM_FLAGS_ANYWHERE | VM_FLAGS_MTE); 54 T_EXPECT_MACH_ERROR_(kr, KERN_INVALID_ARGUMENT, "allocate tagged memory in unentitled process"); 55 56 if (kr == KERN_SUCCESS) { 57 // cleanup if the test failed 58 kr = vm_deallocate(mach_task_self(), address, alloc_size); 59 T_ASSERT_MACH_SUCCESS(kr, "test cleanup"); 60 } 61 } 62 63 /* Here, "debugger" means an MTE-disabled process with access to tagged memory */ 64 T_DECL(mte_debugger_untagged_copyio, 65 "Test that debugger processes can do copyio operations without tag checks", 66 T_META_REQUIRES_SYSCTL_EQ("hw.optional.arm.FEAT_MTE2", 1), 67 XNU_T_META_SOC_SPECIFIC, 68 /* Allow ourselves to act as a debugger */ 69 T_META_BOOTARGS_SET("amfi_unrestrict_task_for_pid=1"), 70 T_META_ASROOT(true)) 71 { 72 __block kern_return_t kr; 73 /* This is the debugger process (MTE disabled) */ 74 75 T_SETUPBEGIN; 76 char *shm_name = "mte_debugger_untagged_copyio"; 77 const mach_vm_size_t ALLOC_SIZE = PAGE_SIZE; 78 79 /* create shared memory descriptor for sending address */ 80 shm_unlink(shm_name); 81 int fd = shm_open(shm_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 82 T_ASSERT_POSIX_SUCCESS(fd, "shm_open"); 83 84 int ret = ftruncate(fd, sizeof(vm_address_t)); 85 T_ASSERT_POSIX_SUCCESS(ret, "ftruncate"); 86 87 volatile vm_address_t *shm = mmap(NULL, sizeof(vm_address_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 88 T_ASSERT_NE(shm, MAP_FAILED, "mmap"); 89 /* tell the process being "debugged" how much memory to allocate */ 90 *shm = ALLOC_SIZE; 91 T_SETUPEND; 92 93 /* Launch the to-be-debugged process, which has the MTE code-signing entitlement */ 94 char *new_argv[] = { "arm_mte_debugger_helper", shm_name, NULL }; 95 pid_t child_pid; 96 ret = posix_spawn(&child_pid, new_argv[0], NULL, NULL, new_argv, NULL); 97 T_ASSERT_POSIX_ZERO(ret, "posix_spawn"); 98 T_ASSERT_NE(child_pid, 0, "posix_spawn child_pid"); 99 100 /* Wait for the process to send the allocated address over */ 101 while (*shm == ALLOC_SIZE) { 102 /* check that the process is still alive */ 103 ret = kill(child_pid, 0); // note: signal 0 does not affect the child 104 105 /* fails with errno = ESRCH if the child process is dead */ 106 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "kill"); 107 } 108 109 vm_address_t child_addr = *shm; 110 T_ASSERT_EQ(child_addr & MTE_TAG_MASK, 0ULL, "received untagged pointer"); 111 112 mach_port_t child_task; 113 kr = task_for_pid(mach_task_self(), child_pid, &child_task); 114 T_ASSERT_MACH_SUCCESS(kr, "fetch task_for_pid(child)"); 115 116 vm_address_t dest_addr = 0; 117 vm_prot_t cur_prot = VM_PROT_DEFAULT, max_prot = VM_PROT_DEFAULT; 118 /* remap the process' tagged memory into the debugger's address space */ 119 kr = vm_remap(mach_task_self(), &dest_addr, ALLOC_SIZE, 120 /* mask = */ 0, VM_FLAGS_ANYWHERE, child_task, child_addr, 121 /* copy = */ false, &cur_prot, &max_prot, VM_INHERIT_DEFAULT); 122 T_ASSERT_MACH_SUCCESS(kr, "remapped process' tagged memory into debugger"); 123 124 /* create a source region for copyio */ 125 vm_address_t src_addr = 0; 126 kr = vm_allocate(mach_task_self(), &src_addr, ALLOC_SIZE, VM_FLAGS_ANYWHERE); 127 T_ASSERT_MACH_SUCCESS(kr, "vm_allocate source region"); 128 memset((void*) src_addr, 'A', ALLOC_SIZE); 129 130 /* make sure the debugger can copyio the tagged memory with its untagged pointer */ 131 expect_normal_exit(^{ 132 kr = mach_vm_copy(mach_task_self(), src_addr, ALLOC_SIZE, dest_addr); 133 T_EXPECT_MACH_SUCCESS(kr, "copyio using untagged pointer from debugger"); 134 }, "copyio tagged memory from debugger"); 135 136 /* cleanup */ 137 T_SETUPBEGIN; 138 ret = close(fd); 139 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "close"); 140 ret = shm_unlink(shm_name); 141 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "shm_unlink"); 142 kr = mach_vm_deallocate(mach_task_self(), dest_addr, ALLOC_SIZE); 143 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "deallocate remapped memory"); 144 kr = mach_vm_deallocate(mach_task_self(), src_addr, ALLOC_SIZE); 145 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "deallocate source region"); 146 kr = mach_port_deallocate(mach_task_self(), child_task); 147 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "deallocate child task port"); 148 T_SETUPEND; 149 } 150 #endif /* __arm64__ */ 151