summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@amacapital.net>2014-07-14 19:23:15 -0700
committerAndy Lutomirski <luto@amacapital.net>2014-07-14 19:23:15 -0700
commitdbfe196a0f6efedc119deb1cdbb0139dbdf609ee (patch)
treeb8d2063c4344fb5b3b4dc23a6bbfb6e74801187f
parentcb45491da0ec079ee440b36af13086722ba594ed (diff)
downloadmisc-tests-dbfe196a0f6efedc119deb1cdbb0139dbdf609ee.tar.gz
sigreturn: split into 32-bit and 64-bit versions
The 32-bit version works on unpatched kernels.
-rw-r--r--.gitignore1
-rw-r--r--Makefile4
-rw-r--r--sigreturn.c119
3 files changed, 95 insertions, 29 deletions
diff --git a/.gitignore b/.gitignore
index df19b87..a0587a1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,7 +6,6 @@ kernel_pf
user_visible_state
highsys
null_seccomp
-sigreturn
*~
*_32
*_64
diff --git a/Makefile b/Makefile
index 0244908..7a319fd 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,10 @@
.PHONY: all clean
-SIMPLE_C_TARGETS := dump-vsyscall context_switch_latency kernel_pf user_visible_state null_seccomp highsys sigreturn
+SIMPLE_C_TARGETS := dump-vsyscall context_switch_latency kernel_pf user_visible_state null_seccomp highsys
SIMPLE_CC_TARGETS := evil-clock-test
-SPLIT_C_TARGETS := dump-vdso dump-vvar syscall_exit_regs
+SPLIT_C_TARGETS := dump-vdso dump-vvar syscall_exit_regs sigreturn
SPLIT_CC_TARGETS := timing_test test_vsyscall test_vdso_parser
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
diff --git a/sigreturn.c b/sigreturn.c
index b863eab..ac68944 100644
--- a/sigreturn.c
+++ b/sigreturn.c
@@ -20,7 +20,7 @@
#include <sys/user.h>
struct selectors {
- short cs, gs, fs, ss;
+ unsigned short cs, gs, fs, ss;
};
static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
@@ -33,7 +33,6 @@ static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
sigemptyset(&sa.sa_mask);
if (sigaction(sig, &sa, 0))
err(1, "sigaction");
-
}
static unsigned char stack16[65536] __attribute__((aligned(4096)));
@@ -42,6 +41,7 @@ asm (".pushsection .text\n\t"
".type int3, @function\n\t"
".align 4096\n\t"
"int3:\n\t"
+ "mov %ss,%ax\n\t"
"int3\n\t"
".size int3, . - int3\n\t"
".align 4096, 0xcc\n\t"
@@ -50,9 +50,9 @@ extern char int3[4096];
static void setup_ldt(void)
{
- if ((unsigned long)stack16 > (1UL << 32) - sizeof(stack16))
+ if ((unsigned long)stack16 > (1ULL << 32) - sizeof(stack16))
errx(1, "stack16 is too high\n");
- if ((unsigned long)int3 > (1UL << 32) - sizeof(int3))
+ if ((unsigned long)int3 > (1ULL << 32) - sizeof(int3))
errx(1, "int3 is too high\n");
// Borrowed from a test case by hpa
@@ -89,29 +89,59 @@ static gregset_t initial_regs, requested_regs, resulting_regs;
static bool sig_twiddle_cs, sig_twiddle_ss;
+#ifdef __x86_64__
+# define REG_IP REG_RIP
+# define REG_SP REG_RSP
+# define REG_AX REG_RAX
+
+static unsigned short *ssptr(ucontext_t *ctx)
+{
+ struct selectors *sels = (void *)&ctx->uc_mcontext.gregs[REG_CSGSFS];
+ return &sels->ss;
+}
+
+static unsigned short *csptr(ucontext_t *ctx)
+{
+ struct selectors *sels = (void *)&ctx->uc_mcontext.gregs[REG_CSGSFS];
+ return &sels->cs;
+}
+#else
+# define REG_IP REG_EIP
+# define REG_SP REG_ESP
+# define REG_AX REG_EAX
+
+static greg_t *ssptr(ucontext_t *ctx)
+{
+ return &ctx->uc_mcontext.gregs[REG_SS];
+}
+
+static greg_t *csptr(ucontext_t *ctx)
+{
+ return &ctx->uc_mcontext.gregs[REG_CS];
+}
+#endif
+
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];
if (sig_twiddle_cs)
- sels->cs = (0 << 3) | 7; /* LDT selector 0, RPL = 3 */
- if (sig_twiddle_ss)
- sels->ss = (1 << 3) | 7; /* LDT selector 1, RPL = 3 */
+ *csptr(ctx) = (0 << 3) | 7; /* LDT selector 0, RPL = 3 */
- /* Avoid spurious failures. */
- asm volatile ("mov %0,%%ds\n\t"
- "mov %0,%%es\n\t"
- : : "r" ((1 << 3) | 7) /* LDT selector 1, RPL = 3 */
- );
+ if (sig_twiddle_ss)
+ *ssptr(ctx) = (1 << 3) | 7; /* LDT selector 1, RPL = 3 */
+ else /* Fix for unpatched kernels. */
+ asm volatile ("mov %%ss,%0" : "=r" (*ssptr(ctx)));
- ctx->uc_mcontext.gregs[REG_RIP] =
+ ctx->uc_mcontext.gregs[REG_IP] =
sig_twiddle_cs ? 0 : (unsigned long)&int3;
- ctx->uc_mcontext.gregs[REG_RSP] = 0x8badf00d5aadc0de;
+ ctx->uc_mcontext.gregs[REG_SP] = (unsigned long)0x8badf00d5aadc0deULL;
+ ctx->uc_mcontext.gregs[REG_AX] = 0;
memcpy(&requested_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t));
+ requested_regs[REG_AX] = *ssptr(ctx); /* The asm code does this. */
return;
}
@@ -119,11 +149,12 @@ static void sigusr1(int sig, siginfo_t *info, void *ctx_void)
static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
{
ucontext_t *ctx = (ucontext_t*)ctx_void;
- struct selectors *sels = (void *)&ctx->uc_mcontext.gregs[REG_CSGSFS];
unsigned short ss;
asm ("mov %%ss,%0" : "=r" (ss));
- printf("\tSIGTRAP: ss = %hx, frame ss = %hx\n", ss, sels->ss);
+ printf("\tSIGTRAP: ss = %hx, frame ss = %hx, ax = %llx\n",
+ ss, *ssptr(ctx),
+ (unsigned long long)ctx->uc_mcontext.gregs[REG_AX]);
memcpy(&resulting_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t));
memcpy(&ctx->uc_mcontext.gregs, &initial_regs, sizeof(gregset_t));
@@ -144,23 +175,59 @@ static int do_test(bool twiddle_cs, bool twiddle_ss)
for (int i = 0; i < NGREG; i++) {
greg_t req = requested_regs[i], res = resulting_regs[i];
- if (i == REG_TRAPNO || i == REG_RIP)
+ if (i == REG_TRAPNO || i == REG_IP)
continue; /* don't care */
- if (i == REG_RSP) {
- printf("\tRSP: %llx -> %llx\n", req, res);
+ if (i == REG_SP) {
+ printf("\tSP: %llx -> %llx\n", (unsigned long long)req,
+ (unsigned long long)res);
if (res == (req & 0xFFFFFFFF))
continue; /* OK; not expected to work */
}
- if (requested_regs[i] != resulting_regs[i]) {
- printf("\tReg %d mismatch: requested 0x%llx; got 0x%llx\n",
- i, requested_regs[i], resulting_regs[i]);
+
+ bool ignore_reg = false;
+#if __i386__
+ if (i == REG_UESP)
+ ignore_reg = true;
+#else
+ if (i == REG_CSGSFS) {
+ struct selectors *req_sels =
+ (void *)&requested_regs[REG_CSGSFS];
+ struct selectors *res_sels =
+ (void *)&resulting_regs[REG_CSGSFS];
+ if (req_sels->cs != res_sels->cs) {
+ printf("[FAIL]\tCS mismatch: requested 0x%hx; got 0x%hx\n",
+ req_sels->cs, res_sels->cs);
+ nerrs++;
+ }
+
+ if (req_sels->ss != res_sels->ss) {
+ printf("[FAIL]\tSS mismatch: requested 0x%hx; got 0x%hx\n",
+ req_sels->ss, res_sels->ss);
+ nerrs++;
+ }
+
+ continue;
+ }
+#endif
+
+ /* Sanity check on the kernel */
+ if (i == REG_AX && requested_regs[i] != resulting_regs[i]) {
+ printf("[FAIL]\tAX (saved SP) mismatch: requested 0x%llx; got 0x%llx\n",
+ (unsigned long long)requested_regs[i],
+ (unsigned long long)resulting_regs[i]);
+ nerrs++;
+ continue;
+ }
+
+ if (requested_regs[i] != resulting_regs[i] && !ignore_reg) {
+ printf("[FAIL]\tReg %d mismatch: requested 0x%llx; got 0x%llx\n",
+ i, (unsigned long long)requested_regs[i],
+ (unsigned long long)resulting_regs[i]);
nerrs++;
}
}
- if (nerrs)
- printf("[FAIL]\t%d registers were corrupted\n", nerrs);
- else
+ if (nerrs == 0)
printf("[OK]\tall registers okay\n");
return nerrs;