fr_start() arms state(hdlc)->timer when LMI is enabled (settings.lmi != LMI_NONE). The only deletion lives in fr_stop(), which is unreachable on the protocol-detach path: detach_hdlc_protocol() calls only ->detach() (never ->stop()) and then kfree()s hdlc->state. FR's ->detach, fr_destroy(), tears down the PVC list but never touches the timer, so unregistering an up FR device with LMI enabled leaves the timer armed on top of freed memory; fr_timer() then fires into the dead frad_state. Shut the timer down at the top of fr_destroy(). Use timer_shutdown_sync() so the timer cannot be re-armed afterwards, matching the CVE-2026-63803 ppp fix (ppp_timer_release()). Initialize the timer in fr_ioctl() when the protocol is attached and drop the timer_setup() from fr_start(): attach_hdlc_protocol() uses kmalloc() (not kzalloc), so state(hdlc)->timer is uninitialized garbage until the first timer_setup() and fr_destroy() must never run timer_shutdown_sync() on it. This bug was found by static analysis and confirmed with a KASAN reproducer: slab-use-after-free in the timer softirq after rmmod of an up Frame Relay HDLC device with LMI enabled. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Chengyu Liu Reviewed-by: Simon Horman --- v2: retarget to net-next and drop Cc: stable per maintainer guidance; no code change. v1: https://lore.kernel.org/netdev/ drivers/net/wan/hdlc_fr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 5f0e54ed1e..2086ff85b5 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -1009,7 +1009,6 @@ static void fr_start(struct net_device *dev) state(hdlc)->txseq = state(hdlc)->rxseq = 0; state(hdlc)->dev = dev; - timer_setup(&state(hdlc)->timer, fr_timer, 0); /* First poll after 1 s */ state(hdlc)->timer.expires = jiffies + HZ; add_timer(&state(hdlc)->timer); @@ -1153,6 +1152,9 @@ static void fr_destroy(struct net_device *frad) hdlc_device *hdlc = dev_to_hdlc(frad); struct pvc_device *pvc = state(hdlc)->first_pvc; + /* The LMI timer must not outlive the state being torn down. */ + timer_shutdown_sync(&state(hdlc)->timer); + state(hdlc)->first_pvc = NULL; /* All PVCs destroyed */ state(hdlc)->dce_pvc_count = 0; state(hdlc)->dce_changed = 1; @@ -1242,6 +1244,7 @@ static int fr_ioctl(struct net_device *dev, struct if_settings *ifs) return result; state(hdlc)->first_pvc = NULL; state(hdlc)->dce_pvc_count = 0; + timer_setup(&state(hdlc)->timer, fr_timer, 0); } memcpy(&state(hdlc)->settings, &new_settings, size); dev->type = ARPHRD_FRAD; -- 2.25.1