Received: by 2002:a05:6a10:206:0:0:0:0 with SMTP id 6csp3921121pxj; Mon, 21 Jun 2021 09:24:35 -0700 (PDT) X-Google-Smtp-Source: ABdhPJw0Mwc97ODlTY2O1c5wnk/j5p3pQaQ2C1pXk7ZGA0JeAqLX9lBYT/1AMeqGyEkFoUlea2Jx X-Received: by 2002:a17:906:7212:: with SMTP id m18mr16437504ejk.351.1624292675541; Mon, 21 Jun 2021 09:24:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1624292675; cv=none; d=google.com; s=arc-20160816; b=DUONlJr6DoSna7sA9CdDRwgnFpWve5sPYTWqj5M0hOpjFghEylQhmiLz9fTWJ1zZJQ 7mvMOsoYTSidsLebVFhV9g7ksZj7zTnRieAwHlsR+TL/+kYzRoPi1u/3mULHTo+DGXy3 NWcnEXAwIt1WCX4NKgks2z6WOgSlfTEW8q9el3PYzrDL5q4Ibl6QZYBTU/ypAbqkCrTs w6xZYW9//2zj0vv2XtWQIn5YYoFSWmCfGseP1/HAtcLbLnu77g4NDZyR90oumw53OnaJ N4ZFdUJRXm2Kgw1MbQuBxeDeJOAFnl8PRY2yCNFaFllGMIxdBpYKwLtqjya/Wni1AxTL dVVw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=WSSXZhiaX0Jr+dZaEW3MBkQz5OtytjilAKZV5qT/m6U=; b=CeusE+DbLPoLOZMnm5EiMhKT4DtAdYYI0hJh4Ah2jQ0OPpi2RmCNTzF0SlIYCZOjer qCjw2zBxwv3mpzUh4gsZmnwy1nx0RFKNO9eaowv/iIjVQ2n++0vRLQ2LpYJ3FDkHBIEW FJ/oKB3slyufPnFrD/Xd5qk59QYvY5jNWeB0a2NC0BLCmtTd08lu/gGVJ7WhRpIE0JZ0 TxGIQGG33Bt9k+7KG/wkLPi9zKDtqKkxz0nXUPcQ+U9bKj8gwwuhyMgVFq+pXyHWwrzz R7ybLawTOdIw9A7QVoBILdFG05+8v0HaprIF9dJd2RRQR3FyVr1qfUNOYgmwLuFgEfW9 qPeg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=mzLn6FRm; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id a8si147630edm.571.2021.06.21.09.24.08; Mon, 21 Jun 2021 09:24:35 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=mzLn6FRm; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231972AbhFUQZR (ORCPT + 99 others); Mon, 21 Jun 2021 12:25:17 -0400 Received: from mail.kernel.org ([198.145.29.99]:42284 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230028AbhFUQXp (ORCPT ); Mon, 21 Jun 2021 12:23:45 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id E6CD9613B2; Mon, 21 Jun 2021 16:20:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1624292445; bh=3MoQ0jYVRL8nF01aftjWa9rRro2SU9luxytdpxcD/f4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mzLn6FRmAhD7jQuUmtmdvI8xKQMpwVEWQrH0lAT+zm3E/HO5xsSDL3oZWe+SKdxF9 6G9vRnHFYBZS5E0MB09dZazIk28iU7YJ8at6qXH0FqXh48AU9NDjsQlxxPZYEVtCb2 iJtr8YThyTXm2zcaGBcQqiIVEsqR+pqW/s7A1wDs= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Nikolay Aleksandrov , "David S. Miller" Subject: [PATCH 5.4 76/90] net: bridge: fix vlan tunnel dst null pointer dereference Date: Mon, 21 Jun 2021 18:15:51 +0200 Message-Id: <20210621154906.727395234@linuxfoundation.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210621154904.159672728@linuxfoundation.org> References: <20210621154904.159672728@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Nikolay Aleksandrov commit 58e2071742e38f29f051b709a5cca014ba51166f upstream. This patch fixes a tunnel_dst null pointer dereference due to lockless access in the tunnel egress path. When deleting a vlan tunnel the tunnel_dst pointer is set to NULL without waiting a grace period (i.e. while it's still usable) and packets egressing are dereferencing it without checking. Use READ/WRITE_ONCE to annotate the lockless use of tunnel_id, use RCU for accessing tunnel_dst and make sure it is read only once and checked in the egress path. The dst is already properly RCU protected so we don't need to do anything fancy than to make sure tunnel_id and tunnel_dst are read only once and checked in the egress path. Cc: stable@vger.kernel.org Fixes: 11538d039ac6 ("bridge: vlan dst_metadata hooks in ingress and egress paths") Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/bridge/br_private.h | 4 ++-- net/bridge/br_vlan_tunnel.c | 38 ++++++++++++++++++++++++-------------- 2 files changed, 26 insertions(+), 16 deletions(-) --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -96,8 +96,8 @@ struct br_vlan_stats { }; struct br_tunnel_info { - __be64 tunnel_id; - struct metadata_dst *tunnel_dst; + __be64 tunnel_id; + struct metadata_dst __rcu *tunnel_dst; }; /* private vlan flags */ --- a/net/bridge/br_vlan_tunnel.c +++ b/net/bridge/br_vlan_tunnel.c @@ -41,26 +41,33 @@ static struct net_bridge_vlan *br_vlan_t br_vlan_tunnel_rht_params); } +static void vlan_tunnel_info_release(struct net_bridge_vlan *vlan) +{ + struct metadata_dst *tdst = rtnl_dereference(vlan->tinfo.tunnel_dst); + + WRITE_ONCE(vlan->tinfo.tunnel_id, 0); + RCU_INIT_POINTER(vlan->tinfo.tunnel_dst, NULL); + dst_release(&tdst->dst); +} + void vlan_tunnel_info_del(struct net_bridge_vlan_group *vg, struct net_bridge_vlan *vlan) { - if (!vlan->tinfo.tunnel_dst) + if (!rcu_access_pointer(vlan->tinfo.tunnel_dst)) return; rhashtable_remove_fast(&vg->tunnel_hash, &vlan->tnode, br_vlan_tunnel_rht_params); - vlan->tinfo.tunnel_id = 0; - dst_release(&vlan->tinfo.tunnel_dst->dst); - vlan->tinfo.tunnel_dst = NULL; + vlan_tunnel_info_release(vlan); } static int __vlan_tunnel_info_add(struct net_bridge_vlan_group *vg, struct net_bridge_vlan *vlan, u32 tun_id) { - struct metadata_dst *metadata = NULL; + struct metadata_dst *metadata = rtnl_dereference(vlan->tinfo.tunnel_dst); __be64 key = key32_to_tunnel_id(cpu_to_be32(tun_id)); int err; - if (vlan->tinfo.tunnel_dst) + if (metadata) return -EEXIST; metadata = __ip_tun_set_dst(0, 0, 0, 0, 0, TUNNEL_KEY, @@ -69,8 +76,8 @@ static int __vlan_tunnel_info_add(struct return -EINVAL; metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_BRIDGE; - vlan->tinfo.tunnel_dst = metadata; - vlan->tinfo.tunnel_id = key; + rcu_assign_pointer(vlan->tinfo.tunnel_dst, metadata); + WRITE_ONCE(vlan->tinfo.tunnel_id, key); err = rhashtable_lookup_insert_fast(&vg->tunnel_hash, &vlan->tnode, br_vlan_tunnel_rht_params); @@ -79,9 +86,7 @@ static int __vlan_tunnel_info_add(struct return 0; out: - dst_release(&vlan->tinfo.tunnel_dst->dst); - vlan->tinfo.tunnel_dst = NULL; - vlan->tinfo.tunnel_id = 0; + vlan_tunnel_info_release(vlan); return err; } @@ -181,12 +186,15 @@ int br_handle_ingress_vlan_tunnel(struct int br_handle_egress_vlan_tunnel(struct sk_buff *skb, struct net_bridge_vlan *vlan) { + struct metadata_dst *tunnel_dst; + __be64 tunnel_id; int err; - if (!vlan || !vlan->tinfo.tunnel_id) + if (!vlan) return 0; - if (unlikely(!skb_vlan_tag_present(skb))) + tunnel_id = READ_ONCE(vlan->tinfo.tunnel_id); + if (!tunnel_id || unlikely(!skb_vlan_tag_present(skb))) return 0; skb_dst_drop(skb); @@ -194,7 +202,9 @@ int br_handle_egress_vlan_tunnel(struct if (err) return err; - skb_dst_set(skb, dst_clone(&vlan->tinfo.tunnel_dst->dst)); + tunnel_dst = rcu_dereference(vlan->tinfo.tunnel_dst); + if (tunnel_dst) + skb_dst_set(skb, dst_clone(&tunnel_dst->dst)); return 0; }