]>
git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - tools/testing/selftests/x86/syscall_arg_fault.c
1 // SPDX-License-Identifier: GPL-2.0-only
3 * syscall_arg_fault.c - tests faults 32-bit fast syscall stack args
4 * Copyright (c) 2015 Andrew Lutomirski
12 #include <sys/signal.h>
13 #include <sys/ucontext.h>
18 /* Our sigaltstack scratch space. */
19 static unsigned char altstack_data
[SIGSTKSZ
];
21 static void sethandler(int sig
, void (*handler
)(int, siginfo_t
*, void *),
25 memset(&sa
, 0, sizeof(sa
));
26 sa
.sa_sigaction
= handler
;
27 sa
.sa_flags
= SA_SIGINFO
| flags
;
28 sigemptyset(&sa
.sa_mask
);
29 if (sigaction(sig
, &sa
, 0))
33 static volatile sig_atomic_t sig_traps
;
34 static sigjmp_buf jmpbuf
;
36 static volatile sig_atomic_t n_errs
;
38 static void sigsegv_or_sigbus(int sig
, siginfo_t
*info
, void *ctx_void
)
40 ucontext_t
*ctx
= (ucontext_t
*)ctx_void
;
42 if (ctx
->uc_mcontext
.gregs
[REG_EAX
] != -EFAULT
) {
43 printf("[FAIL]\tAX had the wrong value: 0x%x\n",
44 ctx
->uc_mcontext
.gregs
[REG_EAX
]);
47 printf("[OK]\tSeems okay\n");
50 siglongjmp(jmpbuf
, 1);
53 static void sigill(int sig
, siginfo_t
*info
, void *ctx_void
)
55 printf("[SKIP]\tIllegal instruction\n");
56 siglongjmp(jmpbuf
, 1);
62 .ss_sp
= altstack_data
,
65 if (sigaltstack(&stack
, NULL
) != 0)
66 err(1, "sigaltstack");
68 sethandler(SIGSEGV
, sigsegv_or_sigbus
, SA_ONSTACK
);
70 * The actual exception can vary. On Atom CPUs, we get #SS
71 * instead of #PF when the vDSO fails to access the stack when
72 * ESP is too close to 2^32, and #SS causes SIGBUS.
74 sethandler(SIGBUS
, sigsegv_or_sigbus
, SA_ONSTACK
);
75 sethandler(SIGILL
, sigill
, SA_ONSTACK
);
78 * Exercise another nasty special case. The 32-bit SYSCALL
79 * and SYSENTER instructions (even in compat mode) each
80 * clobber one register. A Linux system call has a syscall
81 * number and six arguments, and the user stack pointer
82 * needs to live in some register on return. That means
83 * that we need eight registers, but SYSCALL and SYSENTER
84 * only preserve seven registers. As a result, one argument
85 * ends up on the stack. The stack is user memory, which
86 * means that the kernel can fail to read it.
88 * The 32-bit fast system calls don't have a defined ABI:
89 * we're supposed to invoke them through the vDSO. So we'll
90 * fudge it: we set all regs to invalid pointer values and
91 * invoke the entry instruction. The return will fail no
92 * matter what, and we completely lose our program state,
93 * but we can fix it up with a signal handler.
96 printf("[RUN]\tSYSENTER with invalid state\n");
97 if (sigsetjmp(jmpbuf
, 1) == 0) {
100 "movl $-1, %%ebx\n\t"
101 "movl $-1, %%ecx\n\t"
102 "movl $-1, %%edx\n\t"
103 "movl $-1, %%esi\n\t"
104 "movl $-1, %%edi\n\t"
105 "movl $-1, %%ebp\n\t"
106 "movl $-1, %%esp\n\t"
108 : : : "memory", "flags");
111 printf("[RUN]\tSYSCALL with invalid state\n");
112 if (sigsetjmp(jmpbuf
, 1) == 0) {
114 "movl $-1, %%eax\n\t"
115 "movl $-1, %%ebx\n\t"
116 "movl $-1, %%ecx\n\t"
117 "movl $-1, %%edx\n\t"
118 "movl $-1, %%esi\n\t"
119 "movl $-1, %%edi\n\t"
120 "movl $-1, %%ebp\n\t"
121 "movl $-1, %%esp\n\t"
123 "pushl $0" /* make sure we segfault cleanly */
124 : : : "memory", "flags");