+++ /dev/null
-From c78a4e41ab5ead6193ad8a2dd92e8906bae659fa Mon Sep 17 00:00:00 2001
-From: Fan Wu <fanwu01@zju.edu.cn>
-Date: Wed, 17 Jun 2026 02:05:18 +0000
-Subject: hdlc_ppp: sync per-proto timers before freeing hdlc state
-
-From: Fan Wu <fanwu01@zju.edu.cn>
-
-commit c78a4e41ab5ead6193ad8a2dd92e8906bae659fa upstream.
-
-Each PPP control protocol (LCP/IPCP/IPV6CP) embedded in struct ppp
-registers a timer via timer_setup(). That struct ppp is the
-hdlc->state allocation, which detach_hdlc_protocol() frees with kfree()
-in both teardown paths: unregister_hdlc_device() and the re-attach inside
-attach_hdlc_protocol().
-
-The ppp proto never registered a .detach callback, so
-detach_hdlc_protocol() performs no timer synchronization before the
-kfree(). The only cancel, timer_delete(&proto->timer) in ppp_cp_event(),
-is partial (it does not wait for a running callback) and only runs on the
-->CLOSED transition; ppp_stop()/ppp_close() do not sync either. A
-ppp_timer callback already executing (blocked on ppp->lock) survives the
-kfree and then dereferences proto->state / ppp->lock in freed memory,
-leading to a use-after-free.
-
-Fix this by adding a .detach helper that calls timer_shutdown_sync() on
-every per-proto timer. detach_hdlc_protocol() invokes proto->detach(dev)
-before kfree(hdlc->state), so timer_shutdown_sync()
-now runs on both free paths.
-timer_shutdown_sync() is used instead of timer_delete_sync() because the
-keepalive path re-arms the timer through add_timer()/mod_timer() and
-shutdown blocks any re-activation during teardown.
-
-Initialize the per-protocol timers in ppp_ioctl() when the protocol is
-attached, and remove the now-redundant timer_setup() from ppp_start(), so
-that the timers are initialized exactly once at attach time and
-ppp_timer_release() never operates on uninitialized timer_list
-structures. attach_hdlc_protocol() uses kmalloc() (not kzalloc), so
-struct ppp's protos[i].timer is uninitialized garbage until the first
-timer_setup(); without this init-at-attach, attaching the PPP protocol
-without ever bringing the device up would leave timer_shutdown_sync()
-operating on uninitialized memory in .detach. Moving the init out of
-ppp_start() (which only runs on NETDEV_UP) into the attach path makes the
-initialization unconditional and avoids initializing the same timer_list
-twice.
-
-This bug was found by static analysis.
-
-Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
-Cc: stable@vger.kernel.org
-Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
-Link: https://patch.msgid.link/20260617020518.116319-1-fanwu01@zju.edu.cn
-Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- drivers/net/wan/hdlc_ppp.c | 15 +++++++++++++--
- 1 file changed, 13 insertions(+), 2 deletions(-)
-
---- a/drivers/net/wan/hdlc_ppp.c
-+++ b/drivers/net/wan/hdlc_ppp.c
-@@ -624,7 +624,6 @@ static void ppp_start(struct net_device
- for (i = 0; i < IDX_COUNT; i++) {
- struct proto *proto = &ppp->protos[i];
- proto->dev = dev;
-- timer_setup(&proto->timer, ppp_timer, 0);
- proto->state = CLOSED;
- }
- ppp->protos[IDX_LCP].pid = PID_LCP;
-@@ -644,6 +643,15 @@ static void ppp_close(struct net_device
- ppp_tx_flush();
- }
-
-+static void ppp_timer_release(struct net_device *dev)
-+{
-+ struct ppp *ppp = get_ppp(dev);
-+ int i;
-+
-+ for (i = 0; i < IDX_COUNT; i++)
-+ timer_shutdown_sync(&ppp->protos[i].timer);
-+}
-+
- static struct hdlc_proto proto = {
- .start = ppp_start,
- .stop = ppp_stop,
-@@ -652,6 +660,7 @@ static struct hdlc_proto proto = {
- .ioctl = ppp_ioctl,
- .netif_rx = ppp_rx,
- .module = THIS_MODULE,
-+ .detach = ppp_timer_release,
- };
-
- static const struct header_ops ppp_header_ops = {
-@@ -662,7 +671,7 @@ static int ppp_ioctl(struct net_device *
- {
- hdlc_device *hdlc = dev_to_hdlc(dev);
- struct ppp *ppp;
-- int result;
-+ int i, result;
-
- switch (ifr->ifr_settings.type) {
- case IF_GET_PROTO:
-@@ -689,6 +698,8 @@ static int ppp_ioctl(struct net_device *
- return result;
-
- ppp = get_ppp(dev);
-+ for (i = 0; i < IDX_COUNT; i++)
-+ timer_setup(&ppp->protos[i].timer, ppp_timer, 0);
- spin_lock_init(&ppp->lock);
- ppp->req_timeout = 2;
- ppp->cr_retries = 10;