xref: /xnu-12377.81.4/tests/arm_mte_utilities.h (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
1 /*
2  * Copyright (c) 2024 Apple 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 #ifndef ARM_MTE_UTILITIES_H
30 #define ARM_MTE_UTILITIES_H
31 
32 #include <mach/vm_types.h>
33 #include <sys/spawn_internal.h>
34 
35 #include <stdbool.h>
36 #include <stdint.h>
37 
38 #if (TARGET_OS_OSX || TARGET_OS_IOS) && defined(__arm64__)
39 // TODO(PT): It'd be nice to have this as an allow list rather than the inverse,
40 // but I wasn't able to restrict based on TARGET_OS_[IPHONE|IOS] as this is sometimes set even for XR_OS.
41 // For now, to keep things moving, just restrict this from being set on platforms where
42 // we know it's not the case.
43 #if !(TARGET_OS_XR || TARGET_OS_TV || TARGET_OS_WATCH || TARGET_OS_BRIDGE)
44 	#define TARGET_SUPPORTS_MTE_EMULATION 1
45 #endif
46 #endif
47 
48 #define MTE_TAG_SHIFT                56
49 #define MTE_TAG_MASK                 (0xFULL << MTE_TAG_SHIFT)
50 #define MTE_GRANULE_SIZE             16
51 #define VM_MIN_KERNEL_ADDRESS        (0ULL - (2ULL << 40))
52 #define KERNEL_BUFFER_COPY_THRESHOLD (32 * 1024)
53 #define VIRTUAL_COPY_SZ              ((32 * 1024) + 15)
54 #define NUM_MTE_TAGS                 16
55 #define VM_WIMG_MTE                  0x22 /* VM_MEM_MTE | VM_MEM_COHERENT */
56 
57 // Used in arm_mte.c
58 #define SPAWN_HELPER_WITH_ENTITLEMENT "arm_mte_spawn_client_with_hardened_process_entitlement"
59 #define SPAWN_HELPER_WITHOUT_ENTITLEMENT "arm_mte_spawn_client_without_hardened_process_entitlement"
60 
61 // Used in arm_mte_spawn_policies.c
62 #define HARDENED_PROCESS_HELPER         SPAWN_HELPER_WITH_ENTITLEMENT
63 #define NO_HARDENED_PROCESS_HELPER      SPAWN_HELPER_WITHOUT_ENTITLEMENT
64 
65 #define HARDENED_PROCESS_TOP_LEVEL_ONLY_AND_IN_AMFI_MTE_OPT_OUT_HELPER         \
66   "arm_mte_spawn_client_with_top_level_hardened_proc_entitlement_and_in_amfi_opt_out"
67 
68 #define EXPECT_MTE         "YES"
69 #define DO_NOT_EXPECT_MTE  "NO"
70 
71 static enum {
72 	MTE_ENABLEMENT_TEST_HARDENED_PROCESS = 0x41,
73 	MTE_ENABLEMENT_TEST_VANILLA_PROCESS,
74 	MTE_ENABLEMENT_TEST_OPTED_OUT_PROCESS,
75 	MTE_ENABLEMENT_TEST_DONE
76 } mte_enablement_test_op;
77 
78 static char MTE_ENABLEMENT_TEST_HARDENED_PROCESS_STR[2] = {MTE_ENABLEMENT_TEST_HARDENED_PROCESS, '\x0'};
79 static char MTE_ENABLEMENT_TEST_VANILLA_PROCESS_STR[2] = {MTE_ENABLEMENT_TEST_VANILLA_PROCESS, '\x0'};
80 static char MTE_ENABLEMENT_TEST_OPTED_OUT_PROCESS_STR[2] = {MTE_ENABLEMENT_TEST_OPTED_OUT_PROCESS, '\x0'};
81 static char MTE_ENABLEMENT_TEST_DONE_STR[2] = {MTE_ENABLEMENT_TEST_DONE, '\x0'};
82 
83 void kill_child(int child_pid);
84 
85 bool wait_for_child(int pid);
86 
87 bool validate_proc_pidinfo_mte_status(int child_pid,
88     bool expect_mte_enabled);
89 bool validate_proc_pidinfo_mte_soft_mode_status(int child_pid,
90     bool expect_mte_soft_mode_enabled);
91 
92 bool fork_and_exec_new_process(char *new_argv[]);
93 
94 static enum {
95 	MTE_SPAWN_USE_VANILLA,
96 	MTE_SPAWN_USE_LEGACY_API,
97 } mte_spawn_op;
98 
99 bool posix_spawn_then_perform_action_from_process(char *new_argv[], uint8_t setup,
100     uint16_t spawn_flags);
101 
102 inline unsigned int
extract_mte_tag(void * ptr)103 extract_mte_tag(void *ptr)
104 {
105 	return (unsigned int)((((uintptr_t)ptr) & MTE_TAG_MASK) >> MTE_TAG_SHIFT);
106 }
107 
108 int64_t run_sysctl_test(const char *t, int64_t value);
109 
110 void expect_signal_impl(int signal, char *signal_name, void (^fn)(void), const char *msg);
111 #define expect_signal(signal, fn, msg) (expect_signal_impl((signal), #signal, (fn), (msg)))
112 void expect_sigkill(void (^fn)(void), const char *msg);
113 
114 void expect_normal_exit(void (^fn)(void), const char *msg);
115 void assert_normal_exit(void (^fn)(void), const char *msg);
116 
117 /*
118  * Uses vm_allocate to allocate `size` bytes of untagged memory and
119  * returns the untagged pointer to the caller.
120  *
121  * If mask is non-NULL, writes out a mask which can be passed in to
122  * __arm_mte_create_random_tag to exclude the zero tag.
123  */
124 void *allocate_untagged_memory(mach_vm_size_t size);
125 
126 /*
127  * Uses allocate_tagged_memory to get a tagged memory range, and also applies
128  * a tag value to each of the MTE granules within the new allocation.
129  */
130 #define TAG_RANDOM_EXCLUDE(x) ((uintptr_t) ~x)
131 #define TAG_RANDOM TAG_RANDOM_EXCLUDE(0)
132 vm_address_t allocate_and_tag_range(mach_vm_size_t size, uintptr_t tag);
133 #endif
134 
135 /* Posix spawn a process with any specified posix_spawn_secflag_options */
136 void
137 posix_spawn_with_flags_and_assert_successful_exit(
138 	char *const*args,
139 	posix_spawn_secflag_options flags,
140 	bool expect_mte,
141 	bool should_kill_child
142 	);
143 
144 /*
145  * Uses vm_allocate to allocate `size` bytes of tagged memory and
146  * returns the untagged pointer to the caller.
147  */
148 void *allocate_tagged_memory(mach_vm_size_t size, uint64_t *mask);
149 
150 /* Utility to return the output of a output of a uint64_t sysctl */
151 uint64_t
152 sysctl_get_Q(const char *name);
153