diff options
author | Andy Lutomirski <luto@amacapital.net> | 2014-07-03 19:49:42 -0700 |
---|---|---|
committer | Andy Lutomirski <luto@amacapital.net> | 2014-07-03 19:49:42 -0700 |
commit | fc315dc49fbdec7e5c99a76eba5af9cdb4813bf8 (patch) | |
tree | 308282e78632587d67cdd37dc547c89f8472dcb9 | |
parent | 4ef0abaf950bceb0607f3af0e7ccc4e579c64cf7 (diff) | |
download | misc-tests-fc315dc49fbdec7e5c99a76eba5af9cdb4813bf8.tar.gz |
Add sigreturn test
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | sigreturn.c | 160 |
3 files changed, 162 insertions, 1 deletions
@@ -6,6 +6,7 @@ kernel_pf user_visible_state highsys null_seccomp +sigreturn *~ *_32 *_64 @@ -1,6 +1,6 @@ .PHONY: all clean -SIMPLE_C_TARGETS := dump-vdso dump-vvar dump-vsyscall context_switch_latency kernel_pf user_visible_state null_seccomp highsys +SIMPLE_C_TARGETS := dump-vsyscall context_switch_latency kernel_pf user_visible_state null_seccomp highsys sigreturn SIMPLE_CC_TARGETS := evil-clock-test diff --git a/sigreturn.c b/sigreturn.c new file mode 100644 index 0000000..01f92f7 --- /dev/null +++ b/sigreturn.c @@ -0,0 +1,160 @@ +#define _GNU_SOURCE + +#include <sys/time.h> +#include <time.h> +#include <stdlib.h> +#include <sys/syscall.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include <sys/mman.h> +#include <sys/signal.h> +#include <sys/ucontext.h> +#include <asm/ldt.h> +#include <err.h> +#include <setjmp.h> + +struct selectors { + short cs, gs, fs, __pad0; +}; + +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"); + +} + +static unsigned char stack16[65536] __attribute__((aligned(4096))); + +asm (".pushsection .text\n\t" + ".type int3, @function\n\t" + ".align 4096\n\t" + "int3:\n\t" + "int3\n\t" + ".size int3, . - int3\n\t" + ".align 4096, 0xcc\n\t" + ".popsection"); +extern char int3[4096]; + +static void setup_ldt(void) +{ + if ((unsigned long)stack16 > (1UL << 32) - sizeof(stack16)) + errx(1, "stack16 is too high\n"); + if ((unsigned long)int3 > (1UL << 32) - sizeof(int3)) + errx(1, "stack16 is too high\n"); + + // Borrowed from a test case by hpa + const struct user_desc code16_desc = { + .entry_number = 0, + .base_addr = (unsigned long)int3, + .limit = 4095, + .seg_32bit = 0, + .contents = 2, /* Code, not conforming */ + .read_exec_only = 0, + .limit_in_pages = 0, + .seg_not_present = 0, + .useable = 0 + }; + const struct user_desc data16_desc = { + .entry_number = 1, + .base_addr = (unsigned long)stack16, + .limit = 0xffff, + .seg_32bit = 0, + .contents = 0, /* Data, grow-up */ + .read_exec_only = 0, + .limit_in_pages = 0, + .seg_not_present = 0, + .useable = 0 + }; + + if (syscall(SYS_modify_ldt, 1, &code16_desc, sizeof code16_desc) != 0) + err(1, "modify_ldt"); + if (syscall(SYS_modify_ldt, 1, &data16_desc, sizeof data16_desc) != 0) + err(1, "modify_ldt"); +} + +static gregset_t initial_regs, requested_regs, resulting_regs; + +static void sigusr1(int sig, siginfo_t *info, void *ctx_void) +{ + ucontext_t *ctx = (ucontext_t*)ctx_void; + + memcpy(&initial_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t)); + + struct selectors *sels = (void *)&ctx->uc_mcontext.gregs[REG_CSGSFS]; + sels->cs = (0 << 3) | 7; /* LDT selector 0, RPL = 3 */ + sels->__pad0 = 0; /* Avoid spurious failures. */ + + asm volatile ("mov %0,%%ss\n\t" + "mov %0,%%ds\n\t" + "mov %0,%%es\n\t" + : : "r" ((1 << 3) | 7) /* LDT selector 1, RPL = 3 */ + ); + + ctx->uc_mcontext.gregs[REG_RIP] = 0; + ctx->uc_mcontext.gregs[REG_RSP] = 0x8badf00d5aad0000; + + memcpy(&requested_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t)); + + return; +} + +static void sigtrap(int sig, siginfo_t *info, void *ctx_void) +{ + ucontext_t *ctx = (ucontext_t*)ctx_void; + memcpy(&resulting_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t)); + memcpy(&ctx->uc_mcontext.gregs, &initial_regs, sizeof(gregset_t)); +} + +static char altstack_data[SIGSTKSZ]; + +int main() +{ + setup_ldt(); + + stack_t stack = { + .ss_sp = altstack_data, + .ss_size = SIGSTKSZ, + }; + if (sigaltstack(&stack, NULL) != 0) + err(1, "sigaltstack"); + + sethandler(SIGUSR1, sigusr1, 0); + sethandler(SIGTRAP, sigtrap, SA_ONSTACK); + + raise(SIGUSR1); + + int nerrs = 0; + + for (int i = 0; i < NGREG; i++) { + greg_t req = requested_regs[i], res = resulting_regs[i]; + if (i == REG_TRAPNO || i == REG_RIP) + continue; /* don't care */ + if (i == REG_RSP) { + printf("RSP: %llx -> %llx\n", req, res); + if (res == (req & 0xFFFFFFFF)) + continue; /* OK; not expected to work */ + } + if (requested_regs[i] != resulting_regs[i]) { + printf("Reg %d mismatch: requested 0x%llx; got 0x%llx\n", + i, requested_regs[i], resulting_regs[i]); + nerrs++; + } + } + + if (nerrs) { + printf("[FAIL]\t%d registers were corrupted\n", nerrs); + return 1; + } else { + printf("[OK]\tall tests passed\n"); + return 0; + } +} |