1 #include <machine/cpu_capabilities.h>
2 #include <os/thread_self_restrict.h>
3 #include <libkern/OSCacheControl.h>
4 #include <sys/time.h>
5 #include <darwintest.h>
6 #include <sys/types.h>
7 #include <sys/sysctl.h>
8 #include <sys/wait.h>
9 #include <sys/mman.h>
10 #include <ptrauth.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <signal.h>
15
16 /*
17 * What this test does and what this test does not do:
18 * - we test for unexpectedly-writeable MSRs in the implementaion-defined space
19 * - any that are found to be writeable are tested for ability to store at least a single bit
20 * - any found to do so are tested to reset in context switch or sooner
21 *
22 * This will detect any covert channels we create on accident
23 *
24 * What this test does not do:
25 * - test that registers that are allowed to be written per-thread are properly context switched
26 *
27 * And that is why there is a whitelist of regs that we DO intend to be writeable from userspace
28 * and we *KNOW* are properly context switched. Registers we *INTEND* userspace to write are
29 * in that list. Things like TPIDR_EL0, and others
30 *
31 */
32
33
34 #define NUM_THREADS 256
35
36 T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
37
38
39 #if defined(__arm64__) && defined(__LP64__)
40
41 enum msr_op_reason {
42 msr_get_name, // -> const char *name
43 msr_read, // -> uint64_t val
44 msr_write, // <- uint64_t val
45 };
46
47 typedef void (*msr_op)(enum msr_op_reason why, void *param);
48
49
50 static pthread_mutex_t threads_please_die_lock = PTHREAD_MUTEX_INITIALIZER;
51 static volatile bool did_fault;
52 static bool threads_please_die;
53
54 static const char *registers_skipped[] = {
55 "S3_3_C13_C0_2", //TPIDR_EL0
56 "S3_4_C15_C15_6", //JCTL_EL0
57 };
58
59 #define DECLARE_TEST(_op0, _op1, _n, _m, _op2) \
60 static void __attribute__((optnone)) \
61 msr_test_S ## _op0 ## _ ## _op1 ## _C ## _n ## _C ## _m ## _ ## _op2 (enum msr_op_reason why, void *param) \
62 { \
63 switch (why) { \
64 case msr_get_name: \
65 *(const char **)param = "S" #_op0 "_" #_op1 "_C" #_n "_C" #_m "_" #_op2; \
66 break; \
67 \
68 case msr_read: \
69 *(uint64_t*)param = __builtin_arm_rsr64("S" #_op0 "_" #_op1 "_C" #_n "_C" #_m "_" #_op2); \
70 break; \
71 \
72 case msr_write: \
73 __builtin_arm_wsr64("S" #_op0 "_" #_op1 "_C" #_n "_C" #_m "_" #_op2, *(const uint64_t*)param); \
74 break; \
75 } \
76 }
77
78 #include "user_msrs.inc"
79 #undef DECLARE_TEST
80 #define DECLARE_TEST(_op0, _op1, _n, _m, _op2) msr_test_S ## _op0 ## _ ## _op1 ## _C ## _n ## _C ## _m ## _ ## _op2,
81 static msr_op tests[] = {
82 #include "user_msrs.inc"
83 };
84 #undef DECLARE_TEST
85
86 static void*
thread_func(void * param)87 thread_func(void *param)
88 {
89 bool die;
90
91 (void)param;
92
93 do {
94 pthread_mutex_lock(&threads_please_die_lock);
95 die = threads_please_die;
96 pthread_mutex_unlock(&threads_please_die_lock);
97 } while (!die);
98
99 return NULL;
100 }
101
102 static void
msr_test(msr_op op)103 msr_test(msr_op op)
104 {
105 struct timeval time_start, time_end, time_passed;
106 uint64_t val, new_val, wrote_val;
107 pthread_t threads[NUM_THREADS];
108 bool readable, writeable;
109 const char *reg_name;
110 unsigned i;
111
112 op(msr_get_name, ®_name);
113 T_LOG("sub-test '%s'\n", reg_name);
114
115 for (i = 0; i < sizeof(registers_skipped) / sizeof(*registers_skipped); i++) {
116 if (!strcmp(registers_skipped[i], reg_name)) {
117 T_LOG("\tskipping this register by request");
118 return;
119 }
120 }
121
122 //let's see if we can read and write it
123 did_fault = false;
124 op(msr_read, &val);
125 readable = !did_fault;
126
127 did_fault = false;
128 op(msr_write, &val);
129 writeable = !did_fault;
130
131 T_LOG("\tcan read: %s\n", readable ? "YES" : "NO");
132 T_LOG("\tcan write: %s\n", writeable ? "YES" : "NO");
133 if (readable) {
134 T_LOG("\tvalue found: 0x%016llx\n", (unsigned long long)val);
135 }
136
137 if (!readable || !writeable) {
138 T_LOG("\t RW needed for more testing. no further testing will be performed\n");
139 return;
140 }
141
142 //write inverse of what we read and see if the read differs
143 wrote_val = ~val;
144 op(msr_write, &wrote_val);
145 op(msr_read, &new_val);
146
147 if (new_val == val) {
148 T_LOG("\t reg seems to not take writes (0x%016llx). no further testing will be performed\n", val);
149 return;
150 }
151 T_LOG("\twrote 0x%016llx, saw 0x%016llx\n", (unsigned long long)wrote_val, (unsigned long long)new_val);
152 wrote_val = new_val;
153
154 //verify it flips to original value at context switch or otherwise
155 //for context switch to happen, spin up a lot of threads
156 pthread_mutex_lock(&threads_please_die_lock);
157 threads_please_die = false;
158 pthread_mutex_unlock(&threads_please_die_lock);
159 for (i = 0; i < NUM_THREADS; i++) {
160 if (pthread_create(threads + i, NULL, thread_func, NULL)) {
161 T_ASSERT_FAIL("cannot create thread %d\n", i);
162 }
163 }
164
165 gettimeofday(&time_start, NULL);
166 while (1) {
167 op(msr_read, &new_val);
168 if (new_val != wrote_val) {
169 T_LOG("\tvalue reverted to 0x%016llx from 0x%016llx\n", (unsigned long long)new_val, (unsigned long long)wrote_val);
170 break;
171 }
172
173 gettimeofday(&time_end, NULL);
174 timersub(&time_end, &time_start, &time_passed);
175 if (time_passed.tv_sec) { //wait one second at most
176 T_FAIL("\ttoo long for register to be cleared, last read value was 0x%016llx, expected revert to 0x%016llx!", (unsigned long long)new_val, (unsigned long long)val);
177 break;
178 }
179 }
180 pthread_mutex_lock(&threads_please_die_lock);
181 threads_please_die = true;
182 pthread_mutex_unlock(&threads_please_die_lock);
183 for (i = 0; i < NUM_THREADS; i++) {
184 if (pthread_join(threads[i], NULL)) {
185 T_ASSERT_FAIL("cannot join thread %d\n", i);
186 }
187 }
188 }
189
190 static void
sig_caught(int signo,siginfo_t * sinfop,void * ucontext)191 sig_caught(int signo, siginfo_t *sinfop, void *ucontext)
192 {
193 _STRUCT_MCONTEXT64 *ctx = ((ucontext_t *)ucontext)->uc_mcontext;
194 void (*pc)(void);
195 uint32_t instr;
196
197 (void)sinfop;
198
199 if (signo != SIGILL) {
200 T_ASSERT_FAIL("We did not expect signal %d", signo);
201 }
202
203 pc = (void (*)(void))__darwin_arm_thread_state64_get_pc(ctx->__ss);
204 instr = *(uint32_t*)pc;
205
206 if ((instr & 0xffd00000) != 0xd5100000) {
207 T_ASSERT_FAIL("We did not expect SIGILL on an instr that is not an MSR/MRS. [%p] = 0x%08x", (void*)pc, instr);
208 }
209
210 pc = (void (*)(void))(((uintptr_t)pc) + 4);
211 pc = ptrauth_sign_unauthenticated(pc, ptrauth_key_function_pointer, 0);
212
213 did_fault = true;
214
215 // skip the instruction
216 __darwin_arm_thread_state64_set_pc_fptr(ctx->__ss, pc);
217 }
218
219 static bool
is_release_kernel(void)220 is_release_kernel(void)
221 {
222 /*
223 * I apologize to anyone reading this code!! I promise you that I felt
224 * as dirty writing this as you do reading this. I asked in the proper
225 * channels, but nobody had a good idea how to detect a release kernel
226 * from userspace. Sadly, we need that here as the mitigations at hand
227 * are only applied in RELEASE builds. Again: I am sorry.
228 */
229 char ver_str[1024] = {};
230 size_t len = sizeof(ver_str) - 1;
231
232 (void)sysctlbyname("kern.version", ver_str, &len, NULL, 0);
233
234 return !!strstr(ver_str, "/RELEASE_ARM64");
235 }
236
237 #endif // defined(__arm64__) && defined(__LP64__)
238
239 T_DECL(user_msrs, "Userspace MSR access test")
240 {
241 #if defined(__arm64__) && defined(__LP64__)
242 if (is_release_kernel()) {
243 struct sigaction sa_old, sa_new = {.__sigaction_u = { .__sa_sigaction = sig_caught, }, .sa_flags = SA_SIGINFO, };
244 unsigned i;
245
246 sigaction(SIGILL, &sa_new, &sa_old);
247
248 for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
249 msr_test(tests[i]);
250 }
251
252 sigaction(SIGILL, &sa_old, NULL);
253
254 T_PASS("Userspace MSR access test passed");
255 } else {
256 T_PASS("Userspace MSR access test only runs on release kernels");
257 }
258 #else // defined(__arm64__) && defined(__LP64__)
259 T_SKIP("userspace MSR access test skipped - not ARM64.64");
260 #endif // defined(__arm64__) && defined(__LP64__)
261 }
262