aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-03-15 12:32:27 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-15 12:32:27 -0400
commitba33ea811e1ff6726abb7f8f96df38c2d7b50304 (patch)
tree29134e5cc7c19c8e520cb9336b476144d3d1252f /tools
parente23604edac2a7be6a8808a5d13fac6b9df4eb9a8 (diff)
parentd05004944206cbbf1c453e179768163731c7c6f1 (diff)
Merge branch 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 asm updates from Ingo Molnar: "This is another big update. Main changes are: - lots of x86 system call (and other traps/exceptions) entry code enhancements. In particular the complex parts of the 64-bit entry code have been migrated to C code as well, and a number of dusty corners have been refreshed. (Andy Lutomirski) - vDSO special mapping robustification and general cleanups (Andy Lutomirski) - cpufeature refactoring, cleanups and speedups (Borislav Petkov) - lots of other changes ..." * 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (64 commits) x86/cpufeature: Enable new AVX-512 features x86/entry/traps: Show unhandled signal for i386 in do_trap() x86/entry: Call enter_from_user_mode() with IRQs off x86/entry/32: Change INT80 to be an interrupt gate x86/entry: Improve system call entry comments x86/entry: Remove TIF_SINGLESTEP entry work x86/entry/32: Add and check a stack canary for the SYSENTER stack x86/entry/32: Simplify and fix up the SYSENTER stack #DB/NMI fixup x86/entry: Only allocate space for tss_struct::SYSENTER_stack if needed x86/entry: Vastly simplify SYSENTER TF (single-step) handling x86/entry/traps: Clear DR6 early in do_debug() and improve the comment x86/entry/traps: Clear TIF_BLOCKSTEP on all debug exceptions x86/entry/32: Restore FLAGS on SYSEXIT x86/entry/32: Filter NT and speed up AC filtering in SYSENTER x86/entry/compat: In SYSENTER, sink AC clearing below the existing FLAGS test selftests/x86: In syscall_nt, test NT|TF as well x86/asm-offsets: Remove PARAVIRT_enabled x86/entry/32: Introduce and use X86_BUG_ESPFIX instead of paravirt_enabled uprobes: __create_xol_area() must nullify xol_mapping.fault x86/cpufeature: Create a new synthetic cpu capability for machine check recovery ...
Diffstat (limited to 'tools')
-rw-r--r--tools/testing/selftests/x86/Makefile17
-rw-r--r--tools/testing/selftests/x86/check_initial_reg_state.c109
-rw-r--r--tools/testing/selftests/x86/ptrace_syscall.c132
-rw-r--r--tools/testing/selftests/x86/sigreturn.c230
-rw-r--r--tools/testing/selftests/x86/syscall_nt.c57
5 files changed, 501 insertions, 44 deletions
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
index d0c473f65850..d5ce7d7aae3e 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -4,15 +4,16 @@ include ../lib.mk
4 4
5.PHONY: all all_32 all_64 warn_32bit_failure clean 5.PHONY: all all_32 all_64 warn_32bit_failure clean
6 6
7TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall 7TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall \
8TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault sigreturn test_syscall_vdso unwind_vdso \ 8 check_initial_reg_state sigreturn ldt_gdt
9TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \
9 test_FCMOV test_FCOMI test_FISTTP \ 10 test_FCMOV test_FCOMI test_FISTTP \
10 ldt_gdt \
11 vdso_restorer 11 vdso_restorer
12 12
13TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) 13TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY)
14TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY)
14BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32) 15BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32)
15BINARIES_64 := $(TARGETS_C_BOTHBITS:%=%_64) 16BINARIES_64 := $(TARGETS_C_64BIT_ALL:%=%_64)
16 17
17CFLAGS := -O2 -g -std=gnu99 -pthread -Wall 18CFLAGS := -O2 -g -std=gnu99 -pthread -Wall
18 19
@@ -40,7 +41,7 @@ clean:
40$(TARGETS_C_32BIT_ALL:%=%_32): %_32: %.c 41$(TARGETS_C_32BIT_ALL:%=%_32): %_32: %.c
41 $(CC) -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl -lm 42 $(CC) -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl -lm
42 43
43$(TARGETS_C_BOTHBITS:%=%_64): %_64: %.c 44$(TARGETS_C_64BIT_ALL:%=%_64): %_64: %.c
44 $(CC) -m64 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl 45 $(CC) -m64 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl
45 46
46# x86_64 users should be encouraged to install 32-bit libraries 47# x86_64 users should be encouraged to install 32-bit libraries
@@ -65,3 +66,9 @@ endif
65sysret_ss_attrs_64: thunks.S 66sysret_ss_attrs_64: thunks.S
66ptrace_syscall_32: raw_syscall_helper_32.S 67ptrace_syscall_32: raw_syscall_helper_32.S
67test_syscall_vdso_32: thunks_32.S 68test_syscall_vdso_32: thunks_32.S
69
70# check_initial_reg_state is special: it needs a custom entry, and it
71# needs to be static so that its interpreter doesn't destroy its initial
72# state.
73check_initial_reg_state_32: CFLAGS += -Wl,-ereal_start -static
74check_initial_reg_state_64: CFLAGS += -Wl,-ereal_start -static
diff --git a/tools/testing/selftests/x86/check_initial_reg_state.c b/tools/testing/selftests/x86/check_initial_reg_state.c
new file mode 100644
index 000000000000..6aaed9b85baf
--- /dev/null
+++ b/tools/testing/selftests/x86/check_initial_reg_state.c
@@ -0,0 +1,109 @@
1/*
2 * check_initial_reg_state.c - check that execve sets the correct state
3 * Copyright (c) 2014-2016 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.
13 */
14
15#define _GNU_SOURCE
16
17#include <stdio.h>
18
19unsigned long ax, bx, cx, dx, si, di, bp, sp, flags;
20unsigned long r8, r9, r10, r11, r12, r13, r14, r15;
21
22asm (
23 ".pushsection .text\n\t"
24 ".type real_start, @function\n\t"
25 ".global real_start\n\t"
26 "real_start:\n\t"
27#ifdef __x86_64__
28 "mov %rax, ax\n\t"
29 "mov %rbx, bx\n\t"
30 "mov %rcx, cx\n\t"
31 "mov %rdx, dx\n\t"
32 "mov %rsi, si\n\t"
33 "mov %rdi, di\n\t"
34 "mov %rbp, bp\n\t"
35 "mov %rsp, sp\n\t"
36 "mov %r8, r8\n\t"
37 "mov %r9, r9\n\t"
38 "mov %r10, r10\n\t"
39 "mov %r11, r11\n\t"
40 "mov %r12, r12\n\t"
41 "mov %r13, r13\n\t"
42 "mov %r14, r14\n\t"
43 "mov %r15, r15\n\t"
44 "pushfq\n\t"
45 "popq flags\n\t"
46#else
47 "mov %eax, ax\n\t"
48 "mov %ebx, bx\n\t"
49 "mov %ecx, cx\n\t"
50 "mov %edx, dx\n\t"
51 "mov %esi, si\n\t"
52 "mov %edi, di\n\t"
53 "mov %ebp, bp\n\t"
54 "mov %esp, sp\n\t"
55 "pushfl\n\t"
56 "popl flags\n\t"
57#endif
58 "jmp _start\n\t"
59 ".size real_start, . - real_start\n\t"
60 ".popsection");
61
62int main()
63{
64 int nerrs = 0;
65
66 if (sp == 0) {
67 printf("[FAIL]\tTest was built incorrectly\n");
68 return 1;
69 }
70
71 if (ax || bx || cx || dx || si || di || bp
72#ifdef __x86_64__
73 || r8 || r9 || r10 || r11 || r12 || r13 || r14 || r15
74#endif
75 ) {
76 printf("[FAIL]\tAll GPRs except SP should be 0\n");
77#define SHOW(x) printf("\t" #x " = 0x%lx\n", x);
78 SHOW(ax);
79 SHOW(bx);
80 SHOW(cx);
81 SHOW(dx);
82 SHOW(si);
83 SHOW(di);
84 SHOW(bp);
85 SHOW(sp);
86#ifdef __x86_64__
87 SHOW(r8);
88 SHOW(r9);
89 SHOW(r10);
90 SHOW(r11);
91 SHOW(r12);
92 SHOW(r13);
93 SHOW(r14);
94 SHOW(r15);
95#endif
96 nerrs++;
97 } else {
98 printf("[OK]\tAll GPRs except SP are 0\n");
99 }
100
101 if (flags != 0x202) {
102 printf("[FAIL]\tFLAGS is 0x%lx, but it should be 0x202\n", flags);
103 nerrs++;
104 } else {
105 printf("[OK]\tFLAGS is 0x202\n");
106 }
107
108 return nerrs ? 1 : 0;
109}
diff --git a/tools/testing/selftests/x86/ptrace_syscall.c b/tools/testing/selftests/x86/ptrace_syscall.c
index 5105b49cd8aa..421456784bc6 100644
--- a/tools/testing/selftests/x86/ptrace_syscall.c
+++ b/tools/testing/selftests/x86/ptrace_syscall.c
@@ -103,6 +103,17 @@ static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
103 err(1, "sigaction"); 103 err(1, "sigaction");
104} 104}
105 105
106static void setsigign(int sig, int flags)
107{
108 struct sigaction sa;
109 memset(&sa, 0, sizeof(sa));
110 sa.sa_sigaction = (void *)SIG_IGN;
111 sa.sa_flags = flags;
112 sigemptyset(&sa.sa_mask);
113 if (sigaction(sig, &sa, 0))
114 err(1, "sigaction");
115}
116
106static void clearhandler(int sig) 117static void clearhandler(int sig)
107{ 118{
108 struct sigaction sa; 119 struct sigaction sa;
@@ -187,7 +198,7 @@ static void test_ptrace_syscall_restart(void)
187 198
188 printf("[RUN]\tSYSEMU\n"); 199 printf("[RUN]\tSYSEMU\n");
189 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0) 200 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0)
190 err(1, "PTRACE_SYSCALL"); 201 err(1, "PTRACE_SYSEMU");
191 wait_trap(chld); 202 wait_trap(chld);
192 203
193 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0) 204 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0)
@@ -218,7 +229,7 @@ static void test_ptrace_syscall_restart(void)
218 err(1, "PTRACE_SETREGS"); 229 err(1, "PTRACE_SETREGS");
219 230
220 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0) 231 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0)
221 err(1, "PTRACE_SYSCALL"); 232 err(1, "PTRACE_SYSEMU");
222 wait_trap(chld); 233 wait_trap(chld);
223 234
224 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0) 235 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0)
@@ -250,7 +261,7 @@ static void test_ptrace_syscall_restart(void)
250 err(1, "PTRACE_SETREGS"); 261 err(1, "PTRACE_SETREGS");
251 262
252 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0) 263 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0)
253 err(1, "PTRACE_SYSCALL"); 264 err(1, "PTRACE_SYSEMU");
254 wait_trap(chld); 265 wait_trap(chld);
255 266
256 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0) 267 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0)
@@ -277,6 +288,119 @@ static void test_ptrace_syscall_restart(void)
277 } 288 }
278} 289}
279 290
291static void test_restart_under_ptrace(void)
292{
293 printf("[RUN]\tkernel syscall restart under ptrace\n");
294 pid_t chld = fork();
295 if (chld < 0)
296 err(1, "fork");
297
298 if (chld == 0) {
299 if (ptrace(PTRACE_TRACEME, 0, 0, 0) != 0)
300 err(1, "PTRACE_TRACEME");
301
302 printf("\tChild will take a nap until signaled\n");
303 setsigign(SIGUSR1, SA_RESTART);
304 raise(SIGSTOP);
305
306 syscall(SYS_pause, 0, 0, 0, 0, 0, 0);
307 _exit(0);
308 }
309
310 int status;
311
312 /* Wait for SIGSTOP. */
313 if (waitpid(chld, &status, 0) != chld || !WIFSTOPPED(status))
314 err(1, "waitpid");
315
316 struct user_regs_struct regs;
317
318 printf("[RUN]\tSYSCALL\n");
319 if (ptrace(PTRACE_SYSCALL, chld, 0, 0) != 0)
320 err(1, "PTRACE_SYSCALL");
321 wait_trap(chld);
322
323 /* We should be stopped at pause(2) entry. */
324
325 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0)
326 err(1, "PTRACE_GETREGS");
327
328 if (regs.user_syscall_nr != SYS_pause ||
329 regs.user_arg0 != 0 || regs.user_arg1 != 0 ||
330 regs.user_arg2 != 0 || regs.user_arg3 != 0 ||
331 regs.user_arg4 != 0 || regs.user_arg5 != 0) {
332 printf("[FAIL]\tInitial args are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n", (unsigned long)regs.user_syscall_nr, (unsigned long)regs.user_arg0, (unsigned long)regs.user_arg1, (unsigned long)regs.user_arg2, (unsigned long)regs.user_arg3, (unsigned long)regs.user_arg4, (unsigned long)regs.user_arg5);
333 nerrs++;
334 } else {
335 printf("[OK]\tInitial nr and args are correct\n");
336 }
337
338 /* Interrupt it. */
339 kill(chld, SIGUSR1);
340
341 /* Advance. We should be stopped at exit. */
342 printf("[RUN]\tSYSCALL\n");
343 if (ptrace(PTRACE_SYSCALL, chld, 0, 0) != 0)
344 err(1, "PTRACE_SYSCALL");
345 wait_trap(chld);
346
347 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0)
348 err(1, "PTRACE_GETREGS");
349
350 if (regs.user_syscall_nr != SYS_pause ||
351 regs.user_arg0 != 0 || regs.user_arg1 != 0 ||
352 regs.user_arg2 != 0 || regs.user_arg3 != 0 ||
353 regs.user_arg4 != 0 || regs.user_arg5 != 0) {
354 printf("[FAIL]\tArgs after SIGUSR1 are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n", (unsigned long)regs.user_syscall_nr, (unsigned long)regs.user_arg0, (unsigned long)regs.user_arg1, (unsigned long)regs.user_arg2, (unsigned long)regs.user_arg3, (unsigned long)regs.user_arg4, (unsigned long)regs.user_arg5);
355 nerrs++;
356 } else {
357 printf("[OK]\tArgs after SIGUSR1 are correct (ax = %ld)\n",
358 (long)regs.user_ax);
359 }
360
361 /* Poke the regs back in. This must not break anything. */
362 if (ptrace(PTRACE_SETREGS, chld, 0, &regs) != 0)
363 err(1, "PTRACE_SETREGS");
364
365 /* Catch the (ignored) SIGUSR1. */
366 if (ptrace(PTRACE_CONT, chld, 0, 0) != 0)
367 err(1, "PTRACE_CONT");
368 if (waitpid(chld, &status, 0) != chld)
369 err(1, "waitpid");
370 if (!WIFSTOPPED(status)) {
371 printf("[FAIL]\tChild was stopped for SIGUSR1 (status = 0x%x)\n", status);
372 nerrs++;
373 } else {
374 printf("[OK]\tChild got SIGUSR1\n");
375 }
376
377 /* The next event should be pause(2) again. */
378 printf("[RUN]\tStep again\n");
379 if (ptrace(PTRACE_SYSCALL, chld, 0, 0) != 0)
380 err(1, "PTRACE_SYSCALL");
381 wait_trap(chld);
382
383 /* We should be stopped at pause(2) entry. */
384
385 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0)
386 err(1, "PTRACE_GETREGS");
387
388 if (regs.user_syscall_nr != SYS_pause ||
389 regs.user_arg0 != 0 || regs.user_arg1 != 0 ||
390 regs.user_arg2 != 0 || regs.user_arg3 != 0 ||
391 regs.user_arg4 != 0 || regs.user_arg5 != 0) {
392 printf("[FAIL]\tpause did not restart (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n", (unsigned long)regs.user_syscall_nr, (unsigned long)regs.user_arg0, (unsigned long)regs.user_arg1, (unsigned long)regs.user_arg2, (unsigned long)regs.user_arg3, (unsigned long)regs.user_arg4, (unsigned long)regs.user_arg5);
393 nerrs++;
394 } else {
395 printf("[OK]\tpause(2) restarted correctly\n");
396 }
397
398 /* Kill it. */
399 kill(chld, SIGKILL);
400 if (waitpid(chld, &status, 0) != chld)
401 err(1, "waitpid");
402}
403
280int main() 404int main()
281{ 405{
282 printf("[RUN]\tCheck int80 return regs\n"); 406 printf("[RUN]\tCheck int80 return regs\n");
@@ -290,5 +414,7 @@ int main()
290 414
291 test_ptrace_syscall_restart(); 415 test_ptrace_syscall_restart();
292 416
417 test_restart_under_ptrace();
418
293 return 0; 419 return 0;
294} 420}
diff --git a/tools/testing/selftests/x86/sigreturn.c b/tools/testing/selftests/x86/sigreturn.c
index b5aa1bab7416..8a577e7070c6 100644
--- a/tools/testing/selftests/x86/sigreturn.c
+++ b/tools/testing/selftests/x86/sigreturn.c
@@ -54,6 +54,37 @@
54#include <sys/ptrace.h> 54#include <sys/ptrace.h>
55#include <sys/user.h> 55#include <sys/user.h>
56 56
57/* Pull in AR_xyz defines. */
58typedef unsigned int u32;
59typedef unsigned short u16;
60#include "../../../../arch/x86/include/asm/desc_defs.h"
61
62/*
63 * Copied from asm/ucontext.h, as asm/ucontext.h conflicts badly with the glibc
64 * headers.
65 */
66#ifdef __x86_64__
67/*
68 * UC_SIGCONTEXT_SS will be set when delivering 64-bit or x32 signals on
69 * kernels that save SS in the sigcontext. All kernels that set
70 * UC_SIGCONTEXT_SS will correctly restore at least the low 32 bits of esp
71 * regardless of SS (i.e. they implement espfix).
72 *
73 * Kernels that set UC_SIGCONTEXT_SS will also set UC_STRICT_RESTORE_SS
74 * when delivering a signal that came from 64-bit code.
75 *
76 * Sigreturn restores SS as follows:
77 *
78 * if (saved SS is valid || UC_STRICT_RESTORE_SS is set ||
79 * saved CS is not 64-bit)
80 * new SS = saved SS (will fail IRET and signal if invalid)
81 * else
82 * new SS = a flat 32-bit data segment
83 */
84#define UC_SIGCONTEXT_SS 0x2
85#define UC_STRICT_RESTORE_SS 0x4
86#endif
87
57/* 88/*
58 * In principle, this test can run on Linux emulation layers (e.g. 89 * In principle, this test can run on Linux emulation layers (e.g.
59 * Illumos "LX branded zones"). Solaris-based kernels reserve LDT 90 * Illumos "LX branded zones"). Solaris-based kernels reserve LDT
@@ -267,6 +298,9 @@ static gregset_t initial_regs, requested_regs, resulting_regs;
267/* Instructions for the SIGUSR1 handler. */ 298/* Instructions for the SIGUSR1 handler. */
268static volatile unsigned short sig_cs, sig_ss; 299static volatile unsigned short sig_cs, sig_ss;
269static volatile sig_atomic_t sig_trapped, sig_err, sig_trapno; 300static volatile sig_atomic_t sig_trapped, sig_err, sig_trapno;
301#ifdef __x86_64__
302static volatile sig_atomic_t sig_corrupt_final_ss;
303#endif
270 304
271/* Abstractions for some 32-bit vs 64-bit differences. */ 305/* Abstractions for some 32-bit vs 64-bit differences. */
272#ifdef __x86_64__ 306#ifdef __x86_64__
@@ -305,9 +339,105 @@ static greg_t *csptr(ucontext_t *ctx)
305} 339}
306#endif 340#endif
307 341
342/*
343 * Checks a given selector for its code bitness or returns -1 if it's not
344 * a usable code segment selector.
345 */
346int cs_bitness(unsigned short cs)
347{
348 uint32_t valid = 0, ar;
349 asm ("lar %[cs], %[ar]\n\t"
350 "jnz 1f\n\t"
351 "mov $1, %[valid]\n\t"
352 "1:"
353 : [ar] "=r" (ar), [valid] "+rm" (valid)
354 : [cs] "r" (cs));
355
356 if (!valid)
357 return -1;
358
359 bool db = (ar & (1 << 22));
360 bool l = (ar & (1 << 21));
361
362 if (!(ar & (1<<11)))
363 return -1; /* Not code. */
364
365 if (l && !db)
366 return 64;
367 else if (!l && db)
368 return 32;
369 else if (!l && !db)
370 return 16;
371 else
372 return -1; /* Unknown bitness. */
373}
374
375/*
376 * Checks a given selector for its code bitness or returns -1 if it's not
377 * a usable code segment selector.
378 */
379bool is_valid_ss(unsigned short cs)
380{
381 uint32_t valid = 0, ar;
382 asm ("lar %[cs], %[ar]\n\t"
383 "jnz 1f\n\t"
384 "mov $1, %[valid]\n\t"
385 "1:"
386 : [ar] "=r" (ar), [valid] "+rm" (valid)
387 : [cs] "r" (cs));
388
389 if (!valid)
390 return false;
391
392 if ((ar & AR_TYPE_MASK) != AR_TYPE_RWDATA &&
393 (ar & AR_TYPE_MASK) != AR_TYPE_RWDATA_EXPDOWN)
394 return false;
395
396 return (ar & AR_P);
397}
398
308/* Number of errors in the current test case. */ 399/* Number of errors in the current test case. */
309static volatile sig_atomic_t nerrs; 400static volatile sig_atomic_t nerrs;
310 401
402static void validate_signal_ss(int sig, ucontext_t *ctx)
403{
404#ifdef __x86_64__
405 bool was_64bit = (cs_bitness(*csptr(ctx)) == 64);
406
407 if (!(ctx->uc_flags & UC_SIGCONTEXT_SS)) {
408 printf("[FAIL]\tUC_SIGCONTEXT_SS was not set\n");
409 nerrs++;
410
411 /*
412 * This happens on Linux 4.1. The rest will fail, too, so
413 * return now to reduce the noise.
414 */
415 return;
416 }
417
418 /* UC_STRICT_RESTORE_SS is set iff we came from 64-bit mode. */
419 if (!!(ctx->uc_flags & UC_STRICT_RESTORE_SS) != was_64bit) {
420 printf("[FAIL]\tUC_STRICT_RESTORE_SS was wrong in signal %d\n",
421 sig);
422 nerrs++;
423 }
424
425 if (is_valid_ss(*ssptr(ctx))) {
426 /*
427 * DOSEMU was written before 64-bit sigcontext had SS, and
428 * it tries to figure out the signal source SS by looking at
429 * the physical register. Make sure that keeps working.
430 */
431 unsigned short hw_ss;
432 asm ("mov %%ss, %0" : "=rm" (hw_ss));
433 if (hw_ss != *ssptr(ctx)) {
434 printf("[FAIL]\tHW SS didn't match saved SS\n");
435 nerrs++;
436 }
437 }
438#endif
439}
440
311/* 441/*
312 * SIGUSR1 handler. Sets CS and SS as requested and points IP to the 442 * SIGUSR1 handler. Sets CS and SS as requested and points IP to the
313 * int3 trampoline. Sets SP to a large known value so that we can see 443 * int3 trampoline. Sets SP to a large known value so that we can see
@@ -317,6 +447,8 @@ static void sigusr1(int sig, siginfo_t *info, void *ctx_void)
317{ 447{
318 ucontext_t *ctx = (ucontext_t*)ctx_void; 448 ucontext_t *ctx = (ucontext_t*)ctx_void;
319 449
450 validate_signal_ss(sig, ctx);
451
320 memcpy(&initial_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t)); 452 memcpy(&initial_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t));
321 453
322 *csptr(ctx) = sig_cs; 454 *csptr(ctx) = sig_cs;
@@ -334,13 +466,16 @@ static void sigusr1(int sig, siginfo_t *info, void *ctx_void)
334} 466}
335 467
336/* 468/*
337 * Called after a successful sigreturn. Restores our state so that 469 * Called after a successful sigreturn (via int3) or from a failed
338 * the original raise(SIGUSR1) returns. 470 * sigreturn (directly by kernel). Restores our state so that the
471 * original raise(SIGUSR1) returns.
339 */ 472 */
340static void sigtrap(int sig, siginfo_t *info, void *ctx_void) 473static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
341{ 474{
342 ucontext_t *ctx = (ucontext_t*)ctx_void; 475 ucontext_t *ctx = (ucontext_t*)ctx_void;
343 476
477 validate_signal_ss(sig, ctx);
478
344 sig_err = ctx->uc_mcontext.gregs[REG_ERR]; 479 sig_err = ctx->uc_mcontext.gregs[REG_ERR];
345 sig_trapno = ctx->uc_mcontext.gregs[REG_TRAPNO]; 480 sig_trapno = ctx->uc_mcontext.gregs[REG_TRAPNO];
346 481
@@ -358,41 +493,62 @@ static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
358 memcpy(&resulting_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t)); 493 memcpy(&resulting_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t));
359 memcpy(&ctx->uc_mcontext.gregs, &initial_regs, sizeof(gregset_t)); 494 memcpy(&ctx->uc_mcontext.gregs, &initial_regs, sizeof(gregset_t));
360 495
496#ifdef __x86_64__
497 if (sig_corrupt_final_ss) {
498 if (ctx->uc_flags & UC_STRICT_RESTORE_SS) {
499 printf("[FAIL]\tUC_STRICT_RESTORE_SS was set inappropriately\n");
500 nerrs++;
501 } else {
502 /*
503 * DOSEMU transitions from 32-bit to 64-bit mode by
504 * adjusting sigcontext, and it requires that this work
505 * even if the saved SS is bogus.
506 */
507 printf("\tCorrupting SS on return to 64-bit mode\n");
508 *ssptr(ctx) = 0;
509 }
510 }
511#endif
512
361 sig_trapped = sig; 513 sig_trapped = sig;
362} 514}
363 515
364/* 516#ifdef __x86_64__
365 * Checks a given selector for its code bitness or returns -1 if it's not 517/* Tests recovery if !UC_STRICT_RESTORE_SS */
366 * a usable code segment selector. 518static void sigusr2(int sig, siginfo_t *info, void *ctx_void)
367 */
368int cs_bitness(unsigned short cs)
369{ 519{
370 uint32_t valid = 0, ar; 520 ucontext_t *ctx = (ucontext_t*)ctx_void;
371 asm ("lar %[cs], %[ar]\n\t"
372 "jnz 1f\n\t"
373 "mov $1, %[valid]\n\t"
374 "1:"
375 : [ar] "=r" (ar), [valid] "+rm" (valid)
376 : [cs] "r" (cs));
377 521
378 if (!valid) 522 if (!(ctx->uc_flags & UC_STRICT_RESTORE_SS)) {
379 return -1; 523 printf("[FAIL]\traise(2) didn't set UC_STRICT_RESTORE_SS\n");
524 nerrs++;
525 return; /* We can't do the rest. */
526 }
380 527
381 bool db = (ar & (1 << 22)); 528 ctx->uc_flags &= ~UC_STRICT_RESTORE_SS;
382 bool l = (ar & (1 << 21)); 529 *ssptr(ctx) = 0;
383 530
384 if (!(ar & (1<<11))) 531 /* Return. The kernel should recover without sending another signal. */
385 return -1; /* Not code. */ 532}
386 533
387 if (l && !db) 534static int test_nonstrict_ss(void)
388 return 64; 535{
389 else if (!l && db) 536 clearhandler(SIGUSR1);
390 return 32; 537 clearhandler(SIGTRAP);
391 else if (!l && !db) 538 clearhandler(SIGSEGV);
392 return 16; 539 clearhandler(SIGILL);
393 else 540 sethandler(SIGUSR2, sigusr2, 0);
394 return -1; /* Unknown bitness. */ 541
542 nerrs = 0;
543
544 printf("[RUN]\tClear UC_STRICT_RESTORE_SS and corrupt SS\n");
545 raise(SIGUSR2);
546 if (!nerrs)
547 printf("[OK]\tIt worked\n");
548
549 return nerrs;
395} 550}
551#endif
396 552
397/* Finds a usable code segment of the requested bitness. */ 553/* Finds a usable code segment of the requested bitness. */
398int find_cs(int bitness) 554int find_cs(int bitness)
@@ -576,6 +732,12 @@ static int test_bad_iret(int cs_bits, unsigned short ss, int force_cs)
576 errdesc, strsignal(sig_trapped)); 732 errdesc, strsignal(sig_trapped));
577 return 0; 733 return 0;
578 } else { 734 } else {
735 /*
736 * This also implicitly tests UC_STRICT_RESTORE_SS:
737 * We check that these signals set UC_STRICT_RESTORE_SS and,
738 * if UC_STRICT_RESTORE_SS doesn't cause strict behavior,
739 * then we won't get SIGSEGV.
740 */
579 printf("[FAIL]\tDid not get SIGSEGV\n"); 741 printf("[FAIL]\tDid not get SIGSEGV\n");
580 return 1; 742 return 1;
581 } 743 }
@@ -632,6 +794,14 @@ int main()
632 GDT3(gdt_data16_idx)); 794 GDT3(gdt_data16_idx));
633 } 795 }
634 796
797#ifdef __x86_64__
798 /* Nasty ABI case: check SS corruption handling. */
799 sig_corrupt_final_ss = 1;
800 total_nerrs += test_valid_sigreturn(32, false, -1);
801 total_nerrs += test_valid_sigreturn(32, true, -1);
802 sig_corrupt_final_ss = 0;
803#endif
804
635 /* 805 /*
636 * We're done testing valid sigreturn cases. Now we test states 806 * We're done testing valid sigreturn cases. Now we test states
637 * for which sigreturn itself will succeed but the subsequent 807 * for which sigreturn itself will succeed but the subsequent
@@ -680,5 +850,9 @@ int main()
680 if (gdt_npdata32_idx) 850 if (gdt_npdata32_idx)
681 test_bad_iret(32, GDT3(gdt_npdata32_idx), -1); 851 test_bad_iret(32, GDT3(gdt_npdata32_idx), -1);
682 852
853#ifdef __x86_64__
854 total_nerrs += test_nonstrict_ss();
855#endif
856
683 return total_nerrs ? 1 : 0; 857 return total_nerrs ? 1 : 0;
684} 858}
diff --git a/tools/testing/selftests/x86/syscall_nt.c b/tools/testing/selftests/x86/syscall_nt.c
index 60c06af4646a..43fcab367fb0 100644
--- a/tools/testing/selftests/x86/syscall_nt.c
+++ b/tools/testing/selftests/x86/syscall_nt.c
@@ -17,6 +17,9 @@
17 17
18#include <stdio.h> 18#include <stdio.h>
19#include <unistd.h> 19#include <unistd.h>
20#include <string.h>
21#include <signal.h>
22#include <err.h>
20#include <sys/syscall.h> 23#include <sys/syscall.h>
21#include <asm/processor-flags.h> 24#include <asm/processor-flags.h>
22 25
@@ -26,6 +29,8 @@
26# define WIDTH "l" 29# define WIDTH "l"
27#endif 30#endif
28 31
32static unsigned int nerrs;
33
29static unsigned long get_eflags(void) 34static unsigned long get_eflags(void)
30{ 35{
31 unsigned long eflags; 36 unsigned long eflags;
@@ -39,16 +44,52 @@ static void set_eflags(unsigned long eflags)
39 : : "rm" (eflags) : "flags"); 44 : : "rm" (eflags) : "flags");
40} 45}
41 46
42int main() 47static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
48 int flags)
43{ 49{
44 printf("[RUN]\tSet NT and issue a syscall\n"); 50 struct sigaction sa;
45 set_eflags(get_eflags() | X86_EFLAGS_NT); 51 memset(&sa, 0, sizeof(sa));
52 sa.sa_sigaction = handler;
53 sa.sa_flags = SA_SIGINFO | flags;
54 sigemptyset(&sa.sa_mask);
55 if (sigaction(sig, &sa, 0))
56 err(1, "sigaction");
57}
58
59static void sigtrap(int sig, siginfo_t *si, void *ctx_void)
60{
61}
62
63static void do_it(unsigned long extraflags)
64{
65 unsigned long flags;
66
67 set_eflags(get_eflags() | extraflags);
46 syscall(SYS_getpid); 68 syscall(SYS_getpid);
47 if (get_eflags() & X86_EFLAGS_NT) { 69 flags = get_eflags();
48 printf("[OK]\tThe syscall worked and NT is still set\n"); 70 if ((flags & extraflags) == extraflags) {
49 return 0; 71 printf("[OK]\tThe syscall worked and flags are still set\n");
50 } else { 72 } else {
51 printf("[FAIL]\tThe syscall worked but NT was cleared\n"); 73 printf("[FAIL]\tThe syscall worked but flags were cleared (flags = 0x%lx but expected 0x%lx set)\n",
52 return 1; 74 flags, extraflags);
75 nerrs++;
53 } 76 }
54} 77}
78
79int main(void)
80{
81 printf("[RUN]\tSet NT and issue a syscall\n");
82 do_it(X86_EFLAGS_NT);
83
84 /*
85 * Now try it again with TF set -- TF forces returns via IRET in all
86 * cases except non-ptregs-using 64-bit full fast path syscalls.
87 */
88
89 sethandler(SIGTRAP, sigtrap, 0);
90
91 printf("[RUN]\tSet NT|TF and issue a syscall\n");
92 do_it(X86_EFLAGS_NT | X86_EFLAGS_TF);
93
94 return nerrs == 0 ? 0 : 1;
95}