mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
amt: fix use-after-free in AMT delayed works
When an AMT device is removed, pending delayed works can still access
the freed amt_dev structure, which may result in kernel crashes or
memory corruption.
amt_dev_stop() cancels req_wq and discovery_wq with
cancel_delayed_work_sync(), but these works can be scheduled again
from event_wq after the cancellation. This allows delayed works to
access the freed amt_dev structure after the netdev has been released.
The following is a simple race scenario:
CPU0 CPU1
amt_dev_stop()
cancel_delayed_work_sync()
amt_event_work()
mod_delayed_work(req_wq)
free netdev
req_wq accesses freed amt_dev
Use disable_delayed_work_sync() in amt_dev_stop() to prevent req_wq and
discovery_wq from being queued again and wait for running work items
to complete.
The delayed works are disabled after initialization in
amt_newlink() and enabled only when the device is successfully opened.
This keeps the delayed work lifecycle synchronized with the lifetime
of the AMT device.
Fixes: cbc21dc1cf ("amt: add data plane of amt interface")
Cc: stable@vger.kernel.org
Signed-off-by: Shihuang Liu <shlomojune6@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Taehee Yoo <ap420073@gmail.com>
Link: https://patch.msgid.link/20260722113919.7723-1-shlomojune6@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
249447ff83
commit
ea20c44935
|
|
@ -3034,9 +3034,15 @@ static int amt_dev_open(struct net_device *dev)
|
|||
amt->event_idx = 0;
|
||||
amt->nr_events = 0;
|
||||
|
||||
enable_delayed_work(&amt->discovery_wq);
|
||||
enable_delayed_work(&amt->req_wq);
|
||||
|
||||
err = amt_socket_create(amt);
|
||||
if (err)
|
||||
if (err) {
|
||||
disable_delayed_work(&amt->req_wq);
|
||||
disable_delayed_work(&amt->discovery_wq);
|
||||
return err;
|
||||
}
|
||||
|
||||
amt->req_cnt = 0;
|
||||
amt->remote_ip = 0;
|
||||
|
|
@ -3062,8 +3068,8 @@ static int amt_dev_stop(struct net_device *dev)
|
|||
struct sock *sk;
|
||||
int i;
|
||||
|
||||
cancel_delayed_work_sync(&amt->req_wq);
|
||||
cancel_delayed_work_sync(&amt->discovery_wq);
|
||||
disable_delayed_work_sync(&amt->req_wq);
|
||||
disable_delayed_work_sync(&amt->discovery_wq);
|
||||
cancel_delayed_work_sync(&amt->secret_wq);
|
||||
|
||||
/* shutdown */
|
||||
|
|
@ -3317,6 +3323,8 @@ static int amt_newlink(struct net_device *dev,
|
|||
INIT_DELAYED_WORK(&amt->req_wq, amt_req_work);
|
||||
INIT_DELAYED_WORK(&amt->secret_wq, amt_secret_work);
|
||||
INIT_WORK(&amt->event_wq, amt_event_work);
|
||||
disable_delayed_work(&amt->req_wq);
|
||||
disable_delayed_work(&amt->discovery_wq);
|
||||
INIT_LIST_HEAD(&amt->tunnel_list);
|
||||
return 0;
|
||||
err:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user