DF-4311 / uaftrig.c
/* * uaftrig.ko - PoC stand-in for drm.ko's LIVE vga_switcheroo call-in sites * (sys/dev/drm/drm_edid.c:1770 drm_get_edid_switcheroo -> * vga_switcheroo_lock_ddc()/vga_switcheroo_unlock_ddc(), * sys/dev/drm/i915/i915_drv.c:742 vga_switcheroo_force_migd()). * * Writing /dev/uaftrig invokes vga_switcheroo_lock_ddc()/_unlock_ddc() * exactly as the DRM EDID probe path does. The module resolves those * symbols at load time from the loaded vga_switcheroo.ko (same as drm.ko * would). After `kldunload vga_switcheroo`, the same call goes through * a dangling relocated reference into freed module memory. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/bio.h> #include <sys/bus.h> #include <sys/malloc.h> #include <sys/module.h> #include <sys/proc.h> #include <sys/types.h> #include <sys/sysctl.h> #include <sys/systm.h> #include <sys/device.h> #include <sys/conf.h> #include <sys/rman.h> #include <sys/uio.h> #include <sys/errno.h> #include <linux/pci.h> int vga_switcheroo_lock_ddc(struct pci_dev *pdev); int vga_switcheroo_unlock_ddc(struct pci_dev *pdev); static d_open_t uaftrig_open; static d_close_t uaftrig_close; static d_write_t uaftrig_write; static struct dev_ops uaftrig_ops = { { "uaftrig", 0, 0 }, .d_open = uaftrig_open, .d_close = uaftrig_close, .d_write = uaftrig_write, }; static cdev_t uaftrig_dev; static int uaftrig_open(struct dev_open_args *ap __unused) { return (0); } static int uaftrig_close(struct dev_close_args *ap __unused) { return (0); } static int uaftrig_write(struct dev_write_args *ap __unused) { int r1, r2; r1 = vga_switcheroo_lock_ddc(NULL); kprintf("uaftrig: vga_switcheroo_lock_ddc(NULL) = %d\n", r1); r2 = vga_switcheroo_unlock_ddc(NULL); kprintf("uaftrig: vga_switcheroo_unlock_ddc(NULL) = %d\n", r2); return (0); } static int uaftrig_modhandler(struct module *m __unused, int what, void *arg __unused) { switch (what) { case MOD_LOAD: uaftrig_dev = make_dev(&uaftrig_ops, 0, UID_ROOT, GID_WHEEL, 0600, "uaftrig"); kprintf("uaftrig: loaded /dev/uaftrig (stand-in for drm.ko's " "vga_switcheroo references)\n"); break; case MOD_UNLOAD: if (uaftrig_dev != NULL) destroy_dev(uaftrig_dev); break; case MOD_SHUTDOWN: break; default: return (EOPNOTSUPP); } return (0); } DEV_MODULE(uaftrig, uaftrig_modhandler, NULL); /* Models the MODULE_DEPEND(drm/i915/amdgpu, vga_switcheroo, ...) fix */ MODULE_DEPEND(uaftrig, vga_switcheroo, 1, 1, 1); |