DF-5335 / iretbug.c
/* * iretbug.c - probe the doreti_iret fault state machine * (trap.c:679-682 redirect -> ipl.s doreti_iret_fault frame rebuild) * * A signal handler modifies the saved user context so that the iretq * at doreti_iret faults when the kernel returns to user mode after * sigreturn. The kernel must reconstruct a trap frame and deliver * SIGBUS/SIGSEGV; if the reconstruction is broken we expect a kernel * panic instead. * * variants: * 0: mc_ss = 0 (null stack selector -> #GP at iretq) * 1: mc_ss = 0xdead (garbage selector beyond GDT -> #GP) * 2: mc_rsp = 0x0000800000000000 (non-canonical rsp -> #GP) * 3: mc_cs = 0x2b (data selector as cs; RPL3 so passes * CS_SECURE check in sys_sigreturn) * 4: mc_ss = 0x1b|... (code sel as ss) * 5: mc_ss = 0x4 (rpl0 selector as ss -> #GP) * 7: mc_ss = 0x10 (kernel data selector as ss) * 6: control - no modification (should exit cleanly) */ #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> static int variant = 6; static void handler(int sig, siginfo_t *si, void *ctx) { ucontext_t *uc = ctx; switch (variant) { case 0: uc->uc_mcontext.mc_ss = 0; break; case 1: uc->uc_mcontext.mc_ss = 0xdead; break; case 2: uc->uc_mcontext.mc_rsp = 0x0000800000000000LL; break; case 3: uc->uc_mcontext.mc_cs = 0x2b; break; case 4: uc->uc_mcontext.mc_ss = 0x1b; break; case 5: uc->uc_mcontext.mc_ss = 0x4; break; case 7: uc->uc_mcontext.mc_ss = 0x10; break; /* kernel data sel */ default: break; } printf("handler: variant %d, returning into modified frame\n", variant); fflush(stdout); } int main(int argc, char **argv) { struct sigaction sa; if (argc > 1) variant = atoi(argv[1]); memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = handler; sa.sa_flags = SA_SIGINFO; sigaction(SIGUSR1, &sa, NULL); kill(getpid(), SIGUSR1); printf("SURVIVED: returned to unmodified context\n"); return (0); } |