diff options
author | Lin Ma <linma@zju.edu.cn> | 2022-08-08 06:42:24 +0300 |
---|---|---|
committer | Stefan Schmidt <stefan@datenfreihafen.org> | 2022-08-23 10:55:04 +0300 |
commit | afe7116f6d3b888778ed6d95e3cf724767b9aedf (patch) | |
tree | 6e0f6db6a892a977bcddef58ab0e12e4569a095f /drivers/net/ieee802154/adf7242.c | |
parent | 5003e52c311a2135d737ae906577c639fbaafe54 (diff) | |
download | linux-afe7116f6d3b888778ed6d95e3cf724767b9aedf.tar.xz |
ieee802154/adf7242: defer destroy_workqueue call
There is a possible race condition (use-after-free) like below
(FREE) | (USE)
adf7242_remove | adf7242_channel
cancel_delayed_work_sync |
destroy_workqueue (1) | adf7242_cmd_rx
| mod_delayed_work (2)
|
The root cause for this race is that the upper layer (ieee802154) is
unaware of this detaching event and the function adf7242_channel can
be called without any checks.
To fix this, we can add a flag write at the beginning of adf7242_remove
and add flag check in adf7242_channel. Or we can just defer the
destructive operation like other commit 3e0588c291d6 ("hamradio: defer
ax25 kfree after unregister_netdev") which let the
ieee802154_unregister_hw() to handle the synchronization. This patch
takes the second option.
Fixes: 58e9683d1475 ("net: ieee802154: adf7242: Fix OCL calibration
runs")
Signed-off-by: Lin Ma <linma@zju.edu.cn>
Acked-by: Michael Hennerich <michael.hennerich@analog.com>
Link: https://lore.kernel.org/r/20220808034224.12642-1-linma@zju.edu.cn
Signed-off-by: Stefan Schmidt <stefan@datenfreihafen.org>
Diffstat (limited to 'drivers/net/ieee802154/adf7242.c')
-rw-r--r-- | drivers/net/ieee802154/adf7242.c | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/drivers/net/ieee802154/adf7242.c b/drivers/net/ieee802154/adf7242.c index 6afdf1622944..5cf218c674a5 100644 --- a/drivers/net/ieee802154/adf7242.c +++ b/drivers/net/ieee802154/adf7242.c @@ -1310,10 +1310,11 @@ static void adf7242_remove(struct spi_device *spi) debugfs_remove_recursive(lp->debugfs_root); + ieee802154_unregister_hw(lp->hw); + cancel_delayed_work_sync(&lp->work); destroy_workqueue(lp->wqueue); - ieee802154_unregister_hw(lp->hw); mutex_destroy(&lp->bmux); ieee802154_free_hw(lp->hw); } |