diff options
author | Andy Lutomirski <luto@amacapital.net> | 2014-07-21 15:01:57 -0700 |
---|---|---|
committer | Andy Lutomirski <luto@amacapital.net> | 2014-07-21 15:01:57 -0700 |
commit | d0f136192de02b157c1195d92968e802e65a9b19 (patch) | |
tree | a8cd5b0e1b2c0deab7225aabb1249687487681b5 | |
parent | eeba7a35f154d3299b0c062da4d0555ae9b2cfe1 (diff) | |
download | misc-tests-d0f136192de02b157c1195d92968e802e65a9b19.tar.gz |
syscall_exit_regs: Test more things
This fails on current kernels. Oops.
-rw-r--r-- | syscall_exit_regs.c | 162 |
1 files changed, 150 insertions, 12 deletions
diff --git a/syscall_exit_regs.c b/syscall_exit_regs.c index 337dbf5..a794981 100644 --- a/syscall_exit_regs.c +++ b/syscall_exit_regs.c @@ -1,29 +1,167 @@ +#define _GNU_SOURCE + #include <stdio.h> +#include <sys/prctl.h> #include <asm/prctl.h> +#include <sys/ucontext.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <string.h> +#include <err.h> -int main() +static volatile sig_atomic_t got_sigill = 0; + +extern int arch_prctl(int, unsigned long); + +static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), + int flags) +{ + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = handler; + sa.sa_flags = SA_SIGINFO | flags; + sigemptyset(&sa.sa_mask); + if (sigaction(sig, &sa, 0)) + err(1, "sigaction"); +} + +#ifdef __x86_64__ +# define REG_IP REG_RIP +#else +# define REG_IP REG_EIP +#endif + +static void sigill(int sig, siginfo_t *si, void *ctx_void) +{ + ucontext_t *ctx = (ucontext_t*)ctx_void; + + got_sigill = 1; + ctx->uc_mcontext.gregs[REG_IP] += 2; +} + +static int nerrs = 0; + +static void test_syscall(long nr) { extern const char syscall_rip[]; unsigned long rcx = 1; unsigned long orig_rcx = rcx; unsigned short orig_ss, ss; + long ret; + int local_nerrs = 0; #ifdef __x86_64__ arch_prctl(ARCH_SET_GS, 500); // Enable segment 13 asm volatile ("mov %0,%%ss" : : "r" ((13 << 3) | 3)); #endif - asm ("mov %%ss,%[orig_ss]\n\t" - "mov $0x80000000, %%eax\n\t" - "syscall\n\t" - "syscall_rip:" - "mov %%ss,%[ss]\n\t" - : "+c" (rcx), [orig_ss] "=rm" (orig_ss), [ss] "=rm" (ss) : : + got_sigill = 0; + + asm volatile ("mov %%ss,%[orig_ss]\n\t" + "syscall\n\t" + "syscall_rip:" + "mov %%ss,%[ss]\n\t" + : "+c" (rcx), [orig_ss] "=rm" (orig_ss), [ss] "=rm" (ss), + "=a" (ret) + : "a" (nr) : #ifdef __x86_64__ - "r11" + "r11" #endif - ); - printf("syscall: RCX = %lX RIP = %lX orig RCX = %lx ss = %hx orig_ss = %hx\n", - rcx, (unsigned long)syscall_rip, orig_rcx, ss, orig_ss); - return 0; + ); + + if (got_sigill) { + printf("[OK]\tsyscall %lx: SIGILL\n", nr); + } else { + const char *outcome; + if (rcx != (unsigned long)syscall_rip) { + local_nerrs++; + outcome = "[FAIL]"; + } else { + outcome = "[OK]"; + } + printf("%s\tsyscall %lx: RCX = %lX RIP = %lX\n", + outcome, nr, rcx, (unsigned long)syscall_rip); + + if (ret != (long)-ENOSYS) { + local_nerrs++; + outcome = "[FAIL]"; + } else { + outcome = "[OK]"; + } + printf("%s\tsyscall %lx: AX = %lx\n", + outcome, nr, ret); + + printf("[NOTE]\tsyscall %lx: orig RCX = %lx ss = %hx orig_ss = %hx\n", + nr, orig_rcx, ss, orig_ss); + } + + nerrs += local_nerrs; +} + +static void test_int80(long nr) +{ + long ret; + int local_nerrs = 0; + + got_sigill = 0; + + asm volatile ("int $0x80" + : "=a" (ret) + : "a" (nr) + : + ); + + if (got_sigill) { + printf("[OK]\tint80 %lx: SIGILL\n", nr); + } else { + const char *outcome; + + if (ret != (long)-ENOSYS) { + local_nerrs++; + outcome = "[FAIL]"; + } else { + outcome = "[OK]"; + } + printf("%s\tint80 %lx: AX = %lx\n", + outcome, nr, ret); + } + + nerrs += local_nerrs; +} + +static void test_syscallfn(long nr) +{ + long ret; + int local_nerrs = 0; + + ret = syscall(nr); + + const char *outcome; + + if (ret != -1 || errno != ENOSYS) { + local_nerrs++; + outcome = "[FAIL]"; + } else { + outcome = "[OK]"; + } + printf("%s\tsyscall(%lx): ret = %ld, errno = %d\n", + outcome, nr, ret, errno); + + nerrs += local_nerrs; +} + +int main() +{ + sethandler(SIGILL, sigill, 0); + + test_int80(0xFFFF); + test_int80(0x40000000); + + test_syscall(0xFFFF); + test_syscall(0x40000000); + + test_syscallfn(0xFFFF); + + return nerrs ? 1 : 0; } |