aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-08-17 16:16:33 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-08-17 16:16:33 -0400
commit1aaac07112f04068d7e2fc47bb435cfd4f9d5468 (patch)
tree86340f467111ac68148ba3f32ae88213bbfd8cae /drivers/pci/hotplug
parentd010e5769a5ab2ae8d2bcb36e77b98172c24d80c (diff)
ACPI / hotplug / PCI: Fix NULL pointer dereference in cleanup_bridge()
After commit bbd34fc (ACPI / hotplug / PCI: Register all devices under the given bridge) register_slot() is called for all PCI devices under a given bridge that have corresponding objects in the ACPI namespace, but it calls acpiphp_register_hotplug_slot() only for devices satisfying specific criteria. Still, cleanup_bridge() calls acpiphp_unregister_hotplug_slot() for all objects created by register_slot(), although it should only call it for the ones that acpiphp_register_hotplug_slot() has been called for (successfully). This causes a NULL pointer to be dereferenced by the acpiphp_unregister_hotplug_slot() executed by cleanup_bridge() if the object it is called for has not been passed to acpiphp_register_hotplug_slot(). To fix this problem, check if the 'slot' field of the object passed to acpiphp_unregister_hotplug_slot() in cleanup_bridge() is not NULL, which only is the case if acpiphp_register_hotplug_slot() has been executed for that object. In addition to that, make register_slot() reset the 'slot' field to NULL if acpiphp_register_hotplug_slot() has failed for the given object to prevent stale pointers from being used by acpiphp_unregister_hotplug_slot(). Reported-and-tested-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/pci/hotplug')
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 05e463db11de..8054ddcdaed0 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -340,6 +340,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
340 340
341 retval = acpiphp_register_hotplug_slot(slot, sun); 341 retval = acpiphp_register_hotplug_slot(slot, sun);
342 if (retval) { 342 if (retval) {
343 slot->slot = NULL;
343 bridge->nr_slots--; 344 bridge->nr_slots--;
344 if (retval == -EBUSY) 345 if (retval == -EBUSY)
345 warn("Slot %llu already registered by another " 346 warn("Slot %llu already registered by another "
@@ -429,7 +430,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
429 err("failed to remove notify handler\n"); 430 err("failed to remove notify handler\n");
430 } 431 }
431 } 432 }
432 acpiphp_unregister_hotplug_slot(slot); 433 if (slot->slot)
434 acpiphp_unregister_hotplug_slot(slot);
433 } 435 }
434 436
435 mutex_lock(&bridge_mutex); 437 mutex_lock(&bridge_mutex);