DF-5745 / gmuxtrig.c
/* * 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); |