mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
s390/ctcm: Fix use-after-free in channel_remove()
channel_remove() uses fsm_deltimer() which calls timer_delete(),
returning immediately even if the timer callback is running on
another CPU. This leaves a window where fsm_expire_timer() accesses
ch->fsm after kfree_fsm().
For MPC channels the teardown has a circular dependency:
ch->timer callback -> ctcm_chx_txretry() -> mpc_action_go_inop()
-> tasklet_hi_schedule(&ch->ch_disc_tasklet)
ch_tasklet -> ctcmpc_send_sweep_resp() -> fsm_addtimer(&ch->sweep_timer)
sweep_timer callback -> fsm_addtimer(&ch->timer)
Use timer_shutdown_sync() for both timers: it waits for any running
callback and permanently prevents rearming. Shut down sweep_timer
first (its callback rearms ch->timer at ctcm_fsms.c), then
ch->timer. Only then call tasklet_kill() -- catching any tasklet
scheduled by an in-flight callback before shutdown.
kfree(ch->discontact_th) follows tasklet_kill(ch_disc_tasklet) since
ch->ccw[15].cda points to discontact_th and
mpc_action_send_discontact() starts I/O through ch->ccw[15].
timer_shutdown_sync() is also used for non-MPC ch->timer:
ctcm_chx_txretry() (CTC_STATE_TX + CTC_EVENT_TIMER) calls
fsm_addtimer(&ch->timer) on both paths.
Depends on "s390/ctcm: Fix timer corruption in fsm_addtimer()" which
replaces add_timer() with mod_timer(). mod_timer() on a shut-down
timer is discarded; without it fsm_addtimer() calls timer_setup()
defeating timer_shutdown_sync(). Backporting without that
prerequisite is unsafe.
Cc: stable+noautosel@kernel.org # fix for a driver (de)init path race
Fixes: 293d984f0e ("ctcm: infrastructure for replaced ctc driver")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://sashiko.dev/#/patchset/20260922101913.239103-1-nagamani@linux.ibm.com?part=2
Signed-off-by: Nagamani PV <nagamani@linux.ibm.com>
Reviewed-by: Aswin Karuvally <aswin@linux.ibm.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260930070234.569500-3-nagamani@linux.ibm.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
10c339aff2
commit
65629387fd
|
|
@ -211,9 +211,14 @@ static void channel_remove(struct channel *ch)
|
|||
while (*c) {
|
||||
if (*c == ch) {
|
||||
*c = ch->next;
|
||||
fsm_deltimer(&ch->timer);
|
||||
if (IS_MPC(ch))
|
||||
fsm_deltimer(&ch->sweep_timer);
|
||||
timer_shutdown_sync(&ch->sweep_timer.tl);
|
||||
timer_shutdown_sync(&ch->timer.tl);
|
||||
if (IS_MPC(ch)) {
|
||||
tasklet_kill(&ch->ch_tasklet);
|
||||
tasklet_kill(&ch->ch_disc_tasklet);
|
||||
kfree(ch->discontact_th);
|
||||
}
|
||||
|
||||
kfree_fsm(ch->fsm);
|
||||
clear_normalized_cda(&ch->ccw[4]);
|
||||
|
|
@ -221,11 +226,6 @@ static void channel_remove(struct channel *ch)
|
|||
clear_normalized_cda(&ch->ccw[1]);
|
||||
dev_kfree_skb_any(ch->trans_skb);
|
||||
}
|
||||
if (IS_MPC(ch)) {
|
||||
tasklet_kill(&ch->ch_tasklet);
|
||||
tasklet_kill(&ch->ch_disc_tasklet);
|
||||
kfree(ch->discontact_th);
|
||||
}
|
||||
kfree(ch->ccw);
|
||||
kfree(ch->irb);
|
||||
kfree(ch);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user