6.12-stable review patch. If anyone has any objections, please let me know. ------------------ From: Bernard Pidoux ax25_rcv() creates a connection on an incoming SABM, for a listening socket or for a callsign registered by ROSE or NET/ROM. Like the ones made by ax25_send_frame(), it holds no reference on the ax25_dev and relies on ax25_kill_by_device() to detach it before the ax25_dev is freed. If it is added to ax25_list after ax25_kill_by_device() has walked the list, it is left pointing to a freed ax25_dev. ax25_rcv() is called from the packet type handler, under rcu_read_lock(), and ax25_kill_by_device() now clears device_up and waits for the RCU readers before its walk. Drop the frame when device_up is clear: a frame that gets past the test is fully processed before the walk starts, and none is processed behind it. The window is much smaller than for ax25_send_frame(): the core already drops what is received on a device that is no longer running, so only a frame that was queued before the device was stopped and is processed late can hit it. I could not exercise it. The change was checked for regressions only: incoming connections still work in the ROSE tests of the previous patch, where every AX.25 link is opened by an incoming SABM on one side. Signed-off-by: Bernard Pidoux Assisted-by: Claude:claude-opus-5-5 (cherry picked from commit 748551f72b27325043eafe969311b15ae1eb0c7c) Signed-off-by: Sasha Levin --- net/ax25/af_ax25.c | 12 ++++++------ net/ax25/ax25_in.c | 9 +++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 11ac6c83b1442..95224600b5a13 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -84,12 +84,12 @@ static void ax25_kill_by_device(struct net_device *dev) WRITE_ONCE(ax25_dev->device_up, false); /* - * ax25_send_frame() creates connections that hold no reference on - * the ax25_dev: they rely on the walk below to detach them before the - * ax25_dev is freed. It runs under rcu_read_lock() and gives up when - * device_up is clear, so once this returns every connection it was - * setting up is complete and on the list, and no new one can appear - * behind the walk. + * ax25_send_frame() and ax25_rcv() create connections that hold no + * reference on the ax25_dev: they rely on the walk below to detach + * them before the ax25_dev is freed. Both run under rcu_read_lock() + * and give up when device_up is clear, so once this returns every + * connection they were setting up is complete and on the list, and + * no new one can appear behind the walk. */ synchronize_rcu(); diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index 18e15c3c26e46..c81bc8c4563b5 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -216,6 +216,15 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, if (skb_linearize(skb)) goto free; + /* + * A connection made below on an incoming SABM holds no reference on + * the ax25_dev either. We are called under rcu_read_lock(), which + * ax25_kill_by_device() waits for after it has cleared device_up: + * leave a device that is going down alone. + */ + if (!READ_ONCE(ax25_dev->device_up)) + goto free; + /* * Parse the address header. */ -- 2.53.0