⬢ DragonFlyBSD Kernel Audit
DF-5150 / fix.diff
← back to finding ↓ download raw
--- 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)