Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

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