xref: /aosp_15_r20/external/linux-kselftest/tools/testing/selftests/x86/fsgsbase.c (revision 053f45be4e351dfd5e965df293cd45b779f579ee)
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