hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/tools/testing/selftests/x86/syscall_arg_fault.c
....@@ -1,15 +1,7 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * syscall_arg_fault.c - tests faults 32-bit fast syscall stack args
34 * Copyright (c) 2015 Andrew Lutomirski
4
- *
5
- * This program is free software; you can redistribute it and/or modify
6
- * it under the terms and conditions of the GNU General Public License,
7
- * version 2, as published by the Free Software Foundation.
8
- *
9
- * This program is distributed in the hope it will be useful, but
10
- * WITHOUT ANY WARRANTY; without even the implied warranty of
11
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
- * General Public License for more details.
135 */
146
157 #define _GNU_SOURCE
....@@ -22,6 +14,8 @@
2214 #include <err.h>
2315 #include <setjmp.h>
2416 #include <errno.h>
17
+
18
+#include "helpers.h"
2519
2620 /* Our sigaltstack scratch space. */
2721 static unsigned char altstack_data[SIGSTKSZ];
....@@ -43,13 +37,23 @@
4337
4438 static volatile sig_atomic_t n_errs;
4539
46
-static void sigsegv(int sig, siginfo_t *info, void *ctx_void)
40
+#ifdef __x86_64__
41
+#define REG_AX REG_RAX
42
+#define REG_IP REG_RIP
43
+#else
44
+#define REG_AX REG_EAX
45
+#define REG_IP REG_EIP
46
+#endif
47
+
48
+static void sigsegv_or_sigbus(int sig, siginfo_t *info, void *ctx_void)
4749 {
4850 ucontext_t *ctx = (ucontext_t*)ctx_void;
51
+ long ax = (long)ctx->uc_mcontext.gregs[REG_AX];
4952
50
- if (ctx->uc_mcontext.gregs[REG_EAX] != -EFAULT) {
51
- printf("[FAIL]\tAX had the wrong value: 0x%x\n",
52
- ctx->uc_mcontext.gregs[REG_EAX]);
53
+ if (ax != -EFAULT && ax != -ENOSYS) {
54
+ printf("[FAIL]\tAX had the wrong value: 0x%lx\n",
55
+ (unsigned long)ax);
56
+ printf("\tIP = 0x%lx\n", (unsigned long)ctx->uc_mcontext.gregs[REG_IP]);
5357 n_errs++;
5458 } else {
5559 printf("[OK]\tSeems okay\n");
....@@ -58,9 +62,42 @@
5862 siglongjmp(jmpbuf, 1);
5963 }
6064
65
+static volatile sig_atomic_t sigtrap_consecutive_syscalls;
66
+
67
+static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
68
+{
69
+ /*
70
+ * KVM has some bugs that can cause us to stop making progress.
71
+ * detect them and complain, but don't infinite loop or fail the
72
+ * test.
73
+ */
74
+
75
+ ucontext_t *ctx = (ucontext_t*)ctx_void;
76
+ unsigned short *ip = (unsigned short *)ctx->uc_mcontext.gregs[REG_IP];
77
+
78
+ if (*ip == 0x340f || *ip == 0x050f) {
79
+ /* The trap was on SYSCALL or SYSENTER */
80
+ sigtrap_consecutive_syscalls++;
81
+ if (sigtrap_consecutive_syscalls > 3) {
82
+ printf("[WARN]\tGot stuck single-stepping -- you probably have a KVM bug\n");
83
+ siglongjmp(jmpbuf, 1);
84
+ }
85
+ } else {
86
+ sigtrap_consecutive_syscalls = 0;
87
+ }
88
+}
89
+
6190 static void sigill(int sig, siginfo_t *info, void *ctx_void)
6291 {
63
- printf("[SKIP]\tIllegal instruction\n");
92
+ ucontext_t *ctx = (ucontext_t*)ctx_void;
93
+ unsigned short *ip = (unsigned short *)ctx->uc_mcontext.gregs[REG_IP];
94
+
95
+ if (*ip == 0x0b0f) {
96
+ /* one of the ud2 instructions faulted */
97
+ printf("[OK]\tSYSCALL returned normally\n");
98
+ } else {
99
+ printf("[SKIP]\tIllegal instruction\n");
100
+ }
64101 siglongjmp(jmpbuf, 1);
65102 }
66103
....@@ -73,7 +110,13 @@
73110 if (sigaltstack(&stack, NULL) != 0)
74111 err(1, "sigaltstack");
75112
76
- sethandler(SIGSEGV, sigsegv, SA_ONSTACK);
113
+ sethandler(SIGSEGV, sigsegv_or_sigbus, SA_ONSTACK);
114
+ /*
115
+ * The actual exception can vary. On Atom CPUs, we get #SS
116
+ * instead of #PF when the vDSO fails to access the stack when
117
+ * ESP is too close to 2^32, and #SS causes SIGBUS.
118
+ */
119
+ sethandler(SIGBUS, sigsegv_or_sigbus, SA_ONSTACK);
77120 sethandler(SIGILL, sigill, SA_ONSTACK);
78121
79122 /*
....@@ -122,9 +165,73 @@
122165 "movl $-1, %%ebp\n\t"
123166 "movl $-1, %%esp\n\t"
124167 "syscall\n\t"
125
- "pushl $0" /* make sure we segfault cleanly */
168
+ "ud2" /* make sure we recover cleanly */
126169 : : : "memory", "flags");
127170 }
128171
172
+ printf("[RUN]\tSYSENTER with TF and invalid state\n");
173
+ sethandler(SIGTRAP, sigtrap, SA_ONSTACK);
174
+
175
+ if (sigsetjmp(jmpbuf, 1) == 0) {
176
+ sigtrap_consecutive_syscalls = 0;
177
+ set_eflags(get_eflags() | X86_EFLAGS_TF);
178
+ asm volatile (
179
+ "movl $-1, %%eax\n\t"
180
+ "movl $-1, %%ebx\n\t"
181
+ "movl $-1, %%ecx\n\t"
182
+ "movl $-1, %%edx\n\t"
183
+ "movl $-1, %%esi\n\t"
184
+ "movl $-1, %%edi\n\t"
185
+ "movl $-1, %%ebp\n\t"
186
+ "movl $-1, %%esp\n\t"
187
+ "sysenter"
188
+ : : : "memory", "flags");
189
+ }
190
+ set_eflags(get_eflags() & ~X86_EFLAGS_TF);
191
+
192
+ printf("[RUN]\tSYSCALL with TF and invalid state\n");
193
+ if (sigsetjmp(jmpbuf, 1) == 0) {
194
+ sigtrap_consecutive_syscalls = 0;
195
+ set_eflags(get_eflags() | X86_EFLAGS_TF);
196
+ asm volatile (
197
+ "movl $-1, %%eax\n\t"
198
+ "movl $-1, %%ebx\n\t"
199
+ "movl $-1, %%ecx\n\t"
200
+ "movl $-1, %%edx\n\t"
201
+ "movl $-1, %%esi\n\t"
202
+ "movl $-1, %%edi\n\t"
203
+ "movl $-1, %%ebp\n\t"
204
+ "movl $-1, %%esp\n\t"
205
+ "syscall\n\t"
206
+ "ud2" /* make sure we recover cleanly */
207
+ : : : "memory", "flags");
208
+ }
209
+ set_eflags(get_eflags() & ~X86_EFLAGS_TF);
210
+
211
+#ifdef __x86_64__
212
+ printf("[RUN]\tSYSENTER with TF, invalid state, and GSBASE < 0\n");
213
+
214
+ if (sigsetjmp(jmpbuf, 1) == 0) {
215
+ sigtrap_consecutive_syscalls = 0;
216
+
217
+ asm volatile ("wrgsbase %%rax\n\t"
218
+ :: "a" (0xffffffffffff0000UL));
219
+
220
+ set_eflags(get_eflags() | X86_EFLAGS_TF);
221
+ asm volatile (
222
+ "movl $-1, %%eax\n\t"
223
+ "movl $-1, %%ebx\n\t"
224
+ "movl $-1, %%ecx\n\t"
225
+ "movl $-1, %%edx\n\t"
226
+ "movl $-1, %%esi\n\t"
227
+ "movl $-1, %%edi\n\t"
228
+ "movl $-1, %%ebp\n\t"
229
+ "movl $-1, %%esp\n\t"
230
+ "sysenter"
231
+ : : : "memory", "flags");
232
+ }
233
+ set_eflags(get_eflags() & ~X86_EFLAGS_TF);
234
+#endif
235
+
129236 return 0;
130237 }