DF-5408 / iretvm.c
/* * iretvm.c — direct probe: does a CPL3 iretq with EFLAGS.VM=1 (long mode) * #GP on this CPU? Bypasses every kernel path; pure hardware semantics * under the current QEMU/KVM configuration. * * build: cc -O -o iretvm iretvm.c */ #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <setjmp.h> #include <stdlib.h> static sigjmp_buf jb; static volatile int faulted; static void fh(int sig) { faulted = sig; siglongjmp(jb, 1); } static unsigned long rflags_live(void) { unsigned long rf; __asm __volatile("pushfq; popq %0" : "=r" (rf)); return rf; } unsigned long mycs, myss, myrsp, myrip; int main(int ac, char **av) { unsigned long rf0 = rflags_live(); unsigned long sp, out_rf = 0; int rc; int vmflag = (ac > 1) ? atoi(av[1]) : 1; signal(SIGSEGV, fh); signal(SIGBUS, fh); signal(SIGILL, fh); __asm __volatile( "movq %%cs,%0\n" "movq %%ss,%1\n" : "=r"(mycs), "=r"(myss)); printf("iretvm: live rflags=%lx cs=%lx ss=%lx vm=%d\n", rf0, mycs, myss, vmflag); fflush(stdout); if (sigsetjmp(jb, 1) != 0) { printf("iretvm: iretq with VM FAULTED: sig=%d\n", faulted); fflush(stdout); return (2); } /* build the iret frame and execute it */ __asm __volatile( "leaq 1f(%%rip),%%rax\n" /* rip */ "movq %%rsp,%%rdx\n" /* rsp */ "subq $128,%%rdx\n" "movq %%rax,%0\n" "movq %%rdx,%1\n" : "=m"(myrip), "=m"(myrsp) : : "rax", "rdx"); { unsigned long frame[5]; frame[0] = myrip; /* rip */ frame[1] = mycs; /* cs (RPL3) */ frame[2] = 0x246 | (vmflag ? 0x20000 : 0); /* rflags */ frame[3] = myrsp; /* rsp */ frame[4] = myss; /* ss (RPL3) */ /* long-mode iretq pops rip,cs,rflags,rsp,ss (5 slots, * unconditionally): 5 pushes, 5 pops -> stack balanced */ __asm __volatile( "pushq %4\n" "pushq %3\n" "pushq %2\n" "pushq %1\n" "pushq %0\n" "iretq\n" "1:\n" : : "r"(frame[0]), "r"(frame[1]), "r"(frame[2]), "r"(frame[3]), "r"(frame[4]) : "memory"); } printf("iretvm: iretq %s RETURNED normally; live rflags=%lx " "(vm=%d)\n", vmflag ? "with VM" : "no-VM control", rflags_live(), (int)((rflags_live() & 0x20000) ? 1 : 0)); fflush(stdout); rc = ((rflags_live() & 0x20000) == 0); printf("iretvm: RESULT=%s\n", rc ? "VM-SILENTLY-CLEARED" : "VM-SET?!"); return (0); } |