[BUG] PCI: shpchp: Potential use-after-free in cleanup_slots() due to missing synchronization

From: 马云龙

Date: Sun Mar 08 2026 - 23:18:09 EST


Hi,

We found a potential use-after-free bug in the shpchp driver through
static analysis.

Summary
-------

In cleanup_slots() (drivers/pci/hotplug/shpchp_core.c), the function
uses cancel_delayed_work() instead of cancel_delayed_work_sync() before
destroying the workqueue and freeing the slot structure. This can lead
to use-after-free if the delayed work is currently executing.

Analysis
--------

cancel_delayed_work() is non-synchronous - it only cancels pending work
that has not yet started execution. If the delayed work is already
running, cancel_delayed_work() returns false and the work continues to
execute.

The vulnerable code path:

void cleanup_slots(struct controller *ctrl)
{
struct slot *slot, *next;

list_for_each_entry_safe(slot, next, &ctrl->slot_list, slot_list) {
list_del(&slot->slot_list);
cancel_delayed_work(&slot->work); // non-sync cancel
destroy_workqueue(slot->wq); // workqueue destroyed
pci_hp_deregister(&slot->hotplug_slot);
kfree(slot); // slot freed
}
}

The delayed work function shpchp_queue_pushbutton_work() (shpchp_ctrl.c)
performs the following operations that can race with cleanup:

- mutex_lock(&p_slot->lock)
- queue_work(p_slot->wq, &info->work)
- mutex_unlock(&p_slot->lock)

Race Scenario
-------------

CPU0 (driver unload) CPU1 (delayed work)
==================== ====================
shpchp_queue_pushbutton_work()
mutex_lock(&p_slot->lock)
cleanup_slots()
cancel_delayed_work() // returns false, work running
destroy_workqueue(slot->wq) // workqueue destroyed
queue_work(p_slot->wq, ...) // UAF!
kfree(slot) mutex_unlock(&p_slot->lock) // UAF!

Trigger Condition
-----------------

1. User presses the PCI hotplug attention button
2. handle_button_press_event() queues a 5-second delayed work
3. Within 5 seconds, driver is unloaded or device is removed
4. cleanup_slots() races with the executing delayed work

Impact
------

- Kernel crash/panic
- Potential privilege escalation if freed memory is reallocated

Reference
---------

The similar pciehp driver correctly uses cancel_delayed_work_sync() in
pciehp_release_ctrl() (drivers/pci/hotplug/pciehp_hpc.c:1098) for the
same pattern.

Suggested Fix
-------------

Replace cancel_delayed_work() with cancel_delayed_work_sync():

- cancel_delayed_work(&slot->work);
+ cancel_delayed_work_sync(&slot->work);

Detection Information
---------------------

- Tool: ConCord (static analysis framework for concurrency bugs)
- Kernel Version: v7.0-rc2 (commit 0031c06807cf)
- Pattern: Delayed work teardown without synchronization
- Confidence: High

Thanks,
Yunlong Ma