corrupt_xstate_header.c (2151B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Corrupt the XSTATE header in a signal frame 4 * 5 * Based on analysis and a test case from Thomas Gleixner. 6 */ 7 8#define _GNU_SOURCE 9 10#include <stdlib.h> 11#include <stdio.h> 12#include <string.h> 13#include <sched.h> 14#include <signal.h> 15#include <err.h> 16#include <unistd.h> 17#include <stdint.h> 18#include <sys/wait.h> 19 20#include "../kselftest.h" /* For __cpuid_count() */ 21 22static inline int xsave_enabled(void) 23{ 24 unsigned int eax, ebx, ecx, edx; 25 26 __cpuid_count(0x1, 0x0, eax, ebx, ecx, edx); 27 28 /* Is CR4.OSXSAVE enabled ? */ 29 return ecx & (1U << 27); 30} 31 32static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), 33 int flags) 34{ 35 struct sigaction sa; 36 37 memset(&sa, 0, sizeof(sa)); 38 sa.sa_sigaction = handler; 39 sa.sa_flags = SA_SIGINFO | flags; 40 sigemptyset(&sa.sa_mask); 41 if (sigaction(sig, &sa, 0)) 42 err(1, "sigaction"); 43} 44 45static void sigusr1(int sig, siginfo_t *info, void *uc_void) 46{ 47 ucontext_t *uc = uc_void; 48 uint8_t *fpstate = (uint8_t *)uc->uc_mcontext.fpregs; 49 uint64_t *xfeatures = (uint64_t *)(fpstate + 512); 50 51 printf("\tWreck XSTATE header\n"); 52 /* Wreck the first reserved bytes in the header */ 53 *(xfeatures + 2) = 0xfffffff; 54} 55 56static void sigsegv(int sig, siginfo_t *info, void *uc_void) 57{ 58 printf("\tGot SIGSEGV\n"); 59} 60 61int main(void) 62{ 63 cpu_set_t set; 64 65 sethandler(SIGUSR1, sigusr1, 0); 66 sethandler(SIGSEGV, sigsegv, 0); 67 68 if (!xsave_enabled()) { 69 printf("[SKIP] CR4.OSXSAVE disabled.\n"); 70 return 0; 71 } 72 73 CPU_ZERO(&set); 74 CPU_SET(0, &set); 75 76 /* 77 * Enforce that the child runs on the same CPU 78 * which in turn forces a schedule. 79 */ 80 sched_setaffinity(getpid(), sizeof(set), &set); 81 82 printf("[RUN]\tSend ourselves a signal\n"); 83 raise(SIGUSR1); 84 85 printf("[OK]\tBack from the signal. Now schedule.\n"); 86 pid_t child = fork(); 87 if (child < 0) 88 err(1, "fork"); 89 if (child == 0) 90 return 0; 91 if (child) 92 waitpid(child, NULL, 0); 93 printf("[OK]\tBack in the main thread.\n"); 94 95 /* 96 * We could try to confirm that extended state is still preserved 97 * when we schedule. For now, the only indication of failure is 98 * a warning in the kernel logs. 99 */ 100 101 return 0; 102}