From: Rafael J. Wysocki Date: Sat, 17 Aug 2013 20:16:33 +0000 (+0200) Subject: ACPI / hotplug / PCI: Fix NULL pointer dereference in cleanup_bridge() X-Git-Tag: upstream/snapshot3+hdmi~4468^2~16^2~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1aaac07112f04068d7e2fc47bb435cfd4f9d5468;p=platform%2Fadaptation%2Frenesas_rcar%2Frenesas_kernel.git 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 Signed-off-by: Rafael J. Wysocki --- diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 05e463d..8054ddc 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, retval = acpiphp_register_hotplug_slot(slot, sun); if (retval) { + slot->slot = NULL; bridge->nr_slots--; if (retval == -EBUSY) warn("Slot %llu already registered by another " @@ -429,7 +430,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) err("failed to remove notify handler\n"); } } - acpiphp_unregister_hotplug_slot(slot); + if (slot->slot) + acpiphp_unregister_hotplug_slot(slot); } mutex_lock(&bridge_mutex);