⬢ DragonFlyBSD Kernel Audit
DF-4651 / fm801_probe.c
← back to finding ↓ download raw
/*
 * DF-4651 environment probe — fm801 mixer-UAF (DF-4156 family, 14th).
 *
 * The bug: fm801_pci_attach() publishes the 0666 /dev/mixerN at
 * mixer_init() (fm801.c:620) and keeps THREE failure paths after it:
 *
 *   fm801.c:625-627   bus_alloc_resource_any(IRQ)/snd_setup_intr fail
 *   fm801.c:636-638   bus_dma_tag_create() fails
 *   fm801.c:646       pcm_register() fails (EINVAL pcm_veto_load
 *                     sound.c:1021 / ENODEV PCMMAXUNIT sound.c:1027)
 *
 * oops: (fm801.c:656-663) then runs
 *   ac97_destroy(codec)   <- kobj_delete(methods) + kfree(codec)
 *   kfree(fm801)
 * while the mixer cdev created inside mixer_init() (mixer.c:730-733,
 * make_dev(..., 0666, "mixer%d"), pdev->si_drv1 = m, m->devinfo = codec)
 * still dispatches open/ioctl into the freed objects -> use-after-free.
 *
 * Secondary defect on the same unwind: oops: releases fm801->reg
 * (fm801.c:658) BEFORE bus_teardown_intr (fm801.c:659), leaving a live
 * fm801_intr() window over an unmapped MMIO window (fm801_intr reads
 * FM_INTSTATUS at fm801.c:292 immediately).
 *
 * Reproduction on this audit guest is IMPOSSIBLE: it requires a Forte
 * Media FM801 PCI audio controller (1319:0801) whose attach reaches
 * mixer_init() (AC97 codec answers the FM register protocol) and then
 * fails at the IRQ / dma-tag / pcm_register step.  QEMU 7.2.22 has no
 * FM801 device model (only AC97/ES1370/intel-hda/sb16).
 *
 * This probe documents that absence and shows the trigger preconditions.
 */
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int
main(void)
{
	int i;

	printf("DF-4651 fm801 mixer-UAF trigger preconditions:\n");
	printf("  1. PCI audio function 1319:0801 (ForteMedia FM801)"
	    " present\n");
	printf("  2. attach reaches mixer_init() successfully (AC97 codec"
	    " answers via FM_CODEC_CMD protocol, fm801.c:210-238)\n");
	printf("  3. IRQ alloc/snd_setup_intr fails (fm801.c:625-627), or"
	    " bus_dma_tag_create fails (fm801.c:636-638), or pcm_register()"
	    " fails (fm801.c:646)\n");
	printf("  4. unprivileged user opens the surviving 0666 /dev/mixerN"
	    " -> mixer_ops -> freed snd_mixer/ac97_info/fm801_info\n\n");
	printf("This guest: see pciconf output in run.log / env.txt.\n");

	for (i = 0; i < 4; i++) {
		char p[64];
		snprintf(p, sizeof(p), "/dev/mixer%d", i);
		if (access(p, F_OK) == 0)
			printf("%s exists (belongs to attached pcm driver,"
			    " NOT snd_fm801 here)\n", p);
	}
	printf("probe done\n");
	return 0;
}