⬢ DragonFlyBSD Kernel Audit
DF-5745 / gmuxtrig.c
← back to finding ↓ download raw
/*
 * gmuxtrig.c -- NULL-deref trigger for DF-5745.
 *
 * Rig (SSDT): two gmux ACPI devices, AAA0 @ 0x8e and AAA2 @ 0x4cc, each with
 * a 4-byte _CRS. On QEMU/i440fx both bases have a readable non-0xff byte at
 * base+4 (0x92 = port-A register, 0x4d0/0x4d1 = ELCR), so BOTH devices take
 * the "classic" path deep into apple_gmux_attach():
 *
 *   AAA0: attach SUCCEEDS, vga_switcheroo_register_handler() registers
 *         gmux_handler_classic (apple-gmux.c:880-884), global
 *         apple_gmux_softc_data = sc(AAA0) (apple-gmux.c:867).
 *   AAA2: attach proceeds to apple-gmux.c:867 and OVERWRITES the global with
 *         sc(AAA2), then vga_switcheroo_register_handler() returns -EINVAL
 *         (handler exists, vga_switcheroo.c:242-245) -> err_register_handler
 *         -> apple_gmux_softc_data = NULL (apple-gmux.c:894).
 *
 * Net state: registered handler callbacks + NULL global. Any dispatch does
 *   gmux_switchto: apple_gmux_softc_data->switch_state_ddc = id
 *   (apple-gmux.c:511) => write to NULL+offset => fatal page fault.
 *
 * This module invokes the same production dispatch i915 uses at boot on
 * dual-GPU machines (sys/dev/drm/i915/i915_drv.c:742):
 *   vga_switcheroo_force_migd() -> vgasr_priv->handler->switchto()
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/systm.h>

#define	VGA_SWITCHEROO	1
#include <linux/vga_switcheroo.h>
/* vga_switcheroo_force_migd() is declared by the header above. */

static int
gmuxtrig_handler(struct module *m, int what, void *arg)
{
	int flags, ret;

	switch (what) {
	case MOD_LOAD:
		flags = vga_switcheroo_handler_flags();
		kprintf("gmuxtrig: vga_switcheroo handler_flags = 0x%x "
		    "(CAN_SWITCH_DDC=%d)\n", flags,
		    !!(flags & VGA_SWITCHEROO_CAN_SWITCH_DDC));
		kprintf("gmuxtrig: calling vga_switcheroo_force_migd() -> "
		    "gmux_switchto on clobbered apple_gmux_softc_data...\n");
		ret = vga_switcheroo_force_migd();
		kprintf("gmuxtrig: force_migd returned %d, NO PANIC\n", ret);
		break;
	}
	return (0);
}

static moduledata_t gmuxtrig_mod = { "gmuxtrig", gmuxtrig_handler, NULL };
DECLARE_MODULE(gmuxtrig, gmuxtrig_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
MODULE_DEPEND(gmuxtrig, vga_switcheroo, 1, 1, 2);