Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1aaac071 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

ACPI / hotplug / PCI: Fix NULL pointer dereference in cleanup_bridge()



After commit bbd34fcd (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: default avatarYinghai Lu <yinghai@kernel.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent d010e576
Loading
Loading
Loading
Loading
+3 −1
Original line number Original line Diff line number Diff line
@@ -340,6 +340,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,


		retval = acpiphp_register_hotplug_slot(slot, sun);
		retval = acpiphp_register_hotplug_slot(slot, sun);
		if (retval) {
		if (retval) {
			slot->slot = NULL;
			bridge->nr_slots--;
			bridge->nr_slots--;
			if (retval == -EBUSY)
			if (retval == -EBUSY)
				warn("Slot %llu already registered by another "
				warn("Slot %llu already registered by another "
@@ -429,6 +430,7 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
					err("failed to remove notify handler\n");
					err("failed to remove notify handler\n");
			}
			}
		}
		}
		if (slot->slot)
			acpiphp_unregister_hotplug_slot(slot);
			acpiphp_unregister_hotplug_slot(slot);
	}
	}