mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
wifi: rt2x00: avoid full teardown before work setup in probe
rt2x00lib_probe_dev() uses the full rt2x00lib_remove_dev() teardown for all probe failures. However, drv_data allocation and workqueue allocation can fail before intf_work, autowakeup_work and sleep_work have been initialized. Do not enter the full remove path until the probe has reached the point where those work items are set up. Return directly for drv_data allocation failure, and use a small early cleanup path for workqueue allocation failure. This issue was found by our static analysis tool and then confirmed by manual review of rt2x00lib_probe_dev() and rt2x00lib_remove_dev(). The early probe exits should not call a common teardown path that assumes the later work setup has already completed. A QEMU PoC forced alloc_ordered_workqueue() to fail before the work initializers are reached. The resulting fail path entered rt2x00lib_remove_dev(), and DEBUG_OBJECTS reported invalid work drains with rt2x00lib_probe_dev() and rt2x00lib_remove_dev() in the stack. Fixes:1ebbc48520("rt2x00: Introduce concept of driver data in struct rt2x00_dev.") Fixes:0439f5367c("rt2x00: Move TX/RX work into dedicated workqueue") Cc: stable@vger.kernel.org Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn> Link: https://patch.msgid.link/20260619073104.1809161-1-runyu.xiao@seu.edu.cn Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
d78a407bad
commit
536fb3d739
|
|
@ -1388,7 +1388,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
|||
GFP_KERNEL);
|
||||
if (!rt2x00dev->drv_data) {
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1422,7 +1422,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
|||
alloc_ordered_workqueue("%s", 0, wiphy_name(rt2x00dev->hw->wiphy));
|
||||
if (!rt2x00dev->workqueue) {
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
goto exit_free_drv_data;
|
||||
}
|
||||
|
||||
INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
|
||||
|
|
@ -1494,6 +1494,14 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
|||
exit:
|
||||
rt2x00lib_remove_dev(rt2x00dev);
|
||||
|
||||
return retval;
|
||||
|
||||
exit_free_drv_data:
|
||||
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
|
||||
|
||||
kfree(rt2x00dev->drv_data);
|
||||
rt2x00dev->drv_data = NULL;
|
||||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user