diff options
author | Andy Lutomirski <luto@amacapital.net> | 2014-07-05 08:46:36 -0700 |
---|---|---|
committer | Andy Lutomirski <luto@amacapital.net> | 2014-07-05 08:46:36 -0700 |
commit | eab1732d0553cffad95f31181183eee069227548 (patch) | |
tree | 302c0e71df0413ad53f91f10d7c1a3b3c4c36d46 | |
parent | a855db50712b45bc6e531a00d00b1b6c519943ee (diff) | |
parent | fc315dc49fbdec7e5c99a76eba5af9cdb4813bf8 (diff) | |
download | misc-tests-eab1732d0553cffad95f31181183eee069227548.tar.gz |
Merge test_vdso_parser
-rw-r--r-- | .gitignore | 11 | ||||
-rw-r--r-- | Makefile | 53 | ||||
-rw-r--r-- | dump-vdso.c | 1 | ||||
-rw-r--r-- | dump-vvar.c | 47 | ||||
-rw-r--r-- | evil-clock-test.cc | 22 | ||||
-rw-r--r-- | highsys.c | 18 | ||||
-rw-r--r-- | null_seccomp.c | 33 | ||||
-rw-r--r-- | sigreturn.c | 160 | ||||
-rw-r--r-- | syscall32_from_64.c | 22 | ||||
-rw-r--r-- | syscall_exit_regs.c | 19 | ||||
-rw-r--r-- | thunks.S | 60 |
11 files changed, 395 insertions, 51 deletions
@@ -1,13 +1,12 @@ -dump-vdso -dump-vvar dump-vsyscall -timing_test_32 -timing_test_64 time-warp-test evil-clock-test -test_vsyscall_32 -test_vsyscall_64 context_switch_latency kernel_pf user_visible_state +highsys +null_seccomp +sigreturn *~ +*_32 +*_64 @@ -1,44 +1,39 @@ .PHONY: all clean -all: timing_test_64 timing_test_32 evil-clock-test test_vsyscall_64 test_vsyscall_32 dump-vdso dump-vvar dump-vsyscall context_switch_latency kernel_pf user_visible_state test_vdso_parser_64 test_vdso_parser_32 -clean: - rm -f timing_test_64 timing_test_32 evil-clock-test test_vsyscall_64 test_vsyscall_32 dump-vdso dump-vvar dump-vsyscall context_switch_latency kernel_pf user_visible_state test_vdso_parser_64 test_vdso_parser_32 +SIMPLE_C_TARGETS := dump-vsyscall context_switch_latency kernel_pf user_visible_state null_seccomp highsys sigreturn -user_visible_state: user_visible_state.c - gcc -o $@ -O2 -std=gnu99 -Wall $(EXTRA_CFLAGS) -g $^ -lrt -ldl +SIMPLE_CC_TARGETS := evil-clock-test -kernel_pf: kernel_pf.c - gcc -o $@ -O2 -std=gnu99 -Wall $(EXTRA_CFLAGS) -g $^ -lrt -ldl +SPLIT_C_TARGETS := dump-vdso dump-vvar syscall_exit_regs +SPLIT_CC_TARGETS := timing_test test_vsyscall test_vdso_parser -timing_test_64: timing_test.cc - g++ -m64 -o $@ -O2 -Wall $(EXTRA_CFLAGS) -g $^ -lrt -ldl +ALL_TARGETS := $(SIMPLE_C_TARGETS) $(SIMPLE_CC_TARGETS) $(SPLIT_C_TARGETS:%=%_64) $(SPLIT_CC_TARGETS:%=%_64) $(SPLIT_C_TARGETS:%=%_32) $(SPLIT_CC_TARGETS:%=%_32) syscall32_from_64 -timing_test_32: timing_test.cc - g++ -m32 -o $@ -O2 -Wall $(EXTRA_CFLAGS) -g $^ -lrt -ldl +CFLAGS := -O2 -g -std=gnu99 -pthread -Wall +CCFLAGS := -O2 -g -std=gnu++11 -pthread -Wall -evil-clock-test: evil-clock-test.cc - g++ -o $@ -pthread -O2 -Wall $(EXTRA_CFLAGS) -g $^ -lrt +all: $(ALL_TARGETS) -test_vsyscall_64: test_vsyscall.cc - g++ -m64 -o $@ -std=gnu++0x -O2 -Wall $(EXTRA_CFLAGS) -g $^ -lrt -ldl +clean: + rm -f $(ALL_TARGETS) -test_vsyscall_32: test_vsyscall.cc - g++ -m32 -o $@ -std=gnu++0x -O2 -Wall $(EXTRA_CFLAGS) -g $^ -lrt -ldl +$(SIMPLE_C_TARGETS): %: %.c + gcc -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl -test_vdso_parser_64: test_vdso_parser.cc - g++ -m64 -o $@ -std=gnu++0x -O2 -Wall $(EXTRA_CFLAGS) -g $^ -lrt -ldl +$(SIMPLE_CC_TARGETS): %: %.cc + g++ -o $@ $(CCFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl -test_vdso_parser_32: test_vdso_parser.cc - g++ -m32 -o $@ -std=gnu++0x -O2 -Wall $(EXTRA_CFLAGS) -g $^ -lrt -ldl +$(SPLIT_C_TARGETS:%=%_32): %_32: %.c + gcc -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl -dump-vdso: dump-vdso.c - gcc -o $@ -O2 $(EXTRA_CFLAGS) $^ -ldl +$(SPLIT_C_TARGETS:%=%_64): %_64: %.c + gcc -m64 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl -dump-vvar: dump-vvar.c - gcc -o $@ -O2 $(EXTRA_CFLAGS) $^ +$(SPLIT_CC_TARGETS:%=%_32): %_32: %.cc + g++ -m32 -o $@ $(CCFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl -dump-vsyscall: dump-vsyscall.c - gcc -o $@ -O2 $(EXTRA_CFLAGS) $^ -ldl +$(SPLIT_CC_TARGETS:%=%_64): %_64: %.cc + g++ -m64 -o $@ $(CCFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl -context_switch_latency: context_switch_latency.c - g++ -o $@ -pthread -O2 -Wall -g $(EXTRA_CFLAGS) $^ -lrt +syscall32_from_64: syscall32_from_64.c thunks.S + gcc -m64 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl diff --git a/dump-vdso.c b/dump-vdso.c index dbd6439..a4b6f63 100644 --- a/dump-vdso.c +++ b/dump-vdso.c @@ -1,5 +1,6 @@ #include <stdio.h> #include <string.h> +#include <unistd.h> int main() { diff --git a/dump-vvar.c b/dump-vvar.c index 14f0d39..dce7b66 100644 --- a/dump-vvar.c +++ b/dump-vvar.c @@ -1,13 +1,50 @@ +#define _GNU_SOURCE #include <stdio.h> #include <string.h> +#include <sys/mman.h> +#include <unistd.h> int main() { - char page[4096]; - fprintf(stderr, "Do not rely on this program to work across " - "kernel versions\n"); - memcpy(page, (const void *)(0xffffffffff5ff000), 4096); - write(1, page, 4096); + FILE *maps; + void *vvar_begin, *vvar_end; + int found_vvar = 0; + + maps = fopen("/proc/self/maps", "r"); + char buf[1024]; + while (fgets(buf, 1024, maps)) { + if (strstr(buf, "[vvar]")) { + found_vvar = 1; + break; + } + } + fclose(maps); + + if (!found_vvar) { + fprintf(stderr, "Could not find vvar mapping\n"); + return 1; + } + + sscanf(buf, "%p-%p", &vvar_begin, &vvar_end); + + fprintf(stderr, "vvar mapping is at 0x%lx to 0x%lx\n", + (unsigned long)vvar_begin, (unsigned long)vvar_end); + + maps = fopen("/proc/self/maps", "r"); + mremap(vvar_begin, vvar_end-vvar_begin, vvar_end-vvar_begin, MREMAP_FIXED | MREMAP_MAYMOVE, 0x0badc0de0000); + + mremap(vvar_begin - 4096, 4096, 4096, MREMAP_FIXED | MREMAP_MAYMOVE, 0x0badc0de0000 - 4096); + + while (fgets(buf, 1024, maps)) { + fprintf(stderr, "%s", buf); + } + + vvar_end = (void*)0x0badc0de0000 + (vvar_end - vvar_begin); + vvar_begin = (void*)0x0badc0de0000; + + write(1, vvar_begin, vvar_end - vvar_begin); + + mprotect(vvar_begin, vvar_end - vvar_begin, PROT_READ | PROT_WRITE); return 0; } diff --git a/evil-clock-test.cc b/evil-clock-test.cc index 164a0b1..153cd28 100644 --- a/evil-clock-test.cc +++ b/evil-clock-test.cc @@ -279,7 +279,7 @@ public: // Consume one entry from times2 if (times2[i]) { if (times2[i] < t2max) { - printf(" ERROR! Time2 went back by %"PRIu64"\n", + printf(" ERROR! Time2 went back by %" PRIu64 "\n", t2max - times2[i]); worst_error = INT64_MAX; } else { @@ -297,7 +297,7 @@ public: // Consume one entry from times1 if (times1[i]) { if (times1[i] < t1max) { - printf(" ERROR! Time1 went back by %"PRIu64"\n", + printf(" ERROR! Time1 went back by %" PRIu64 "\n", t1max - times1[i]); worst_error = INT64_MAX; } else { @@ -313,7 +313,7 @@ public: if (nsamples == 0) printf(" No data!\n"); else if (worst_error <= 0) - printf(" Passed with margin %" PRIi64 " (%"PRIu64" samples)\n", + printf(" Passed with margin %" PRIi64 " (%" PRIu64 " samples)\n", -worst_error, nsamples); else printf(" Failed %" PRIu64 "/%" PRIu64 " times with worst error %" PRIi64 "\n", @@ -705,10 +705,10 @@ static void run() if (t->nsamples == 0) printf("Now test got no data\n"); else if (t->worst_error > 0) - printf("Now test failed : worst error %"PRIi64" with %"PRIu64" samples\n", + printf("Now test failed : worst error %" PRIi64 " with %" PRIu64 " samples\n", t->worst_error, t->nsamples); else - printf("Now test passed : margin %"PRIi64" with %"PRIu64" samples\n", + printf("Now test passed : margin %" PRIi64 " with %" PRIu64 " samples\n", -t->worst_error, t->nsamples); delete t; @@ -726,10 +726,10 @@ static void run() if (t->nsamples == 0) printf("Load3 test got no data\n"); else if (t->worst_error > 0) - printf("Load3 test failed: worst error %"PRIi64" with %"PRIu64" samples\n", + printf("Load3 test failed: worst error %" PRIi64 " with %" PRIu64 " samples\n", t->worst_error, t->nsamples); else - printf("Load3 test passed: margin %"PRIi64" with %"PRIu64" samples\n", + printf("Load3 test passed: margin %" PRIi64 " with %" PRIu64 " samples\n", -t->worst_error, t->nsamples); delete t; @@ -747,10 +747,10 @@ static void run() if (t->nsamples == 0) { printf("Load test got no data\n"); } else if (t->worst_error > 0) { - printf("Load test failed : worst error %"PRIi64" with %"PRIu64" samples\n", + printf("Load test failed : worst error %" PRIi64 " with %" PRIu64 " samples\n", t->worst_error, t->nsamples); } else { - printf("Load test passed : margin %"PRIi64" with %"PRIu64" samples\n", + printf("Load test passed : margin %" PRIi64 " with %" PRIu64 " samples\n", -t->worst_error, t->nsamples); } @@ -769,11 +769,11 @@ static void run() if (t->nsamples == 0) { printf("Store test got no data\n"); } else if (t->worst_error > 0) { - printf("Store test failed%s: worst error %"PRIi64" with %"PRIu64" samples\n", + printf("Store test failed%s: worst error %" PRIi64 " with %" PRIu64 " samples\n", ClockType::is_strict ? "" : " as expected", t->worst_error, t->nsamples); } else { - printf("Store test passed: margin %"PRIi64" with %"PRIu64" samples\n", + printf("Store test passed: margin %" PRIi64 " with %" PRIu64 " samples\n", -t->worst_error, t->nsamples); } diff --git a/highsys.c b/highsys.c new file mode 100644 index 0000000..93eb45e --- /dev/null +++ b/highsys.c @@ -0,0 +1,18 @@ +#include <stdio.h> +#include <sys/syscall.h> + +static long high_getpid(void) +{ + long ret; + asm volatile ("syscall" : + "=a" (ret) : + "a" (SYS_getpid | 0xbaadf00d00000000ULL) : + "memory", "cc", "rcx", "r11"); + return ret; +} + +int main() +{ + printf("high_getpid says %ld\n", high_getpid()); + return 0; +} diff --git a/null_seccomp.c b/null_seccomp.c new file mode 100644 index 0000000..752c73d --- /dev/null +++ b/null_seccomp.c @@ -0,0 +1,33 @@ +#include <unistd.h> +#include <linux/filter.h> +#include <linux/seccomp.h> +#include <sys/syscall.h> +#include <err.h> +#include <sys/prctl.h> +#include <stddef.h> +#include <stdio.h> + +int main(int argc, char **argv) +{ + struct sock_filter filter[] = { + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), + }; + + struct sock_fprog prog = { + .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), + .filter = filter, + }; + + if (argc < 2) { + printf("Usage: null_seccomp PATH ARGS...\n"); + return 1; + } + + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) + err(1, "PR_SET_NO_NEW_PRIVS"); + if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) + err(1, "PR_SET_SECCOMP"); + + execv(argv[1], argv + 1); + err(1, argv[1]); +} 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; + } +} diff --git a/syscall32_from_64.c b/syscall32_from_64.c new file mode 100644 index 0000000..775cef2 --- /dev/null +++ b/syscall32_from_64.c @@ -0,0 +1,22 @@ +#include <stdio.h> + +extern unsigned long call32_from_64(void *stack, void (*function)(void)); + +asm (".pushsection .text\n\t" + ".code32\n\t" + "syscall32:\n\t" + "mov $20,%eax\n\t" // NR_getpid (32-bit) + "syscall\n\t" + "syscall32_ret:\n\t" + "ret\n\t" + ".code64"); +extern void syscall32(void); + +static char low_stack[4096]; + +int main() +{ + unsigned long ret = call32_from_64(low_stack, syscall32); + printf("syscall return = %ld\n", (long)ret); + return 0; +} diff --git a/syscall_exit_regs.c b/syscall_exit_regs.c new file mode 100644 index 0000000..4c7f97e --- /dev/null +++ b/syscall_exit_regs.c @@ -0,0 +1,19 @@ +#include <stdio.h> + +int main() +{ + extern const char syscall_rip[]; + unsigned long rcx = 1; + unsigned long orig_rcx = rcx; + asm ("mov $-1, %%eax\n\t" + "syscall\n\t" + "syscall_rip:" + : "+c" (rcx) : : +#ifdef __x86_64__ + "r11" +#endif + ); + printf("syscall: RCX = %lX RIP = %lX orig RCX = %lx\n", + rcx, (unsigned long)syscall_rip, orig_rcx); + return 0; +} diff --git a/thunks.S b/thunks.S new file mode 100644 index 0000000..ab3a0a0 --- /dev/null +++ b/thunks.S @@ -0,0 +1,60 @@ + .text + + .global init_thunks + .type init_thunks, @function +init_thunks: + mov $0x2b, %rax /* USER32_DS */ + mov %rax,%ss + mov %rax,%ds + mov %rax,%es + ret +.size init_thunks, .-init_thunks + + .global call32_from_64 + .type call32_from_64, @function +call32_from_64: + // rdi: stack to use + // esi: function to call + + // Save registers + pushq %rbx + pushq %rbp + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + pushfq + + // Switch stacks + mov %rsp,(%rdi) + mov %rdi,%rsp + + // Switch to compatibility mode + pushq $0x23 /* USER32_CS */ + pushq $1f + lretq + +1: + .code32 + // Call the function + call *%esi + // Switch back to long mode + jmp $0x33,$1f + .code64 + +1: + // Restore the stack + mov (%rsp),%rsp + + // Restore registers + popfq + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + popq %rbx + + ret + +.size call32_from_64, .-call32_from_64 |