1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker * Copyright (c) 2017 Google, Inc.
4*49cdfc7eSAndroid Build Coastguard Worker */
5*49cdfc7eSAndroid Build Coastguard Worker
6*49cdfc7eSAndroid Build Coastguard Worker /*
7*49cdfc7eSAndroid Build Coastguard Worker * Regression test for commit 814fb7bb7db5 ("x86/fpu: Don't let userspace set
8*49cdfc7eSAndroid Build Coastguard Worker * bogus xcomp_bv"), or CVE-2017-15537. This bug allowed ptrace(pid,
9*49cdfc7eSAndroid Build Coastguard Worker * PTRACE_SETREGSET, NT_X86_XSTATE, &iov) to assign a task an invalid FPU state
10*49cdfc7eSAndroid Build Coastguard Worker * --- specifically, by setting reserved bits in xstate_header.xcomp_bv. This
11*49cdfc7eSAndroid Build Coastguard Worker * made restoring the FPU registers fail when switching to the task, causing the
12*49cdfc7eSAndroid Build Coastguard Worker * FPU registers to take on the values from other tasks.
13*49cdfc7eSAndroid Build Coastguard Worker *
14*49cdfc7eSAndroid Build Coastguard Worker * To detect the bug, we have a subprocess run a loop checking its xmm0 register
15*49cdfc7eSAndroid Build Coastguard Worker * for corruption. This detects the case where the FPU state became invalid and
16*49cdfc7eSAndroid Build Coastguard Worker * the kernel is not restoring the process's registers. Note that we have to
17*49cdfc7eSAndroid Build Coastguard Worker * set the expected value of xmm0 to all 0's since it is acceptable behavior for
18*49cdfc7eSAndroid Build Coastguard Worker * the kernel to simply reinitialize the FPU state upon seeing that it is
19*49cdfc7eSAndroid Build Coastguard Worker * invalid. To increase the chance of detecting the problem, we also create
20*49cdfc7eSAndroid Build Coastguard Worker * additional subprocesses that spin with different xmm0 contents.
21*49cdfc7eSAndroid Build Coastguard Worker *
22*49cdfc7eSAndroid Build Coastguard Worker * Thus bug affected the x86 architecture only. Other architectures could have
23*49cdfc7eSAndroid Build Coastguard Worker * similar bugs as well, but this test has to be x86-specific because it has to
24*49cdfc7eSAndroid Build Coastguard Worker * know about the architecture-dependent FPU state.
25*49cdfc7eSAndroid Build Coastguard Worker */
26*49cdfc7eSAndroid Build Coastguard Worker
27*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
28*49cdfc7eSAndroid Build Coastguard Worker
29*49cdfc7eSAndroid Build Coastguard Worker #ifdef __x86_64__
30*49cdfc7eSAndroid Build Coastguard Worker
31*49cdfc7eSAndroid Build Coastguard Worker #include <errno.h>
32*49cdfc7eSAndroid Build Coastguard Worker #include <inttypes.h>
33*49cdfc7eSAndroid Build Coastguard Worker #include <sched.h>
34*49cdfc7eSAndroid Build Coastguard Worker #include <stdbool.h>
35*49cdfc7eSAndroid Build Coastguard Worker #include <stdlib.h>
36*49cdfc7eSAndroid Build Coastguard Worker #include <sys/uio.h>
37*49cdfc7eSAndroid Build Coastguard Worker #include <sys/wait.h>
38*49cdfc7eSAndroid Build Coastguard Worker #include <sys/ptrace.h>
39*49cdfc7eSAndroid Build Coastguard Worker
40*49cdfc7eSAndroid Build Coastguard Worker #include "tst_safe_macros.h"
41*49cdfc7eSAndroid Build Coastguard Worker #include "lapi/cpuid.h"
42*49cdfc7eSAndroid Build Coastguard Worker
43*49cdfc7eSAndroid Build Coastguard Worker #ifndef PTRACE_GETREGSET
44*49cdfc7eSAndroid Build Coastguard Worker # define PTRACE_GETREGSET 0x4204
45*49cdfc7eSAndroid Build Coastguard Worker #endif
46*49cdfc7eSAndroid Build Coastguard Worker
47*49cdfc7eSAndroid Build Coastguard Worker #ifndef PTRACE_SETREGSET
48*49cdfc7eSAndroid Build Coastguard Worker # define PTRACE_SETREGSET 0x4205
49*49cdfc7eSAndroid Build Coastguard Worker #endif
50*49cdfc7eSAndroid Build Coastguard Worker
51*49cdfc7eSAndroid Build Coastguard Worker #ifndef NT_X86_XSTATE
52*49cdfc7eSAndroid Build Coastguard Worker # define NT_X86_XSTATE 0x202
53*49cdfc7eSAndroid Build Coastguard Worker #endif
54*49cdfc7eSAndroid Build Coastguard Worker
55*49cdfc7eSAndroid Build Coastguard Worker #ifndef CPUID_LEAF_XSTATE
56*49cdfc7eSAndroid Build Coastguard Worker # define CPUID_LEAF_XSTATE 0xd
57*49cdfc7eSAndroid Build Coastguard Worker #endif
58*49cdfc7eSAndroid Build Coastguard Worker
check_regs_loop(uint32_t initval)59*49cdfc7eSAndroid Build Coastguard Worker static void check_regs_loop(uint32_t initval)
60*49cdfc7eSAndroid Build Coastguard Worker {
61*49cdfc7eSAndroid Build Coastguard Worker const unsigned long num_iters = 1000000000;
62*49cdfc7eSAndroid Build Coastguard Worker uint32_t xmm0[4] = { initval, initval, initval, initval };
63*49cdfc7eSAndroid Build Coastguard Worker int status = 1;
64*49cdfc7eSAndroid Build Coastguard Worker
65*49cdfc7eSAndroid Build Coastguard Worker asm volatile(" movdqu %0, %%xmm0\n"
66*49cdfc7eSAndroid Build Coastguard Worker " mov %0, %%rbx\n"
67*49cdfc7eSAndroid Build Coastguard Worker "1: dec %2\n"
68*49cdfc7eSAndroid Build Coastguard Worker " jz 2f\n"
69*49cdfc7eSAndroid Build Coastguard Worker " movdqu %%xmm0, %0\n"
70*49cdfc7eSAndroid Build Coastguard Worker " mov %0, %%rax\n"
71*49cdfc7eSAndroid Build Coastguard Worker " cmp %%rax, %%rbx\n"
72*49cdfc7eSAndroid Build Coastguard Worker " je 1b\n"
73*49cdfc7eSAndroid Build Coastguard Worker " jmp 3f\n"
74*49cdfc7eSAndroid Build Coastguard Worker "2: mov $0, %1\n"
75*49cdfc7eSAndroid Build Coastguard Worker "3:\n"
76*49cdfc7eSAndroid Build Coastguard Worker : "+m" (xmm0), "+r" (status)
77*49cdfc7eSAndroid Build Coastguard Worker : "r" (num_iters) : "rax", "rbx", "xmm0");
78*49cdfc7eSAndroid Build Coastguard Worker
79*49cdfc7eSAndroid Build Coastguard Worker if (status) {
80*49cdfc7eSAndroid Build Coastguard Worker tst_res(TFAIL,
81*49cdfc7eSAndroid Build Coastguard Worker "xmm registers corrupted! initval=%08X, xmm0=%08X%08X%08X%08X\n",
82*49cdfc7eSAndroid Build Coastguard Worker initval, xmm0[0], xmm0[1], xmm0[2], xmm0[3]);
83*49cdfc7eSAndroid Build Coastguard Worker }
84*49cdfc7eSAndroid Build Coastguard Worker exit(status);
85*49cdfc7eSAndroid Build Coastguard Worker }
86*49cdfc7eSAndroid Build Coastguard Worker
do_test(void)87*49cdfc7eSAndroid Build Coastguard Worker static void do_test(void)
88*49cdfc7eSAndroid Build Coastguard Worker {
89*49cdfc7eSAndroid Build Coastguard Worker int i;
90*49cdfc7eSAndroid Build Coastguard Worker int num_cpus = tst_ncpus();
91*49cdfc7eSAndroid Build Coastguard Worker pid_t pid;
92*49cdfc7eSAndroid Build Coastguard Worker uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
93*49cdfc7eSAndroid Build Coastguard Worker uint64_t *xstate;
94*49cdfc7eSAndroid Build Coastguard Worker /*
95*49cdfc7eSAndroid Build Coastguard Worker * CPUID.(EAX=0DH, ECX=0H):EBX: maximum size (bytes, from the beginning
96*49cdfc7eSAndroid Build Coastguard Worker * of the XSAVE/XRSTOR save area) required by enabled features in XCR0.
97*49cdfc7eSAndroid Build Coastguard Worker */
98*49cdfc7eSAndroid Build Coastguard Worker __cpuid_count(CPUID_LEAF_XSTATE, ecx, eax, ebx, ecx, edx);
99*49cdfc7eSAndroid Build Coastguard Worker xstate = SAFE_MEMALIGN(64, ebx);
100*49cdfc7eSAndroid Build Coastguard Worker struct iovec iov = { .iov_base = xstate, .iov_len = ebx };
101*49cdfc7eSAndroid Build Coastguard Worker int status;
102*49cdfc7eSAndroid Build Coastguard Worker bool okay;
103*49cdfc7eSAndroid Build Coastguard Worker
104*49cdfc7eSAndroid Build Coastguard Worker tst_res(TINFO, "CPUID.(EAX=%u, ECX=0):EAX=%u, EBX=%u, ECX=%u, EDX=%u",
105*49cdfc7eSAndroid Build Coastguard Worker CPUID_LEAF_XSTATE, eax, ebx, ecx, edx);
106*49cdfc7eSAndroid Build Coastguard Worker pid = SAFE_FORK();
107*49cdfc7eSAndroid Build Coastguard Worker if (pid == 0) {
108*49cdfc7eSAndroid Build Coastguard Worker TST_CHECKPOINT_WAKE(0);
109*49cdfc7eSAndroid Build Coastguard Worker check_regs_loop(0x00000000);
110*49cdfc7eSAndroid Build Coastguard Worker }
111*49cdfc7eSAndroid Build Coastguard Worker for (i = 0; i < num_cpus; i++) {
112*49cdfc7eSAndroid Build Coastguard Worker if (SAFE_FORK() == 0)
113*49cdfc7eSAndroid Build Coastguard Worker check_regs_loop(0xDEADBEEF);
114*49cdfc7eSAndroid Build Coastguard Worker }
115*49cdfc7eSAndroid Build Coastguard Worker
116*49cdfc7eSAndroid Build Coastguard Worker TST_CHECKPOINT_WAIT(0);
117*49cdfc7eSAndroid Build Coastguard Worker sched_yield();
118*49cdfc7eSAndroid Build Coastguard Worker
119*49cdfc7eSAndroid Build Coastguard Worker TEST(ptrace(PTRACE_ATTACH, pid, 0, 0));
120*49cdfc7eSAndroid Build Coastguard Worker if (TST_RET != 0) {
121*49cdfc7eSAndroid Build Coastguard Worker free(xstate);
122*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TBROK | TTERRNO, "PTRACE_ATTACH failed");
123*49cdfc7eSAndroid Build Coastguard Worker }
124*49cdfc7eSAndroid Build Coastguard Worker
125*49cdfc7eSAndroid Build Coastguard Worker SAFE_WAITPID(pid, NULL, 0);
126*49cdfc7eSAndroid Build Coastguard Worker TEST(ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov));
127*49cdfc7eSAndroid Build Coastguard Worker if (TST_RET != 0) {
128*49cdfc7eSAndroid Build Coastguard Worker free(xstate);
129*49cdfc7eSAndroid Build Coastguard Worker if (TST_ERR == EIO)
130*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TCONF, "GETREGSET/SETREGSET is unsupported");
131*49cdfc7eSAndroid Build Coastguard Worker
132*49cdfc7eSAndroid Build Coastguard Worker if (TST_ERR == EINVAL)
133*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TCONF, "NT_X86_XSTATE is unsupported");
134*49cdfc7eSAndroid Build Coastguard Worker
135*49cdfc7eSAndroid Build Coastguard Worker if (TST_ERR == ENODEV)
136*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TCONF, "CPU doesn't support XSAVE instruction");
137*49cdfc7eSAndroid Build Coastguard Worker
138*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TBROK | TTERRNO,
139*49cdfc7eSAndroid Build Coastguard Worker "PTRACE_GETREGSET failed with unexpected error");
140*49cdfc7eSAndroid Build Coastguard Worker }
141*49cdfc7eSAndroid Build Coastguard Worker
142*49cdfc7eSAndroid Build Coastguard Worker xstate[65] = -1; /* sets all bits in xstate_header.xcomp_bv */
143*49cdfc7eSAndroid Build Coastguard Worker
144*49cdfc7eSAndroid Build Coastguard Worker /*
145*49cdfc7eSAndroid Build Coastguard Worker * Old kernels simply masked out all the reserved bits in the xstate
146*49cdfc7eSAndroid Build Coastguard Worker * header (causing the PTRACE_SETREGSET command here to succeed), while
147*49cdfc7eSAndroid Build Coastguard Worker * new kernels will reject them (causing the PTRACE_SETREGSET command
148*49cdfc7eSAndroid Build Coastguard Worker * here to fail with EINVAL). We accept either behavior, as neither
149*49cdfc7eSAndroid Build Coastguard Worker * behavior reliably tells us whether the real bug (which we test for
150*49cdfc7eSAndroid Build Coastguard Worker * below in either case) is present.
151*49cdfc7eSAndroid Build Coastguard Worker */
152*49cdfc7eSAndroid Build Coastguard Worker TEST(ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov));
153*49cdfc7eSAndroid Build Coastguard Worker if (TST_RET == 0) {
154*49cdfc7eSAndroid Build Coastguard Worker tst_res(TINFO, "PTRACE_SETREGSET with reserved bits succeeded");
155*49cdfc7eSAndroid Build Coastguard Worker } else if (TST_ERR == EINVAL) {
156*49cdfc7eSAndroid Build Coastguard Worker tst_res(TINFO,
157*49cdfc7eSAndroid Build Coastguard Worker "PTRACE_SETREGSET with reserved bits failed with EINVAL");
158*49cdfc7eSAndroid Build Coastguard Worker } else {
159*49cdfc7eSAndroid Build Coastguard Worker free(xstate);
160*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TBROK | TTERRNO,
161*49cdfc7eSAndroid Build Coastguard Worker "PTRACE_SETREGSET failed with unexpected error");
162*49cdfc7eSAndroid Build Coastguard Worker }
163*49cdfc7eSAndroid Build Coastguard Worker
164*49cdfc7eSAndroid Build Coastguard Worker /*
165*49cdfc7eSAndroid Build Coastguard Worker * It is possible for test child 'pid' to crash on AMD
166*49cdfc7eSAndroid Build Coastguard Worker * systems (e.g. AMD Opteron(TM) Processor 6234) with
167*49cdfc7eSAndroid Build Coastguard Worker * older kernels. This causes tracee to stop and sleep
168*49cdfc7eSAndroid Build Coastguard Worker * in ptrace_stop(). Without resuming the tracee, the
169*49cdfc7eSAndroid Build Coastguard Worker * test hangs at do_test()->tst_reap_children() called
170*49cdfc7eSAndroid Build Coastguard Worker * by the library. Use detach here, so we don't need to
171*49cdfc7eSAndroid Build Coastguard Worker * worry about potential stops after this point.
172*49cdfc7eSAndroid Build Coastguard Worker */
173*49cdfc7eSAndroid Build Coastguard Worker TEST(ptrace(PTRACE_DETACH, pid, 0, 0));
174*49cdfc7eSAndroid Build Coastguard Worker if (TST_RET != 0) {
175*49cdfc7eSAndroid Build Coastguard Worker free(xstate);
176*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TBROK | TTERRNO, "PTRACE_DETACH failed");
177*49cdfc7eSAndroid Build Coastguard Worker }
178*49cdfc7eSAndroid Build Coastguard Worker
179*49cdfc7eSAndroid Build Coastguard Worker /* If child 'pid' crashes, only report it as info. */
180*49cdfc7eSAndroid Build Coastguard Worker SAFE_WAITPID(pid, &status, 0);
181*49cdfc7eSAndroid Build Coastguard Worker if (WIFEXITED(status)) {
182*49cdfc7eSAndroid Build Coastguard Worker tst_res(TINFO, "test child %d exited, retcode: %d",
183*49cdfc7eSAndroid Build Coastguard Worker pid, WEXITSTATUS(status));
184*49cdfc7eSAndroid Build Coastguard Worker }
185*49cdfc7eSAndroid Build Coastguard Worker if (WIFSIGNALED(status)) {
186*49cdfc7eSAndroid Build Coastguard Worker tst_res(TINFO, "test child %d exited, termsig: %d",
187*49cdfc7eSAndroid Build Coastguard Worker pid, WTERMSIG(status));
188*49cdfc7eSAndroid Build Coastguard Worker }
189*49cdfc7eSAndroid Build Coastguard Worker
190*49cdfc7eSAndroid Build Coastguard Worker okay = true;
191*49cdfc7eSAndroid Build Coastguard Worker for (i = 0; i < num_cpus; i++) {
192*49cdfc7eSAndroid Build Coastguard Worker SAFE_WAIT(&status);
193*49cdfc7eSAndroid Build Coastguard Worker okay &= (WIFEXITED(status) && WEXITSTATUS(status) == 0);
194*49cdfc7eSAndroid Build Coastguard Worker }
195*49cdfc7eSAndroid Build Coastguard Worker if (okay)
196*49cdfc7eSAndroid Build Coastguard Worker tst_res(TPASS, "wasn't able to set invalid FPU state");
197*49cdfc7eSAndroid Build Coastguard Worker free(xstate);
198*49cdfc7eSAndroid Build Coastguard Worker }
199*49cdfc7eSAndroid Build Coastguard Worker
200*49cdfc7eSAndroid Build Coastguard Worker static struct tst_test test = {
201*49cdfc7eSAndroid Build Coastguard Worker .test_all = do_test,
202*49cdfc7eSAndroid Build Coastguard Worker .forks_child = 1,
203*49cdfc7eSAndroid Build Coastguard Worker .needs_checkpoints = 1,
204*49cdfc7eSAndroid Build Coastguard Worker .supported_archs = (const char *const []) {
205*49cdfc7eSAndroid Build Coastguard Worker "x86_64",
206*49cdfc7eSAndroid Build Coastguard Worker NULL
207*49cdfc7eSAndroid Build Coastguard Worker },
208*49cdfc7eSAndroid Build Coastguard Worker .tags = (const struct tst_tag[]) {
209*49cdfc7eSAndroid Build Coastguard Worker {"linux-git", "814fb7bb7db5"},
210*49cdfc7eSAndroid Build Coastguard Worker {"CVE", "2017-15537"},
211*49cdfc7eSAndroid Build Coastguard Worker {}
212*49cdfc7eSAndroid Build Coastguard Worker }
213*49cdfc7eSAndroid Build Coastguard Worker
214*49cdfc7eSAndroid Build Coastguard Worker };
215*49cdfc7eSAndroid Build Coastguard Worker
216*49cdfc7eSAndroid Build Coastguard Worker #else
217*49cdfc7eSAndroid Build Coastguard Worker TST_TEST_TCONF("Tests an x86_64 feature");
218*49cdfc7eSAndroid Build Coastguard Worker #endif /* if x86 */
219