1*053f45beSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-only
2*053f45beSAndroid Build Coastguard Worker /*
3*053f45beSAndroid Build Coastguard Worker * fsgsbase.c, an fsgsbase test
4*053f45beSAndroid Build Coastguard Worker * Copyright (c) 2014-2016 Andy Lutomirski
5*053f45beSAndroid Build Coastguard Worker */
6*053f45beSAndroid Build Coastguard Worker
7*053f45beSAndroid Build Coastguard Worker #define _GNU_SOURCE
8*053f45beSAndroid Build Coastguard Worker #include <stdio.h>
9*053f45beSAndroid Build Coastguard Worker #include <stdlib.h>
10*053f45beSAndroid Build Coastguard Worker #include <stdbool.h>
11*053f45beSAndroid Build Coastguard Worker #include <string.h>
12*053f45beSAndroid Build Coastguard Worker #include <sys/syscall.h>
13*053f45beSAndroid Build Coastguard Worker #include <unistd.h>
14*053f45beSAndroid Build Coastguard Worker #include <err.h>
15*053f45beSAndroid Build Coastguard Worker #include <sys/user.h>
16*053f45beSAndroid Build Coastguard Worker #include <asm/prctl.h>
17*053f45beSAndroid Build Coastguard Worker #include <sys/prctl.h>
18*053f45beSAndroid Build Coastguard Worker #include <signal.h>
19*053f45beSAndroid Build Coastguard Worker #include <limits.h>
20*053f45beSAndroid Build Coastguard Worker #include <sys/ucontext.h>
21*053f45beSAndroid Build Coastguard Worker #include <sched.h>
22*053f45beSAndroid Build Coastguard Worker #include <linux/futex.h>
23*053f45beSAndroid Build Coastguard Worker #include <pthread.h>
24*053f45beSAndroid Build Coastguard Worker #include <asm/ldt.h>
25*053f45beSAndroid Build Coastguard Worker #include <sys/mman.h>
26*053f45beSAndroid Build Coastguard Worker #include <stddef.h>
27*053f45beSAndroid Build Coastguard Worker #include <sys/ptrace.h>
28*053f45beSAndroid Build Coastguard Worker #include <sys/wait.h>
29*053f45beSAndroid Build Coastguard Worker #include <setjmp.h>
30*053f45beSAndroid Build Coastguard Worker
31*053f45beSAndroid Build Coastguard Worker #ifndef __x86_64__
32*053f45beSAndroid Build Coastguard Worker # error This test is 64-bit only
33*053f45beSAndroid Build Coastguard Worker #endif
34*053f45beSAndroid Build Coastguard Worker
35*053f45beSAndroid Build Coastguard Worker static volatile sig_atomic_t want_segv;
36*053f45beSAndroid Build Coastguard Worker static volatile unsigned long segv_addr;
37*053f45beSAndroid Build Coastguard Worker
38*053f45beSAndroid Build Coastguard Worker static unsigned short *shared_scratch;
39*053f45beSAndroid Build Coastguard Worker
40*053f45beSAndroid Build Coastguard Worker static int nerrs;
41*053f45beSAndroid Build Coastguard Worker
sethandler(int sig,void (* handler)(int,siginfo_t *,void *),int flags)42*053f45beSAndroid Build Coastguard Worker static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
43*053f45beSAndroid Build Coastguard Worker int flags)
44*053f45beSAndroid Build Coastguard Worker {
45*053f45beSAndroid Build Coastguard Worker struct sigaction sa;
46*053f45beSAndroid Build Coastguard Worker memset(&sa, 0, sizeof(sa));
47*053f45beSAndroid Build Coastguard Worker sa.sa_sigaction = handler;
48*053f45beSAndroid Build Coastguard Worker sa.sa_flags = SA_SIGINFO | flags;
49*053f45beSAndroid Build Coastguard Worker sigemptyset(&sa.sa_mask);
50*053f45beSAndroid Build Coastguard Worker if (sigaction(sig, &sa, 0))
51*053f45beSAndroid Build Coastguard Worker err(1, "sigaction");
52*053f45beSAndroid Build Coastguard Worker }
53*053f45beSAndroid Build Coastguard Worker
clearhandler(int sig)54*053f45beSAndroid Build Coastguard Worker static void clearhandler(int sig)
55*053f45beSAndroid Build Coastguard Worker {
56*053f45beSAndroid Build Coastguard Worker struct sigaction sa;
57*053f45beSAndroid Build Coastguard Worker memset(&sa, 0, sizeof(sa));
58*053f45beSAndroid Build Coastguard Worker sa.sa_handler = SIG_DFL;
59*053f45beSAndroid Build Coastguard Worker sigemptyset(&sa.sa_mask);
60*053f45beSAndroid Build Coastguard Worker if (sigaction(sig, &sa, 0))
61*053f45beSAndroid Build Coastguard Worker err(1, "sigaction");
62*053f45beSAndroid Build Coastguard Worker }
63*053f45beSAndroid Build Coastguard Worker
sigsegv(int sig,siginfo_t * si,void * ctx_void)64*053f45beSAndroid Build Coastguard Worker static void sigsegv(int sig, siginfo_t *si, void *ctx_void)
65*053f45beSAndroid Build Coastguard Worker {
66*053f45beSAndroid Build Coastguard Worker ucontext_t *ctx = (ucontext_t*)ctx_void;
67*053f45beSAndroid Build Coastguard Worker
68*053f45beSAndroid Build Coastguard Worker if (!want_segv) {
69*053f45beSAndroid Build Coastguard Worker clearhandler(SIGSEGV);
70*053f45beSAndroid Build Coastguard Worker return; /* Crash cleanly. */
71*053f45beSAndroid Build Coastguard Worker }
72*053f45beSAndroid Build Coastguard Worker
73*053f45beSAndroid Build Coastguard Worker want_segv = false;
74*053f45beSAndroid Build Coastguard Worker segv_addr = (unsigned long)si->si_addr;
75*053f45beSAndroid Build Coastguard Worker
76*053f45beSAndroid Build Coastguard Worker ctx->uc_mcontext.gregs[REG_RIP] += 4; /* Skip the faulting mov */
77*053f45beSAndroid Build Coastguard Worker
78*053f45beSAndroid Build Coastguard Worker }
79*053f45beSAndroid Build Coastguard Worker
80*053f45beSAndroid Build Coastguard Worker static jmp_buf jmpbuf;
81*053f45beSAndroid Build Coastguard Worker
sigill(int sig,siginfo_t * si,void * ctx_void)82*053f45beSAndroid Build Coastguard Worker static void sigill(int sig, siginfo_t *si, void *ctx_void)
83*053f45beSAndroid Build Coastguard Worker {
84*053f45beSAndroid Build Coastguard Worker siglongjmp(jmpbuf, 1);
85*053f45beSAndroid Build Coastguard Worker }
86*053f45beSAndroid Build Coastguard Worker
87*053f45beSAndroid Build Coastguard Worker static bool have_fsgsbase;
88*053f45beSAndroid Build Coastguard Worker
rdgsbase(void)89*053f45beSAndroid Build Coastguard Worker static inline unsigned long rdgsbase(void)
90*053f45beSAndroid Build Coastguard Worker {
91*053f45beSAndroid Build Coastguard Worker unsigned long gsbase;
92*053f45beSAndroid Build Coastguard Worker
93*053f45beSAndroid Build Coastguard Worker asm volatile("rdgsbase %0" : "=r" (gsbase) :: "memory");
94*053f45beSAndroid Build Coastguard Worker
95*053f45beSAndroid Build Coastguard Worker return gsbase;
96*053f45beSAndroid Build Coastguard Worker }
97*053f45beSAndroid Build Coastguard Worker
rdfsbase(void)98*053f45beSAndroid Build Coastguard Worker static inline unsigned long rdfsbase(void)
99*053f45beSAndroid Build Coastguard Worker {
100*053f45beSAndroid Build Coastguard Worker unsigned long fsbase;
101*053f45beSAndroid Build Coastguard Worker
102*053f45beSAndroid Build Coastguard Worker asm volatile("rdfsbase %0" : "=r" (fsbase) :: "memory");
103*053f45beSAndroid Build Coastguard Worker
104*053f45beSAndroid Build Coastguard Worker return fsbase;
105*053f45beSAndroid Build Coastguard Worker }
106*053f45beSAndroid Build Coastguard Worker
wrgsbase(unsigned long gsbase)107*053f45beSAndroid Build Coastguard Worker static inline void wrgsbase(unsigned long gsbase)
108*053f45beSAndroid Build Coastguard Worker {
109*053f45beSAndroid Build Coastguard Worker asm volatile("wrgsbase %0" :: "r" (gsbase) : "memory");
110*053f45beSAndroid Build Coastguard Worker }
111*053f45beSAndroid Build Coastguard Worker
wrfsbase(unsigned long fsbase)112*053f45beSAndroid Build Coastguard Worker static inline void wrfsbase(unsigned long fsbase)
113*053f45beSAndroid Build Coastguard Worker {
114*053f45beSAndroid Build Coastguard Worker asm volatile("wrfsbase %0" :: "r" (fsbase) : "memory");
115*053f45beSAndroid Build Coastguard Worker }
116*053f45beSAndroid Build Coastguard Worker
117*053f45beSAndroid Build Coastguard Worker enum which_base { FS, GS };
118*053f45beSAndroid Build Coastguard Worker
read_base(enum which_base which)119*053f45beSAndroid Build Coastguard Worker static unsigned long read_base(enum which_base which)
120*053f45beSAndroid Build Coastguard Worker {
121*053f45beSAndroid Build Coastguard Worker unsigned long offset;
122*053f45beSAndroid Build Coastguard Worker /*
123*053f45beSAndroid Build Coastguard Worker * Unless we have FSGSBASE, there's no direct way to do this from
124*053f45beSAndroid Build Coastguard Worker * user mode. We can get at it indirectly using signals, though.
125*053f45beSAndroid Build Coastguard Worker */
126*053f45beSAndroid Build Coastguard Worker
127*053f45beSAndroid Build Coastguard Worker want_segv = true;
128*053f45beSAndroid Build Coastguard Worker
129*053f45beSAndroid Build Coastguard Worker offset = 0;
130*053f45beSAndroid Build Coastguard Worker if (which == FS) {
131*053f45beSAndroid Build Coastguard Worker /* Use a constant-length instruction here. */
132*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %%fs:(%%rcx), %%rax" : : "c" (offset) : "rax");
133*053f45beSAndroid Build Coastguard Worker } else {
134*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %%gs:(%%rcx), %%rax" : : "c" (offset) : "rax");
135*053f45beSAndroid Build Coastguard Worker }
136*053f45beSAndroid Build Coastguard Worker if (!want_segv)
137*053f45beSAndroid Build Coastguard Worker return segv_addr + offset;
138*053f45beSAndroid Build Coastguard Worker
139*053f45beSAndroid Build Coastguard Worker /*
140*053f45beSAndroid Build Coastguard Worker * If that didn't segfault, try the other end of the address space.
141*053f45beSAndroid Build Coastguard Worker * Unless we get really unlucky and run into the vsyscall page, this
142*053f45beSAndroid Build Coastguard Worker * is guaranteed to segfault.
143*053f45beSAndroid Build Coastguard Worker */
144*053f45beSAndroid Build Coastguard Worker
145*053f45beSAndroid Build Coastguard Worker offset = (ULONG_MAX >> 1) + 1;
146*053f45beSAndroid Build Coastguard Worker if (which == FS) {
147*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %%fs:(%%rcx), %%rax"
148*053f45beSAndroid Build Coastguard Worker : : "c" (offset) : "rax");
149*053f45beSAndroid Build Coastguard Worker } else {
150*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %%gs:(%%rcx), %%rax"
151*053f45beSAndroid Build Coastguard Worker : : "c" (offset) : "rax");
152*053f45beSAndroid Build Coastguard Worker }
153*053f45beSAndroid Build Coastguard Worker if (!want_segv)
154*053f45beSAndroid Build Coastguard Worker return segv_addr + offset;
155*053f45beSAndroid Build Coastguard Worker
156*053f45beSAndroid Build Coastguard Worker abort();
157*053f45beSAndroid Build Coastguard Worker }
158*053f45beSAndroid Build Coastguard Worker
check_gs_value(unsigned long value)159*053f45beSAndroid Build Coastguard Worker static void check_gs_value(unsigned long value)
160*053f45beSAndroid Build Coastguard Worker {
161*053f45beSAndroid Build Coastguard Worker unsigned long base;
162*053f45beSAndroid Build Coastguard Worker unsigned short sel;
163*053f45beSAndroid Build Coastguard Worker
164*053f45beSAndroid Build Coastguard Worker printf("[RUN]\tARCH_SET_GS to 0x%lx\n", value);
165*053f45beSAndroid Build Coastguard Worker if (syscall(SYS_arch_prctl, ARCH_SET_GS, value) != 0)
166*053f45beSAndroid Build Coastguard Worker err(1, "ARCH_SET_GS");
167*053f45beSAndroid Build Coastguard Worker
168*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %%gs, %0" : "=rm" (sel));
169*053f45beSAndroid Build Coastguard Worker base = read_base(GS);
170*053f45beSAndroid Build Coastguard Worker if (base == value) {
171*053f45beSAndroid Build Coastguard Worker printf("[OK]\tGSBASE was set as expected (selector 0x%hx)\n",
172*053f45beSAndroid Build Coastguard Worker sel);
173*053f45beSAndroid Build Coastguard Worker } else {
174*053f45beSAndroid Build Coastguard Worker nerrs++;
175*053f45beSAndroid Build Coastguard Worker printf("[FAIL]\tGSBASE was not as expected: got 0x%lx (selector 0x%hx)\n",
176*053f45beSAndroid Build Coastguard Worker base, sel);
177*053f45beSAndroid Build Coastguard Worker }
178*053f45beSAndroid Build Coastguard Worker
179*053f45beSAndroid Build Coastguard Worker if (syscall(SYS_arch_prctl, ARCH_GET_GS, &base) != 0)
180*053f45beSAndroid Build Coastguard Worker err(1, "ARCH_GET_GS");
181*053f45beSAndroid Build Coastguard Worker if (base == value) {
182*053f45beSAndroid Build Coastguard Worker printf("[OK]\tARCH_GET_GS worked as expected (selector 0x%hx)\n",
183*053f45beSAndroid Build Coastguard Worker sel);
184*053f45beSAndroid Build Coastguard Worker } else {
185*053f45beSAndroid Build Coastguard Worker nerrs++;
186*053f45beSAndroid Build Coastguard Worker printf("[FAIL]\tARCH_GET_GS was not as expected: got 0x%lx (selector 0x%hx)\n",
187*053f45beSAndroid Build Coastguard Worker base, sel);
188*053f45beSAndroid Build Coastguard Worker }
189*053f45beSAndroid Build Coastguard Worker }
190*053f45beSAndroid Build Coastguard Worker
mov_0_gs(unsigned long initial_base,bool schedule)191*053f45beSAndroid Build Coastguard Worker static void mov_0_gs(unsigned long initial_base, bool schedule)
192*053f45beSAndroid Build Coastguard Worker {
193*053f45beSAndroid Build Coastguard Worker unsigned long base, arch_base;
194*053f45beSAndroid Build Coastguard Worker
195*053f45beSAndroid Build Coastguard Worker printf("[RUN]\tARCH_SET_GS to 0x%lx then mov 0 to %%gs%s\n", initial_base, schedule ? " and schedule " : "");
196*053f45beSAndroid Build Coastguard Worker if (syscall(SYS_arch_prctl, ARCH_SET_GS, initial_base) != 0)
197*053f45beSAndroid Build Coastguard Worker err(1, "ARCH_SET_GS");
198*053f45beSAndroid Build Coastguard Worker
199*053f45beSAndroid Build Coastguard Worker if (schedule)
200*053f45beSAndroid Build Coastguard Worker usleep(10);
201*053f45beSAndroid Build Coastguard Worker
202*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %0, %%gs" : : "rm" (0));
203*053f45beSAndroid Build Coastguard Worker base = read_base(GS);
204*053f45beSAndroid Build Coastguard Worker if (syscall(SYS_arch_prctl, ARCH_GET_GS, &arch_base) != 0)
205*053f45beSAndroid Build Coastguard Worker err(1, "ARCH_GET_GS");
206*053f45beSAndroid Build Coastguard Worker if (base == arch_base) {
207*053f45beSAndroid Build Coastguard Worker printf("[OK]\tGSBASE is 0x%lx\n", base);
208*053f45beSAndroid Build Coastguard Worker } else {
209*053f45beSAndroid Build Coastguard Worker nerrs++;
210*053f45beSAndroid Build Coastguard Worker printf("[FAIL]\tGSBASE changed to 0x%lx but kernel reports 0x%lx\n", base, arch_base);
211*053f45beSAndroid Build Coastguard Worker }
212*053f45beSAndroid Build Coastguard Worker }
213*053f45beSAndroid Build Coastguard Worker
214*053f45beSAndroid Build Coastguard Worker static volatile unsigned long remote_base;
215*053f45beSAndroid Build Coastguard Worker static volatile bool remote_hard_zero;
216*053f45beSAndroid Build Coastguard Worker static volatile unsigned int ftx;
217*053f45beSAndroid Build Coastguard Worker
218*053f45beSAndroid Build Coastguard Worker /*
219*053f45beSAndroid Build Coastguard Worker * ARCH_SET_FS/GS(0) may or may not program a selector of zero. HARD_ZERO
220*053f45beSAndroid Build Coastguard Worker * means to force the selector to zero to improve test coverage.
221*053f45beSAndroid Build Coastguard Worker */
222*053f45beSAndroid Build Coastguard Worker #define HARD_ZERO 0xa1fa5f343cb85fa4
223*053f45beSAndroid Build Coastguard Worker
do_remote_base()224*053f45beSAndroid Build Coastguard Worker static void do_remote_base()
225*053f45beSAndroid Build Coastguard Worker {
226*053f45beSAndroid Build Coastguard Worker unsigned long to_set = remote_base;
227*053f45beSAndroid Build Coastguard Worker bool hard_zero = false;
228*053f45beSAndroid Build Coastguard Worker if (to_set == HARD_ZERO) {
229*053f45beSAndroid Build Coastguard Worker to_set = 0;
230*053f45beSAndroid Build Coastguard Worker hard_zero = true;
231*053f45beSAndroid Build Coastguard Worker }
232*053f45beSAndroid Build Coastguard Worker
233*053f45beSAndroid Build Coastguard Worker if (syscall(SYS_arch_prctl, ARCH_SET_GS, to_set) != 0)
234*053f45beSAndroid Build Coastguard Worker err(1, "ARCH_SET_GS");
235*053f45beSAndroid Build Coastguard Worker
236*053f45beSAndroid Build Coastguard Worker if (hard_zero)
237*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
238*053f45beSAndroid Build Coastguard Worker
239*053f45beSAndroid Build Coastguard Worker unsigned short sel;
240*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %%gs, %0" : "=rm" (sel));
241*053f45beSAndroid Build Coastguard Worker printf("\tother thread: ARCH_SET_GS(0x%lx)%s -- sel is 0x%hx\n",
242*053f45beSAndroid Build Coastguard Worker to_set, hard_zero ? " and clear gs" : "", sel);
243*053f45beSAndroid Build Coastguard Worker }
244*053f45beSAndroid Build Coastguard Worker
245*053f45beSAndroid Build Coastguard Worker static __thread int set_thread_area_entry_number = -1;
246*053f45beSAndroid Build Coastguard Worker
load_gs(void)247*053f45beSAndroid Build Coastguard Worker static unsigned short load_gs(void)
248*053f45beSAndroid Build Coastguard Worker {
249*053f45beSAndroid Build Coastguard Worker /*
250*053f45beSAndroid Build Coastguard Worker * Sets GS != 0 and GSBASE != 0 but arranges for the kernel to think
251*053f45beSAndroid Build Coastguard Worker * that GSBASE == 0 (i.e. thread.gsbase == 0).
252*053f45beSAndroid Build Coastguard Worker */
253*053f45beSAndroid Build Coastguard Worker
254*053f45beSAndroid Build Coastguard Worker /* Step 1: tell the kernel that we have GSBASE == 0. */
255*053f45beSAndroid Build Coastguard Worker if (syscall(SYS_arch_prctl, ARCH_SET_GS, 0) != 0)
256*053f45beSAndroid Build Coastguard Worker err(1, "ARCH_SET_GS");
257*053f45beSAndroid Build Coastguard Worker
258*053f45beSAndroid Build Coastguard Worker /* Step 2: change GSBASE without telling the kernel. */
259*053f45beSAndroid Build Coastguard Worker struct user_desc desc = {
260*053f45beSAndroid Build Coastguard Worker .entry_number = 0,
261*053f45beSAndroid Build Coastguard Worker .base_addr = 0xBAADF00D,
262*053f45beSAndroid Build Coastguard Worker .limit = 0xfffff,
263*053f45beSAndroid Build Coastguard Worker .seg_32bit = 1,
264*053f45beSAndroid Build Coastguard Worker .contents = 0, /* Data, grow-up */
265*053f45beSAndroid Build Coastguard Worker .read_exec_only = 0,
266*053f45beSAndroid Build Coastguard Worker .limit_in_pages = 1,
267*053f45beSAndroid Build Coastguard Worker .seg_not_present = 0,
268*053f45beSAndroid Build Coastguard Worker .useable = 0
269*053f45beSAndroid Build Coastguard Worker };
270*053f45beSAndroid Build Coastguard Worker if (syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)) == 0) {
271*053f45beSAndroid Build Coastguard Worker printf("\tusing LDT slot 0\n");
272*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0x7));
273*053f45beSAndroid Build Coastguard Worker return 0x7;
274*053f45beSAndroid Build Coastguard Worker } else {
275*053f45beSAndroid Build Coastguard Worker /* No modify_ldt for us (configured out, perhaps) */
276*053f45beSAndroid Build Coastguard Worker
277*053f45beSAndroid Build Coastguard Worker struct user_desc *low_desc = mmap(
278*053f45beSAndroid Build Coastguard Worker NULL, sizeof(desc),
279*053f45beSAndroid Build Coastguard Worker PROT_READ | PROT_WRITE,
280*053f45beSAndroid Build Coastguard Worker MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
281*053f45beSAndroid Build Coastguard Worker memcpy(low_desc, &desc, sizeof(desc));
282*053f45beSAndroid Build Coastguard Worker
283*053f45beSAndroid Build Coastguard Worker low_desc->entry_number = set_thread_area_entry_number;
284*053f45beSAndroid Build Coastguard Worker
285*053f45beSAndroid Build Coastguard Worker /* 32-bit set_thread_area */
286*053f45beSAndroid Build Coastguard Worker long ret;
287*053f45beSAndroid Build Coastguard Worker asm volatile ("int $0x80"
288*053f45beSAndroid Build Coastguard Worker : "=a" (ret), "+m" (*low_desc)
289*053f45beSAndroid Build Coastguard Worker : "a" (243), "b" (low_desc)
290*053f45beSAndroid Build Coastguard Worker : "r8", "r9", "r10", "r11");
291*053f45beSAndroid Build Coastguard Worker memcpy(&desc, low_desc, sizeof(desc));
292*053f45beSAndroid Build Coastguard Worker munmap(low_desc, sizeof(desc));
293*053f45beSAndroid Build Coastguard Worker
294*053f45beSAndroid Build Coastguard Worker if (ret != 0) {
295*053f45beSAndroid Build Coastguard Worker printf("[NOTE]\tcould not create a segment -- test won't do anything\n");
296*053f45beSAndroid Build Coastguard Worker return 0;
297*053f45beSAndroid Build Coastguard Worker }
298*053f45beSAndroid Build Coastguard Worker printf("\tusing GDT slot %d\n", desc.entry_number);
299*053f45beSAndroid Build Coastguard Worker set_thread_area_entry_number = desc.entry_number;
300*053f45beSAndroid Build Coastguard Worker
301*053f45beSAndroid Build Coastguard Worker unsigned short gs = (unsigned short)((desc.entry_number << 3) | 0x3);
302*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %0, %%gs" : : "rm" (gs));
303*053f45beSAndroid Build Coastguard Worker return gs;
304*053f45beSAndroid Build Coastguard Worker }
305*053f45beSAndroid Build Coastguard Worker }
306*053f45beSAndroid Build Coastguard Worker
test_wrbase(unsigned short index,unsigned long base)307*053f45beSAndroid Build Coastguard Worker void test_wrbase(unsigned short index, unsigned long base)
308*053f45beSAndroid Build Coastguard Worker {
309*053f45beSAndroid Build Coastguard Worker unsigned short newindex;
310*053f45beSAndroid Build Coastguard Worker unsigned long newbase;
311*053f45beSAndroid Build Coastguard Worker
312*053f45beSAndroid Build Coastguard Worker printf("[RUN]\tGS = 0x%hx, GSBASE = 0x%lx\n", index, base);
313*053f45beSAndroid Build Coastguard Worker
314*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %0, %%gs" : : "rm" (index));
315*053f45beSAndroid Build Coastguard Worker wrgsbase(base);
316*053f45beSAndroid Build Coastguard Worker
317*053f45beSAndroid Build Coastguard Worker remote_base = 0;
318*053f45beSAndroid Build Coastguard Worker ftx = 1;
319*053f45beSAndroid Build Coastguard Worker syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
320*053f45beSAndroid Build Coastguard Worker while (ftx != 0)
321*053f45beSAndroid Build Coastguard Worker syscall(SYS_futex, &ftx, FUTEX_WAIT, 1, NULL, NULL, 0);
322*053f45beSAndroid Build Coastguard Worker
323*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %%gs, %0" : "=rm" (newindex));
324*053f45beSAndroid Build Coastguard Worker newbase = rdgsbase();
325*053f45beSAndroid Build Coastguard Worker
326*053f45beSAndroid Build Coastguard Worker if (newindex == index && newbase == base) {
327*053f45beSAndroid Build Coastguard Worker printf("[OK]\tIndex and base were preserved\n");
328*053f45beSAndroid Build Coastguard Worker } else {
329*053f45beSAndroid Build Coastguard Worker printf("[FAIL]\tAfter switch, GS = 0x%hx and GSBASE = 0x%lx\n",
330*053f45beSAndroid Build Coastguard Worker newindex, newbase);
331*053f45beSAndroid Build Coastguard Worker nerrs++;
332*053f45beSAndroid Build Coastguard Worker }
333*053f45beSAndroid Build Coastguard Worker }
334*053f45beSAndroid Build Coastguard Worker
threadproc(void * ctx)335*053f45beSAndroid Build Coastguard Worker static void *threadproc(void *ctx)
336*053f45beSAndroid Build Coastguard Worker {
337*053f45beSAndroid Build Coastguard Worker while (1) {
338*053f45beSAndroid Build Coastguard Worker while (ftx == 0)
339*053f45beSAndroid Build Coastguard Worker syscall(SYS_futex, &ftx, FUTEX_WAIT, 0, NULL, NULL, 0);
340*053f45beSAndroid Build Coastguard Worker if (ftx == 3)
341*053f45beSAndroid Build Coastguard Worker return NULL;
342*053f45beSAndroid Build Coastguard Worker
343*053f45beSAndroid Build Coastguard Worker if (ftx == 1) {
344*053f45beSAndroid Build Coastguard Worker do_remote_base();
345*053f45beSAndroid Build Coastguard Worker } else if (ftx == 2) {
346*053f45beSAndroid Build Coastguard Worker /*
347*053f45beSAndroid Build Coastguard Worker * On AMD chips, this causes GSBASE != 0, GS == 0, and
348*053f45beSAndroid Build Coastguard Worker * thread.gsbase == 0.
349*053f45beSAndroid Build Coastguard Worker */
350*053f45beSAndroid Build Coastguard Worker
351*053f45beSAndroid Build Coastguard Worker load_gs();
352*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
353*053f45beSAndroid Build Coastguard Worker } else {
354*053f45beSAndroid Build Coastguard Worker errx(1, "helper thread got bad command");
355*053f45beSAndroid Build Coastguard Worker }
356*053f45beSAndroid Build Coastguard Worker
357*053f45beSAndroid Build Coastguard Worker ftx = 0;
358*053f45beSAndroid Build Coastguard Worker syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
359*053f45beSAndroid Build Coastguard Worker }
360*053f45beSAndroid Build Coastguard Worker }
361*053f45beSAndroid Build Coastguard Worker
set_gs_and_switch_to(unsigned long local,unsigned short force_sel,unsigned long remote)362*053f45beSAndroid Build Coastguard Worker static void set_gs_and_switch_to(unsigned long local,
363*053f45beSAndroid Build Coastguard Worker unsigned short force_sel,
364*053f45beSAndroid Build Coastguard Worker unsigned long remote)
365*053f45beSAndroid Build Coastguard Worker {
366*053f45beSAndroid Build Coastguard Worker unsigned long base;
367*053f45beSAndroid Build Coastguard Worker unsigned short sel_pre_sched, sel_post_sched;
368*053f45beSAndroid Build Coastguard Worker
369*053f45beSAndroid Build Coastguard Worker bool hard_zero = false;
370*053f45beSAndroid Build Coastguard Worker if (local == HARD_ZERO) {
371*053f45beSAndroid Build Coastguard Worker hard_zero = true;
372*053f45beSAndroid Build Coastguard Worker local = 0;
373*053f45beSAndroid Build Coastguard Worker }
374*053f45beSAndroid Build Coastguard Worker
375*053f45beSAndroid Build Coastguard Worker printf("[RUN]\tARCH_SET_GS(0x%lx)%s, then schedule to 0x%lx\n",
376*053f45beSAndroid Build Coastguard Worker local, hard_zero ? " and clear gs" : "", remote);
377*053f45beSAndroid Build Coastguard Worker if (force_sel)
378*053f45beSAndroid Build Coastguard Worker printf("\tBefore schedule, set selector to 0x%hx\n", force_sel);
379*053f45beSAndroid Build Coastguard Worker if (syscall(SYS_arch_prctl, ARCH_SET_GS, local) != 0)
380*053f45beSAndroid Build Coastguard Worker err(1, "ARCH_SET_GS");
381*053f45beSAndroid Build Coastguard Worker if (hard_zero)
382*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
383*053f45beSAndroid Build Coastguard Worker
384*053f45beSAndroid Build Coastguard Worker if (read_base(GS) != local) {
385*053f45beSAndroid Build Coastguard Worker nerrs++;
386*053f45beSAndroid Build Coastguard Worker printf("[FAIL]\tGSBASE wasn't set as expected\n");
387*053f45beSAndroid Build Coastguard Worker }
388*053f45beSAndroid Build Coastguard Worker
389*053f45beSAndroid Build Coastguard Worker if (force_sel) {
390*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %0, %%gs" : : "rm" (force_sel));
391*053f45beSAndroid Build Coastguard Worker sel_pre_sched = force_sel;
392*053f45beSAndroid Build Coastguard Worker local = read_base(GS);
393*053f45beSAndroid Build Coastguard Worker
394*053f45beSAndroid Build Coastguard Worker /*
395*053f45beSAndroid Build Coastguard Worker * Signal delivery is quite likely to change a selector
396*053f45beSAndroid Build Coastguard Worker * of 1, 2, or 3 back to 0 due to IRET being defective.
397*053f45beSAndroid Build Coastguard Worker */
398*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %0, %%gs" : : "rm" (force_sel));
399*053f45beSAndroid Build Coastguard Worker } else {
400*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %%gs, %0" : "=rm" (sel_pre_sched));
401*053f45beSAndroid Build Coastguard Worker }
402*053f45beSAndroid Build Coastguard Worker
403*053f45beSAndroid Build Coastguard Worker remote_base = remote;
404*053f45beSAndroid Build Coastguard Worker ftx = 1;
405*053f45beSAndroid Build Coastguard Worker syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
406*053f45beSAndroid Build Coastguard Worker while (ftx != 0)
407*053f45beSAndroid Build Coastguard Worker syscall(SYS_futex, &ftx, FUTEX_WAIT, 1, NULL, NULL, 0);
408*053f45beSAndroid Build Coastguard Worker
409*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %%gs, %0" : "=rm" (sel_post_sched));
410*053f45beSAndroid Build Coastguard Worker base = read_base(GS);
411*053f45beSAndroid Build Coastguard Worker if (base == local && sel_pre_sched == sel_post_sched) {
412*053f45beSAndroid Build Coastguard Worker printf("[OK]\tGS/BASE remained 0x%hx/0x%lx\n",
413*053f45beSAndroid Build Coastguard Worker sel_pre_sched, local);
414*053f45beSAndroid Build Coastguard Worker } else if (base == local && sel_pre_sched >= 1 && sel_pre_sched <= 3 &&
415*053f45beSAndroid Build Coastguard Worker sel_post_sched == 0) {
416*053f45beSAndroid Build Coastguard Worker /*
417*053f45beSAndroid Build Coastguard Worker * IRET is misdesigned and will squash selectors 1, 2, or 3
418*053f45beSAndroid Build Coastguard Worker * to zero. Don't fail the test just because this happened.
419*053f45beSAndroid Build Coastguard Worker */
420*053f45beSAndroid Build Coastguard Worker printf("[OK]\tGS/BASE changed from 0x%hx/0x%lx to 0x%hx/0x%lx because IRET is defective\n",
421*053f45beSAndroid Build Coastguard Worker sel_pre_sched, local, sel_post_sched, base);
422*053f45beSAndroid Build Coastguard Worker } else {
423*053f45beSAndroid Build Coastguard Worker nerrs++;
424*053f45beSAndroid Build Coastguard Worker printf("[FAIL]\tGS/BASE changed from 0x%hx/0x%lx to 0x%hx/0x%lx\n",
425*053f45beSAndroid Build Coastguard Worker sel_pre_sched, local, sel_post_sched, base);
426*053f45beSAndroid Build Coastguard Worker }
427*053f45beSAndroid Build Coastguard Worker }
428*053f45beSAndroid Build Coastguard Worker
test_unexpected_base(void)429*053f45beSAndroid Build Coastguard Worker static void test_unexpected_base(void)
430*053f45beSAndroid Build Coastguard Worker {
431*053f45beSAndroid Build Coastguard Worker unsigned long base;
432*053f45beSAndroid Build Coastguard Worker
433*053f45beSAndroid Build Coastguard Worker printf("[RUN]\tARCH_SET_GS(0), clear gs, then manipulate GSBASE in a different thread\n");
434*053f45beSAndroid Build Coastguard Worker if (syscall(SYS_arch_prctl, ARCH_SET_GS, 0) != 0)
435*053f45beSAndroid Build Coastguard Worker err(1, "ARCH_SET_GS");
436*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
437*053f45beSAndroid Build Coastguard Worker
438*053f45beSAndroid Build Coastguard Worker ftx = 2;
439*053f45beSAndroid Build Coastguard Worker syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
440*053f45beSAndroid Build Coastguard Worker while (ftx != 0)
441*053f45beSAndroid Build Coastguard Worker syscall(SYS_futex, &ftx, FUTEX_WAIT, 1, NULL, NULL, 0);
442*053f45beSAndroid Build Coastguard Worker
443*053f45beSAndroid Build Coastguard Worker base = read_base(GS);
444*053f45beSAndroid Build Coastguard Worker if (base == 0) {
445*053f45beSAndroid Build Coastguard Worker printf("[OK]\tGSBASE remained 0\n");
446*053f45beSAndroid Build Coastguard Worker } else {
447*053f45beSAndroid Build Coastguard Worker nerrs++;
448*053f45beSAndroid Build Coastguard Worker printf("[FAIL]\tGSBASE changed to 0x%lx\n", base);
449*053f45beSAndroid Build Coastguard Worker }
450*053f45beSAndroid Build Coastguard Worker }
451*053f45beSAndroid Build Coastguard Worker
452*053f45beSAndroid Build Coastguard Worker #define USER_REGS_OFFSET(r) offsetof(struct user_regs_struct, r)
453*053f45beSAndroid Build Coastguard Worker
test_ptrace_write_gs_read_base(void)454*053f45beSAndroid Build Coastguard Worker static void test_ptrace_write_gs_read_base(void)
455*053f45beSAndroid Build Coastguard Worker {
456*053f45beSAndroid Build Coastguard Worker int status;
457*053f45beSAndroid Build Coastguard Worker pid_t child = fork();
458*053f45beSAndroid Build Coastguard Worker
459*053f45beSAndroid Build Coastguard Worker if (child < 0)
460*053f45beSAndroid Build Coastguard Worker err(1, "fork");
461*053f45beSAndroid Build Coastguard Worker
462*053f45beSAndroid Build Coastguard Worker if (child == 0) {
463*053f45beSAndroid Build Coastguard Worker printf("[RUN]\tPTRACE_POKE GS, read GSBASE back\n");
464*053f45beSAndroid Build Coastguard Worker
465*053f45beSAndroid Build Coastguard Worker printf("[RUN]\tARCH_SET_GS to 1\n");
466*053f45beSAndroid Build Coastguard Worker if (syscall(SYS_arch_prctl, ARCH_SET_GS, 1) != 0)
467*053f45beSAndroid Build Coastguard Worker err(1, "ARCH_SET_GS");
468*053f45beSAndroid Build Coastguard Worker
469*053f45beSAndroid Build Coastguard Worker if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0)
470*053f45beSAndroid Build Coastguard Worker err(1, "PTRACE_TRACEME");
471*053f45beSAndroid Build Coastguard Worker
472*053f45beSAndroid Build Coastguard Worker raise(SIGTRAP);
473*053f45beSAndroid Build Coastguard Worker _exit(0);
474*053f45beSAndroid Build Coastguard Worker }
475*053f45beSAndroid Build Coastguard Worker
476*053f45beSAndroid Build Coastguard Worker wait(&status);
477*053f45beSAndroid Build Coastguard Worker
478*053f45beSAndroid Build Coastguard Worker if (WSTOPSIG(status) == SIGTRAP) {
479*053f45beSAndroid Build Coastguard Worker unsigned long base;
480*053f45beSAndroid Build Coastguard Worker unsigned long gs_offset = USER_REGS_OFFSET(gs);
481*053f45beSAndroid Build Coastguard Worker unsigned long base_offset = USER_REGS_OFFSET(gs_base);
482*053f45beSAndroid Build Coastguard Worker
483*053f45beSAndroid Build Coastguard Worker /* Read the initial base. It should be 1. */
484*053f45beSAndroid Build Coastguard Worker base = ptrace(PTRACE_PEEKUSER, child, base_offset, NULL);
485*053f45beSAndroid Build Coastguard Worker if (base == 1) {
486*053f45beSAndroid Build Coastguard Worker printf("[OK]\tGSBASE started at 1\n");
487*053f45beSAndroid Build Coastguard Worker } else {
488*053f45beSAndroid Build Coastguard Worker nerrs++;
489*053f45beSAndroid Build Coastguard Worker printf("[FAIL]\tGSBASE started at 0x%lx\n", base);
490*053f45beSAndroid Build Coastguard Worker }
491*053f45beSAndroid Build Coastguard Worker
492*053f45beSAndroid Build Coastguard Worker printf("[RUN]\tSet GS = 0x7, read GSBASE\n");
493*053f45beSAndroid Build Coastguard Worker
494*053f45beSAndroid Build Coastguard Worker /* Poke an LDT selector into GS. */
495*053f45beSAndroid Build Coastguard Worker if (ptrace(PTRACE_POKEUSER, child, gs_offset, 0x7) != 0)
496*053f45beSAndroid Build Coastguard Worker err(1, "PTRACE_POKEUSER");
497*053f45beSAndroid Build Coastguard Worker
498*053f45beSAndroid Build Coastguard Worker /* And read the base. */
499*053f45beSAndroid Build Coastguard Worker base = ptrace(PTRACE_PEEKUSER, child, base_offset, NULL);
500*053f45beSAndroid Build Coastguard Worker
501*053f45beSAndroid Build Coastguard Worker if (base == 0 || base == 1) {
502*053f45beSAndroid Build Coastguard Worker printf("[OK]\tGSBASE reads as 0x%lx with invalid GS\n", base);
503*053f45beSAndroid Build Coastguard Worker } else {
504*053f45beSAndroid Build Coastguard Worker nerrs++;
505*053f45beSAndroid Build Coastguard Worker printf("[FAIL]\tGSBASE=0x%lx (should be 0 or 1)\n", base);
506*053f45beSAndroid Build Coastguard Worker }
507*053f45beSAndroid Build Coastguard Worker }
508*053f45beSAndroid Build Coastguard Worker
509*053f45beSAndroid Build Coastguard Worker ptrace(PTRACE_CONT, child, NULL, NULL);
510*053f45beSAndroid Build Coastguard Worker
511*053f45beSAndroid Build Coastguard Worker wait(&status);
512*053f45beSAndroid Build Coastguard Worker if (!WIFEXITED(status))
513*053f45beSAndroid Build Coastguard Worker printf("[WARN]\tChild didn't exit cleanly.\n");
514*053f45beSAndroid Build Coastguard Worker }
515*053f45beSAndroid Build Coastguard Worker
test_ptrace_write_gsbase(void)516*053f45beSAndroid Build Coastguard Worker static void test_ptrace_write_gsbase(void)
517*053f45beSAndroid Build Coastguard Worker {
518*053f45beSAndroid Build Coastguard Worker int status;
519*053f45beSAndroid Build Coastguard Worker pid_t child = fork();
520*053f45beSAndroid Build Coastguard Worker
521*053f45beSAndroid Build Coastguard Worker if (child < 0)
522*053f45beSAndroid Build Coastguard Worker err(1, "fork");
523*053f45beSAndroid Build Coastguard Worker
524*053f45beSAndroid Build Coastguard Worker if (child == 0) {
525*053f45beSAndroid Build Coastguard Worker printf("[RUN]\tPTRACE_POKE(), write GSBASE from ptracer\n");
526*053f45beSAndroid Build Coastguard Worker
527*053f45beSAndroid Build Coastguard Worker *shared_scratch = load_gs();
528*053f45beSAndroid Build Coastguard Worker
529*053f45beSAndroid Build Coastguard Worker if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0)
530*053f45beSAndroid Build Coastguard Worker err(1, "PTRACE_TRACEME");
531*053f45beSAndroid Build Coastguard Worker
532*053f45beSAndroid Build Coastguard Worker raise(SIGTRAP);
533*053f45beSAndroid Build Coastguard Worker _exit(0);
534*053f45beSAndroid Build Coastguard Worker }
535*053f45beSAndroid Build Coastguard Worker
536*053f45beSAndroid Build Coastguard Worker wait(&status);
537*053f45beSAndroid Build Coastguard Worker
538*053f45beSAndroid Build Coastguard Worker if (WSTOPSIG(status) == SIGTRAP) {
539*053f45beSAndroid Build Coastguard Worker unsigned long gs, base;
540*053f45beSAndroid Build Coastguard Worker unsigned long gs_offset = USER_REGS_OFFSET(gs);
541*053f45beSAndroid Build Coastguard Worker unsigned long base_offset = USER_REGS_OFFSET(gs_base);
542*053f45beSAndroid Build Coastguard Worker
543*053f45beSAndroid Build Coastguard Worker gs = ptrace(PTRACE_PEEKUSER, child, gs_offset, NULL);
544*053f45beSAndroid Build Coastguard Worker
545*053f45beSAndroid Build Coastguard Worker if (gs != *shared_scratch) {
546*053f45beSAndroid Build Coastguard Worker nerrs++;
547*053f45beSAndroid Build Coastguard Worker printf("[FAIL]\tGS is not prepared with nonzero\n");
548*053f45beSAndroid Build Coastguard Worker goto END;
549*053f45beSAndroid Build Coastguard Worker }
550*053f45beSAndroid Build Coastguard Worker
551*053f45beSAndroid Build Coastguard Worker if (ptrace(PTRACE_POKEUSER, child, base_offset, 0xFF) != 0)
552*053f45beSAndroid Build Coastguard Worker err(1, "PTRACE_POKEUSER");
553*053f45beSAndroid Build Coastguard Worker
554*053f45beSAndroid Build Coastguard Worker gs = ptrace(PTRACE_PEEKUSER, child, gs_offset, NULL);
555*053f45beSAndroid Build Coastguard Worker base = ptrace(PTRACE_PEEKUSER, child, base_offset, NULL);
556*053f45beSAndroid Build Coastguard Worker
557*053f45beSAndroid Build Coastguard Worker /*
558*053f45beSAndroid Build Coastguard Worker * In a non-FSGSBASE system, the nonzero selector will load
559*053f45beSAndroid Build Coastguard Worker * GSBASE (again). But what is tested here is whether the
560*053f45beSAndroid Build Coastguard Worker * selector value is changed or not by the GSBASE write in
561*053f45beSAndroid Build Coastguard Worker * a ptracer.
562*053f45beSAndroid Build Coastguard Worker */
563*053f45beSAndroid Build Coastguard Worker if (gs != *shared_scratch) {
564*053f45beSAndroid Build Coastguard Worker nerrs++;
565*053f45beSAndroid Build Coastguard Worker printf("[FAIL]\tGS changed to %lx\n", gs);
566*053f45beSAndroid Build Coastguard Worker
567*053f45beSAndroid Build Coastguard Worker /*
568*053f45beSAndroid Build Coastguard Worker * On older kernels, poking a nonzero value into the
569*053f45beSAndroid Build Coastguard Worker * base would zero the selector. On newer kernels,
570*053f45beSAndroid Build Coastguard Worker * this behavior has changed -- poking the base
571*053f45beSAndroid Build Coastguard Worker * changes only the base and, if FSGSBASE is not
572*053f45beSAndroid Build Coastguard Worker * available, this may have no effect once the tracee
573*053f45beSAndroid Build Coastguard Worker * is resumed.
574*053f45beSAndroid Build Coastguard Worker */
575*053f45beSAndroid Build Coastguard Worker if (gs == 0)
576*053f45beSAndroid Build Coastguard Worker printf("\tNote: this is expected behavior on older kernels.\n");
577*053f45beSAndroid Build Coastguard Worker } else if (have_fsgsbase && (base != 0xFF)) {
578*053f45beSAndroid Build Coastguard Worker nerrs++;
579*053f45beSAndroid Build Coastguard Worker printf("[FAIL]\tGSBASE changed to %lx\n", base);
580*053f45beSAndroid Build Coastguard Worker } else {
581*053f45beSAndroid Build Coastguard Worker printf("[OK]\tGS remained 0x%hx", *shared_scratch);
582*053f45beSAndroid Build Coastguard Worker if (have_fsgsbase)
583*053f45beSAndroid Build Coastguard Worker printf(" and GSBASE changed to 0xFF");
584*053f45beSAndroid Build Coastguard Worker printf("\n");
585*053f45beSAndroid Build Coastguard Worker }
586*053f45beSAndroid Build Coastguard Worker }
587*053f45beSAndroid Build Coastguard Worker
588*053f45beSAndroid Build Coastguard Worker END:
589*053f45beSAndroid Build Coastguard Worker ptrace(PTRACE_CONT, child, NULL, NULL);
590*053f45beSAndroid Build Coastguard Worker wait(&status);
591*053f45beSAndroid Build Coastguard Worker if (!WIFEXITED(status))
592*053f45beSAndroid Build Coastguard Worker printf("[WARN]\tChild didn't exit cleanly.\n");
593*053f45beSAndroid Build Coastguard Worker }
594*053f45beSAndroid Build Coastguard Worker
main()595*053f45beSAndroid Build Coastguard Worker int main()
596*053f45beSAndroid Build Coastguard Worker {
597*053f45beSAndroid Build Coastguard Worker pthread_t thread;
598*053f45beSAndroid Build Coastguard Worker
599*053f45beSAndroid Build Coastguard Worker shared_scratch = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
600*053f45beSAndroid Build Coastguard Worker MAP_ANONYMOUS | MAP_SHARED, -1, 0);
601*053f45beSAndroid Build Coastguard Worker
602*053f45beSAndroid Build Coastguard Worker /* Do these tests before we have an LDT. */
603*053f45beSAndroid Build Coastguard Worker test_ptrace_write_gs_read_base();
604*053f45beSAndroid Build Coastguard Worker
605*053f45beSAndroid Build Coastguard Worker /* Probe FSGSBASE */
606*053f45beSAndroid Build Coastguard Worker sethandler(SIGILL, sigill, 0);
607*053f45beSAndroid Build Coastguard Worker if (sigsetjmp(jmpbuf, 1) == 0) {
608*053f45beSAndroid Build Coastguard Worker rdfsbase();
609*053f45beSAndroid Build Coastguard Worker have_fsgsbase = true;
610*053f45beSAndroid Build Coastguard Worker printf("\tFSGSBASE instructions are enabled\n");
611*053f45beSAndroid Build Coastguard Worker } else {
612*053f45beSAndroid Build Coastguard Worker printf("\tFSGSBASE instructions are disabled\n");
613*053f45beSAndroid Build Coastguard Worker }
614*053f45beSAndroid Build Coastguard Worker clearhandler(SIGILL);
615*053f45beSAndroid Build Coastguard Worker
616*053f45beSAndroid Build Coastguard Worker sethandler(SIGSEGV, sigsegv, 0);
617*053f45beSAndroid Build Coastguard Worker
618*053f45beSAndroid Build Coastguard Worker check_gs_value(0);
619*053f45beSAndroid Build Coastguard Worker check_gs_value(1);
620*053f45beSAndroid Build Coastguard Worker check_gs_value(0x200000000);
621*053f45beSAndroid Build Coastguard Worker check_gs_value(0);
622*053f45beSAndroid Build Coastguard Worker check_gs_value(0x200000000);
623*053f45beSAndroid Build Coastguard Worker check_gs_value(1);
624*053f45beSAndroid Build Coastguard Worker
625*053f45beSAndroid Build Coastguard Worker for (int sched = 0; sched < 2; sched++) {
626*053f45beSAndroid Build Coastguard Worker mov_0_gs(0, !!sched);
627*053f45beSAndroid Build Coastguard Worker mov_0_gs(1, !!sched);
628*053f45beSAndroid Build Coastguard Worker mov_0_gs(0x200000000, !!sched);
629*053f45beSAndroid Build Coastguard Worker }
630*053f45beSAndroid Build Coastguard Worker
631*053f45beSAndroid Build Coastguard Worker /* Set up for multithreading. */
632*053f45beSAndroid Build Coastguard Worker
633*053f45beSAndroid Build Coastguard Worker cpu_set_t cpuset;
634*053f45beSAndroid Build Coastguard Worker CPU_ZERO(&cpuset);
635*053f45beSAndroid Build Coastguard Worker CPU_SET(0, &cpuset);
636*053f45beSAndroid Build Coastguard Worker if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
637*053f45beSAndroid Build Coastguard Worker err(1, "sched_setaffinity to CPU 0"); /* should never fail */
638*053f45beSAndroid Build Coastguard Worker
639*053f45beSAndroid Build Coastguard Worker if (pthread_create(&thread, 0, threadproc, 0) != 0)
640*053f45beSAndroid Build Coastguard Worker err(1, "pthread_create");
641*053f45beSAndroid Build Coastguard Worker
642*053f45beSAndroid Build Coastguard Worker static unsigned long bases_with_hard_zero[] = {
643*053f45beSAndroid Build Coastguard Worker 0, HARD_ZERO, 1, 0x200000000,
644*053f45beSAndroid Build Coastguard Worker };
645*053f45beSAndroid Build Coastguard Worker
646*053f45beSAndroid Build Coastguard Worker for (int local = 0; local < 4; local++) {
647*053f45beSAndroid Build Coastguard Worker for (int remote = 0; remote < 4; remote++) {
648*053f45beSAndroid Build Coastguard Worker for (unsigned short s = 0; s < 5; s++) {
649*053f45beSAndroid Build Coastguard Worker unsigned short sel = s;
650*053f45beSAndroid Build Coastguard Worker if (s == 4)
651*053f45beSAndroid Build Coastguard Worker asm ("mov %%ss, %0" : "=rm" (sel));
652*053f45beSAndroid Build Coastguard Worker set_gs_and_switch_to(
653*053f45beSAndroid Build Coastguard Worker bases_with_hard_zero[local],
654*053f45beSAndroid Build Coastguard Worker sel,
655*053f45beSAndroid Build Coastguard Worker bases_with_hard_zero[remote]);
656*053f45beSAndroid Build Coastguard Worker }
657*053f45beSAndroid Build Coastguard Worker }
658*053f45beSAndroid Build Coastguard Worker }
659*053f45beSAndroid Build Coastguard Worker
660*053f45beSAndroid Build Coastguard Worker test_unexpected_base();
661*053f45beSAndroid Build Coastguard Worker
662*053f45beSAndroid Build Coastguard Worker if (have_fsgsbase) {
663*053f45beSAndroid Build Coastguard Worker unsigned short ss;
664*053f45beSAndroid Build Coastguard Worker
665*053f45beSAndroid Build Coastguard Worker asm volatile ("mov %%ss, %0" : "=rm" (ss));
666*053f45beSAndroid Build Coastguard Worker
667*053f45beSAndroid Build Coastguard Worker test_wrbase(0, 0);
668*053f45beSAndroid Build Coastguard Worker test_wrbase(0, 1);
669*053f45beSAndroid Build Coastguard Worker test_wrbase(0, 0x200000000);
670*053f45beSAndroid Build Coastguard Worker test_wrbase(0, 0xffffffffffffffff);
671*053f45beSAndroid Build Coastguard Worker test_wrbase(ss, 0);
672*053f45beSAndroid Build Coastguard Worker test_wrbase(ss, 1);
673*053f45beSAndroid Build Coastguard Worker test_wrbase(ss, 0x200000000);
674*053f45beSAndroid Build Coastguard Worker test_wrbase(ss, 0xffffffffffffffff);
675*053f45beSAndroid Build Coastguard Worker }
676*053f45beSAndroid Build Coastguard Worker
677*053f45beSAndroid Build Coastguard Worker ftx = 3; /* Kill the thread. */
678*053f45beSAndroid Build Coastguard Worker syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
679*053f45beSAndroid Build Coastguard Worker
680*053f45beSAndroid Build Coastguard Worker if (pthread_join(thread, NULL) != 0)
681*053f45beSAndroid Build Coastguard Worker err(1, "pthread_join");
682*053f45beSAndroid Build Coastguard Worker
683*053f45beSAndroid Build Coastguard Worker test_ptrace_write_gsbase();
684*053f45beSAndroid Build Coastguard Worker
685*053f45beSAndroid Build Coastguard Worker return nerrs == 0 ? 0 : 1;
686*053f45beSAndroid Build Coastguard Worker }
687