DF-4651 / fm801_probe.c
/* * 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; } |