summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@amacapital.net>2014-07-14 14:28:49 -0700
committerAndy Lutomirski <luto@amacapital.net>2014-07-14 14:28:49 -0700
commitcb45491da0ec079ee440b36af13086722ba594ed (patch)
treef5a88ad3f8f30d78778ce85dd7ce2189022fea13
parentd9a083999ddfff824e2ddc4ae20e4ec24b0682bc (diff)
downloadmisc-tests-cb45491da0ec079ee440b36af13086722ba594ed.tar.gz
sigreturn: Improve (and require kernel patch)
-rw-r--r--sigreturn.c87
1 files changed, 59 insertions, 28 deletions
diff --git a/sigreturn.c b/sigreturn.c
index 01f92f7..b863eab 100644
--- a/sigreturn.c
+++ b/sigreturn.c
@@ -14,9 +14,13 @@
#include <asm/ldt.h>
#include <err.h>
#include <setjmp.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <sys/ptrace.h>
+#include <sys/user.h>
struct selectors {
- short cs, gs, fs, __pad0;
+ short cs, gs, fs, ss;
};
static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
@@ -49,7 +53,7 @@ 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");
+ errx(1, "int3 is too high\n");
// Borrowed from a test case by hpa
const struct user_desc code16_desc = {
@@ -83,6 +87,8 @@ static void setup_ldt(void)
static gregset_t initial_regs, requested_regs, resulting_regs;
+static bool sig_twiddle_cs, sig_twiddle_ss;
+
static void sigusr1(int sig, siginfo_t *info, void *ctx_void)
{
ucontext_t *ctx = (ucontext_t*)ctx_void;
@@ -90,17 +96,20 @@ static void sigusr1(int sig, siginfo_t *info, void *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. */
+ 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 */
- asm volatile ("mov %0,%%ss\n\t"
- "mov %0,%%ds\n\t"
+ /* Avoid spurious failures. */
+ asm volatile ("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;
+ ctx->uc_mcontext.gregs[REG_RIP] =
+ sig_twiddle_cs ? 0 : (unsigned long)&int3;
+ ctx->uc_mcontext.gregs[REG_RSP] = 0x8badf00d5aadc0de;
memcpy(&requested_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t));
@@ -110,25 +119,24 @@ 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);
+
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()
+static int do_test(bool twiddle_cs, bool twiddle_ss)
{
- 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);
+ printf("\ttwiddle_cs = %d, twiddle_ss = %d\n",
+ (int)twiddle_cs, (int)twiddle_ss);
+ sig_twiddle_cs = twiddle_cs;
+ sig_twiddle_ss = twiddle_ss;
raise(SIGUSR1);
@@ -139,22 +147,45 @@ int main()
if (i == REG_TRAPNO || i == REG_RIP)
continue; /* don't care */
if (i == REG_RSP) {
- printf("RSP: %llx -> %llx\n", req, res);
+ printf("\tRSP: %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",
+ printf("\tReg %d mismatch: requested 0x%llx; got 0x%llx\n",
i, requested_regs[i], resulting_regs[i]);
nerrs++;
}
}
- if (nerrs) {
+ if (nerrs)
printf("[FAIL]\t%d registers were corrupted\n", nerrs);
- return 1;
- } else {
- printf("[OK]\tall tests passed\n");
- return 0;
- }
+ else
+ printf("[OK]\tall registers okay\n");
+
+ return nerrs;
+}
+
+int main()
+{
+ int nerrs = 0;
+
+ 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);
+
+ nerrs += do_test(false, false);
+ nerrs += do_test(true, false);
+ nerrs += do_test(false, true);
+ nerrs += do_test(true, true);
+
+ return nerrs ? 1 : 0;
}