Skip to content

Commit

Permalink
platform/x86: wmi: Fix driver->notify() vs ->probe() race
Browse files Browse the repository at this point in the history
The driver core sets struct device->driver before calling out
to the bus' probe() method, this leaves a window where an ACPI
notify may happen on the WMI object before the driver's
probe() method has completed running, causing e.g. the
driver's notify() callback to get called with drvdata
not yet being set leading to a NULL pointer deref.

At a check for this to the WMI core, ensuring that the notify()
callback is not called before the driver is ready.

Fixes: 1686f54 ("platform/x86: wmi: Incorporate acpi_install_notify_handler")
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20211128190031.405620-2-hdegoede@redhat.com
  • Loading branch information
Hans de Goede committed Dec 6, 2021
1 parent a90b38c commit 9918878
Showing 1 changed file with 5 additions and 1 deletion.
6 changes: 5 additions & 1 deletion drivers/platform/x86/wmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ static_assert(__alignof__(struct guid_block) == 1);

enum { /* wmi_block flags */
WMI_READ_TAKES_NO_ARGS,
WMI_PROBED,
};

struct wmi_block {
Expand Down Expand Up @@ -1008,6 +1009,7 @@ static int wmi_dev_probe(struct device *dev)
}
}

set_bit(WMI_PROBED, &wblock->flags);
return 0;

probe_misc_failure:
Expand All @@ -1025,6 +1027,8 @@ static void wmi_dev_remove(struct device *dev)
struct wmi_block *wblock = dev_to_wblock(dev);
struct wmi_driver *wdriver = drv_to_wdrv(dev->driver);

clear_bit(WMI_PROBED, &wblock->flags);

if (wdriver->filter_callback) {
misc_deregister(&wblock->char_dev);
kfree(wblock->char_dev.name);
Expand Down Expand Up @@ -1322,7 +1326,7 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event,
return;

/* If a driver is bound, then notify the driver. */
if (wblock->dev.dev.driver) {
if (test_bit(WMI_PROBED, &wblock->flags) && wblock->dev.dev.driver) {
struct wmi_driver *driver = drv_to_wdrv(wblock->dev.dev.driver);
struct acpi_buffer evdata = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_status status;
Expand Down

0 comments on commit 9918878

Please sign in to comment.