DF-5150 / fix.diff
--- a/sys/dev/acpica/acpi_lid.c +++ b/sys/dev/acpica/acpi_lid.c @@ -57,6 +57,7 @@ static int acpi_lid_probe(device_t dev); static int acpi_lid_attach(device_t dev); +static int acpi_lid_detach(device_t dev); static int acpi_lid_suspend(device_t dev); static int acpi_lid_resume(device_t dev); static void acpi_lid_notify_status_changed(void *arg); @@ -67,6 +68,7 @@ /* Device interface */ DEVMETHOD(device_probe, acpi_lid_probe), DEVMETHOD(device_attach, acpi_lid_attach), + DEVMETHOD(device_detach, acpi_lid_detach), DEVMETHOD(device_suspend, acpi_lid_suspend), DEVMETHOD(device_resume, acpi_lid_resume), @@ -128,6 +130,37 @@ return (0); } + +static int +acpi_lid_detach(device_t dev) +{ + struct acpi_lid_softc *sc; + struct acpi_prw_data prw; + + sc = device_get_softc(dev); + + /* + * Undo acpi_lid_attach(): the ACPICA notify handler holds `sc` as + * its context (acpi_lid.c:121-122) and acpi_lid_notify_handler() + * additionally defers `sc` to AcpiOsExecute() (acpi_lid.c:194-195), + * so leaving either registered past detach is a guaranteed UAF once + * any detach path exists. + * + * NOTE: AcpiRemoveNotifyHandler() waits for in-progress handler + * invocations but not for callbacks already queued to + * AcpiOsExecute(); a complete fix would also drain those before + * returning (e.g. a generation counter checked by + * acpi_lid_notify_status_changed). + */ + AcpiRemoveNotifyHandler(sc->lid_handle, ACPI_DEVICE_NOTIFY, + acpi_lid_notify_handler); + + acpi_wake_set_enable(dev, 0); + if (acpi_parse_prw(sc->lid_handle, &prw) == 0) + AcpiDisableGpe(prw.gpe_handle, prw.gpe_bit); + + return (0); +} static int acpi_lid_suspend(device_t dev) |