summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@amacapital.net>2014-07-21 15:01:57 -0700
committerAndy Lutomirski <luto@amacapital.net>2014-07-21 15:01:57 -0700
commitd0f136192de02b157c1195d92968e802e65a9b19 (patch)
treea8cd5b0e1b2c0deab7225aabb1249687487681b5
parenteeba7a35f154d3299b0c062da4d0555ae9b2cfe1 (diff)
downloadmisc-tests-d0f136192de02b157c1195d92968e802e65a9b19.tar.gz
syscall_exit_regs: Test more things
This fails on current kernels. Oops.
-rw-r--r--syscall_exit_regs.c162
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;
}