Skip to content

Commit a46bfa0

Browse files
Shihuang Liugregkh
authored andcommitted
amt: fix use-after-free in AMT delayed works
commit ea20c44 upstream. 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: cbc21dc ("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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent d3dc888 commit a46bfa0

1 file changed

Lines changed: 11 additions & 3 deletions

File tree

drivers/net/amt.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3029,9 +3029,15 @@ static int amt_dev_open(struct net_device *dev)
30293029
amt->event_idx = 0;
30303030
amt->nr_events = 0;
30313031

3032+
enable_delayed_work(&amt->discovery_wq);
3033+
enable_delayed_work(&amt->req_wq);
3034+
30323035
err = amt_socket_create(amt);
3033-
if (err)
3036+
if (err) {
3037+
disable_delayed_work(&amt->req_wq);
3038+
disable_delayed_work(&amt->discovery_wq);
30343039
return err;
3040+
}
30353041

30363042
amt->req_cnt = 0;
30373043
amt->remote_ip = 0;
@@ -3057,8 +3063,8 @@ static int amt_dev_stop(struct net_device *dev)
30573063
struct sk_buff *skb;
30583064
int i;
30593065

3060-
cancel_delayed_work_sync(&amt->req_wq);
3061-
cancel_delayed_work_sync(&amt->discovery_wq);
3066+
disable_delayed_work_sync(&amt->req_wq);
3067+
disable_delayed_work_sync(&amt->discovery_wq);
30623068
cancel_delayed_work_sync(&amt->secret_wq);
30633069

30643070
/* shutdown */
@@ -3313,6 +3319,8 @@ static int amt_newlink(struct net *net, struct net_device *dev,
33133319
INIT_DELAYED_WORK(&amt->req_wq, amt_req_work);
33143320
INIT_DELAYED_WORK(&amt->secret_wq, amt_secret_work);
33153321
INIT_WORK(&amt->event_wq, amt_event_work);
3322+
disable_delayed_work(&amt->req_wq);
3323+
disable_delayed_work(&amt->discovery_wq);
33163324
INIT_LIST_HEAD(&amt->tunnel_list);
33173325
return 0;
33183326
err:

0 commit comments

Comments
 (0)