From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E6908358D28; Wed, 3 Dec 2025 16:36:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764779767; cv=none; b=jO88qWf4kb18kbDR9iJJR3144Se2DqX9CjKzh0nLo8KBpE5D4SqzR3glbe9IQikPV1TPcIBJINXniYBVyWZMEx3J2ii066Bb6XAq3Ao0W91dQUdH3rzk6GNXdCLuWhzNZRxb3zpWefjkjigVluVeTRKukMvY03P5OM6/FJsyQ2o= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764779767; c=relaxed/simple; bh=QK3zbrewV6goQJ/5nr5s0Lt9EZPLTn1xXJqybqceBls=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=F1XXs1Hb3jrJYhOnh6E+j2ZgShD2R7Dr58W+E7DFSeVfz5BpA0WhxIC5La/DEjVtkuEk24tt+KZ0wY1XEhXMDelCuQZ1MkqgqlI6Ry0EUnSQPn3B27pIAYflsHp4Gz53XnAP10qtkm1BvrTy26zaqJOHA+83GUyapApz0J+kmbg= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=a2hj2A8g; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b="a2hj2A8g" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E67C4C4CEF5; Wed, 3 Dec 2025 16:36:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1764779765; bh=QK3zbrewV6goQJ/5nr5s0Lt9EZPLTn1xXJqybqceBls=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=a2hj2A8gBoZ6vzoB/KB6lltr9aE6YDlFIqJ7soRL2Bh3VMjTUUMGPjDyf3sXzONEK hC9gqc6F24rJ75M/bAy8PAQFMcotoOWbxndgpeTbGaOrVOvdxaEWoyLI81oWQr4f4X aqs+vjiDt6oSoPdKda+lrr8TlpunrJP/BHil/BKY= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, syzbot+dd280197f0f7ab3917be@syzkaller.appspotmail.com, Nikolay Aleksandrov , Ido Schimmel , Jakub Kicinski , Sasha Levin Subject: [PATCH 6.1 322/568] net: bridge: fix use-after-free due to MST port state bypass Date: Wed, 3 Dec 2025 16:25:24 +0100 Message-ID: <20251203152452.506500538@linuxfoundation.org> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20251203152440.645416925@linuxfoundation.org> References: <20251203152440.645416925@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 6.1-stable review patch. If anyone has any objections, please let me know. ------------------ From: Nikolay Aleksandrov [ Upstream commit 8dca36978aa80bab9d4da130c211db75c9e00048 ] syzbot reported[1] a use-after-free when deleting an expired fdb. It is due to a race condition between learning still happening and a port being deleted, after all its fdbs have been flushed. The port's state has been toggled to disabled so no learning should happen at that time, but if we have MST enabled, it will bypass the port's state, that together with VLAN filtering disabled can lead to fdb learning at a time when it shouldn't happen while the port is being deleted. VLAN filtering must be disabled because we flush the port VLANs when it's being deleted which will stop learning. This fix adds a check for the port's vlan group which is initialized to NULL when the port is getting deleted, that avoids the port state bypass. When MST is enabled there would be a minimal new overhead in the fast-path because the port's vlan group pointer is cache-hot. [1] https://syzkaller.appspot.com/bug?extid=dd280197f0f7ab3917be Fixes: ec7328b59176 ("net: bridge: mst: Multiple Spanning Tree (MST) mode") Reported-by: syzbot+dd280197f0f7ab3917be@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/69088ffa.050a0220.29fc44.003d.GAE@google.com/ Signed-off-by: Nikolay Aleksandrov Reviewed-by: Ido Schimmel Link: https://patch.msgid.link/20251105111919.1499702-2-razor@blackwall.org Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/bridge/br_forward.c | 2 +- net/bridge/br_input.c | 4 ++-- net/bridge/br_private.h | 8 +++++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index d3257c9bfa920..9a6a6c1c4ced3 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -25,7 +25,7 @@ static inline int should_deliver(const struct net_bridge_port *p, vg = nbp_vlan_group_rcu(p); return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) && - (br_mst_is_enabled(p->br) || p->state == BR_STATE_FORWARDING) && + (br_mst_is_enabled(p) || p->state == BR_STATE_FORWARDING) && br_allowed_egress(vg, skb) && nbp_switchdev_allowed_egress(p, skb) && !br_skb_isolated(p, skb); } diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index b94a1783902ea..f11345720c275 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -93,7 +93,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb br = p->br; - if (br_mst_is_enabled(br)) { + if (br_mst_is_enabled(p)) { state = BR_STATE_FORWARDING; } else { if (p->state == BR_STATE_DISABLED) @@ -393,7 +393,7 @@ static rx_handler_result_t br_handle_frame(struct sk_buff **pskb) return RX_HANDLER_PASS; forward: - if (br_mst_is_enabled(p->br)) + if (br_mst_is_enabled(p)) goto defer_stp_filtering; switch (p->state) { diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 20c96cb406d5a..372e9664b2cb8 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -1802,10 +1802,12 @@ static inline bool br_vlan_state_allowed(u8 state, bool learn_allow) /* br_mst.c */ #ifdef CONFIG_BRIDGE_VLAN_FILTERING DECLARE_STATIC_KEY_FALSE(br_mst_used); -static inline bool br_mst_is_enabled(struct net_bridge *br) +static inline bool br_mst_is_enabled(const struct net_bridge_port *p) { + /* check the port's vlan group to avoid racing with port deletion */ return static_branch_unlikely(&br_mst_used) && - br_opt_get(br, BROPT_MST_ENABLED); + br_opt_get(p->br, BROPT_MST_ENABLED) && + rcu_access_pointer(p->vlgrp); } int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state, @@ -1820,7 +1822,7 @@ int br_mst_fill_info(struct sk_buff *skb, int br_mst_process(struct net_bridge_port *p, const struct nlattr *mst_attr, struct netlink_ext_ack *extack); #else -static inline bool br_mst_is_enabled(struct net_bridge *br) +static inline bool br_mst_is_enabled(const struct net_bridge_port *p) { return false; } -- 2.51.0