Received: by 2002:a05:6a10:f3d0:0:0:0:0 with SMTP id a16csp3814277pxv; Mon, 28 Jun 2021 13:36:38 -0700 (PDT) X-Google-Smtp-Source: ABdhPJw7anWbgP6YJke/9bFz/OMvuTuBqcRxz/Eg0gjkB5Dgcyv9gXUPf3WmeYaMFIGXc692sna0 X-Received: by 2002:a92:da44:: with SMTP id p4mr18205643ilq.39.1624912598347; Mon, 28 Jun 2021 13:36:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1624912598; cv=none; d=google.com; s=arc-20160816; b=tx3N+asZ71YEkIiNivQTgocrfVBRH6bZ1jaFluIsByRgifPUkPlAc1j00pZJKClpyB 37BY1HTAassGRaCPmyF+FM/FKb7MbXHHugu0xnIiBBmVQ/qIgEAdkKOYtP4RlVD2S82H 5GVpwvD5dXlhxDwhfWSHEftUHrVIrvAmE1w6LT5B25+HyRKslmze+2vYhp3qp+vvVaJP H9RpM5QaIB72l0lAIEstgk7U7Q9G2PGb/WgNLdtnn6xVvuF1hNjtbSAxkvXIeXQzWqVM mOp6FzKLIPoOwxb/lpqPhLZnPoYbuioHq/p3P25ZakWGK6L/wdwRfRaa6f6QSQl1Wurw 8Phg== 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 :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=cH5XC7SSBMyi8GWoaSHoES3kCSCpoMvRNa2rs5OKILY=; b=v8PRszEp1WgI1MKJ+dElZjuDbJDiTNKAAdHSh2Nc5NrdPy9eG4CfsoohIVrSxFTtWp y4+zR8IowaXVBcc68jIXta9wghW8UPpoh1+++FBiCAY/XwiiC62151JGZdW/ZnZnlbbc bS4NYW5GRGQLNB1sEsZZIbftdxHrdTlv3VWBGANsPLwFKJDq21GJBkUDbjSOVNPiuacm C+98aLxLD/3NN4b3ENak53/Lo1Scjt+FaHxAWGj3IITn1YE/kS46NWZcrvy6z7iCz0oY IGFqQV2IHZxEegYFug78ARchVOMBu/rIX3xZazkFi0+On8K81vhDXUQv/DWwL1WBvV2+ LiUg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=EBfw7rzz; 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=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id z7si2464566jap.105.2021.06.28.13.36.26; Mon, 28 Jun 2021 13:36:38 -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=@kernel.org header.s=k20201202 header.b=EBfw7rzz; 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=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235149AbhF1PN5 (ORCPT + 99 others); Mon, 28 Jun 2021 11:13:57 -0400 Received: from mail.kernel.org ([198.145.29.99]:55958 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232644AbhF1Owz (ORCPT ); Mon, 28 Jun 2021 10:52:55 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 3B3E661D32; Mon, 28 Jun 2021 14:37:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1624891037; bh=6eGUlXJ0zTfZv83a75Wr/75CS0zZoR2gC7cf6oeZV9E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EBfw7rzz8JQTKzjXBnwfO6rMHf6XQ2TLN1DHZNvWpN8W9cfAMUY01yRaiUfsRwPaq odWVExGPdLDz7vaaQFDOYXP9mLY5D46LywxgEwNgaog+HJcNZWQ0Q7Mm705ojBbvgm yyekgv+0k7TBPziSMbqKI5Q+4ADHvWUx26QpPvwVSBHAl3jwUED9alr86D3nmeOgBz m9HVOixedirckyskwszEC2lPcnwPYrzyUcOD2Nuwrss9tyzcT03tOSAM6csO35fzT/ IrePbXc5lHcIooMBxLv6riNqnCTq6Th6OvaRrnPdRt5FnrEdhs1CZ10li9Y8reEZ/1 l8avvpl4om0Xg== From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Nikolay Aleksandrov , "David S . Miller" , Greg Kroah-Hartman Subject: [PATCH 4.14 55/88] net: bridge: fix vlan tunnel dst null pointer dereference Date: Mon, 28 Jun 2021 10:35:55 -0400 Message-Id: <20210628143628.33342-56-sashal@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210628143628.33342-1-sashal@kernel.org> References: <20210628143628.33342-1-sashal@kernel.org> MIME-Version: 1.0 X-KernelTest-Patch: http://kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.14.238-rc1.gz X-KernelTest-Tree: git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git X-KernelTest-Branch: linux-4.14.y X-KernelTest-Patches: git://git.kernel.org/pub/scm/linux/kernel/git/stable/stable-queue.git X-KernelTest-Version: 4.14.238-rc1 X-KernelTest-Deadline: 2021-06-30T14:36+00:00 X-stable: review X-Patchwork-Hint: Ignore 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(-) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 14ff034e561c..50a55553a25c 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -93,8 +93,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; }; /** diff --git a/net/bridge/br_vlan_tunnel.c b/net/bridge/br_vlan_tunnel.c index 6d2c4eed2dc8..4d5100677c68 100644 --- a/net/bridge/br_vlan_tunnel.c +++ b/net/bridge/br_vlan_tunnel.c @@ -46,26 +46,33 @@ static struct net_bridge_vlan *br_vlan_tunnel_lookup(struct rhashtable *tbl, 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, @@ -74,8 +81,8 @@ static int __vlan_tunnel_info_add(struct net_bridge_vlan_group *vg, 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); @@ -84,9 +91,7 @@ static int __vlan_tunnel_info_add(struct net_bridge_vlan_group *vg, 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; } @@ -186,12 +191,15 @@ int br_handle_ingress_vlan_tunnel(struct sk_buff *skb, 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); @@ -199,7 +207,9 @@ int br_handle_egress_vlan_tunnel(struct sk_buff *skb, 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; } -- 2.30.2