summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@amacapital.net>2014-07-05 08:46:36 -0700
committerAndy Lutomirski <luto@amacapital.net>2014-07-05 08:46:36 -0700
commiteab1732d0553cffad95f31181183eee069227548 (patch)
tree302c0e71df0413ad53f91f10d7c1a3b3c4c36d46
parenta855db50712b45bc6e531a00d00b1b6c519943ee (diff)
parentfc315dc49fbdec7e5c99a76eba5af9cdb4813bf8 (diff)
downloadmisc-tests-eab1732d0553cffad95f31181183eee069227548.tar.gz
Merge test_vdso_parser
-rw-r--r--.gitignore11
-rw-r--r--Makefile53
-rw-r--r--dump-vdso.c1
-rw-r--r--dump-vvar.c47
-rw-r--r--evil-clock-test.cc22
-rw-r--r--highsys.c18
-rw-r--r--null_seccomp.c33
-rw-r--r--sigreturn.c160
-rw-r--r--syscall32_from_64.c22
-rw-r--r--syscall_exit_regs.c19
-rw-r--r--thunks.S60
11 files changed, 395 insertions, 51 deletions
diff --git a/.gitignore b/.gitignore
index 2dde783..df19b87 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/Makefile b/Makefile
index ddf7adc..0244908 100644
--- a/Makefile
+++ b/Makefile
@@ -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