Received: by 2002:a05:6a10:206:0:0:0:0 with SMTP id 6csp3942707pxj; Mon, 21 Jun 2021 09:52:50 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwbxatZKbvo/rm7I1J/EijE4D7faULLtfqcqDQ+2Lj90VbqF7rBPN70mU6lZlNdtNtGM3WL X-Received: by 2002:a92:360e:: with SMTP id d14mr18601447ila.106.1624294369942; Mon, 21 Jun 2021 09:52:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1624294369; cv=none; d=google.com; s=arc-20160816; b=hQBmvqq4xXf57RHdmC8jOoIe0oZRKP3tIRTXET0+aSN/xbTJGJNXW/vkaBzvpeipLn PTYHgomGuxlnSVQH0S1V4eukmOfXY6Tf6GukTT9r3SZcmemIOr4uwmzGQqMi4X7YHA9w 9c/5iFUfF/0PERrlFWHvd6keRIPbfEnZQbKyIpsNKjKMrLJT1/EDobOQ+AeMllpiDuhr W48Y8PqYixOwASj/5wA7OnacY+N/cCWreJ2MxAXq2XMEYsKF3pzFnvAnDrJ2Se1ZeXjB +wAAnnhRoyV06x0N+5NS7/xFJn21eOw4cQtfkrEnk5RpXVefotwbWv8VbjxzppV96kDP NBdA== 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=niNrI5rJyG+L+rVIsfS2r96oI7DW04aX+i4t66fqXXA=; b=C6/hLWN+HyA5zjdR9yVhX29lk0UrbMcDA2KFHZHFC23ZFIuEk56o0+eVAyuunDTmMP nXR7j0uI+/aVHsoN/giiKQGjh5yCKFm1jxqv/pV+8a5v39OR4JVOyJ9yvtt3ot5Euch3 ayEsYUgAl5bAUet+Umnt6ClgoGBXi/JX9TQbJK0P3rphx2JKd/0txy6SE/XI3amEB03o 5Sz81uOyNZdCBgM2rXosN2TNYKxrVP36UohTCGIx/9c11a6x1GT7/5iTdhIga50CZvop b5ecGSPfTPyvSOZDTdH+SefGY+q+vterZ/tSUGdcpSap6MjQigDjcZYoWLaX/KeKhd/1 6Kyw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=FjreZfD9; 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 u12si15682519ilm.99.2021.06.21.09.52.34; Mon, 21 Jun 2021 09:52:49 -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=FjreZfD9; 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 S232381AbhFUQxx (ORCPT + 99 others); Mon, 21 Jun 2021 12:53:53 -0400 Received: from mail.kernel.org ([198.145.29.99]:41326 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233348AbhFUQtg (ORCPT ); Mon, 21 Jun 2021 12:49:36 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id A737461419; Mon, 21 Jun 2021 16:34:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1624293279; bh=C4IxMRUbKIVrX5uTAl0QTpolDOfCUCJ4h5F1AbXTluM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FjreZfD9ggvHWKXC4XCv0VSHUBruK/F3yfuK7ubdPw5cABwZhGXm/69b+GuUrxjHK 31xPKQRgUOoMWYFjVKs9eHfxyxWeFkWcaMz+rCytAE14FByQbi70EmIRSHRsCdU110 eoJJvO8Sbch8KTaxlKXHxtNuuIHZ9RDbtXrdW418= 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.12 164/178] net: bridge: fix vlan tunnel dst null pointer dereference Date: Mon, 21 Jun 2021 18:16:18 +0200 Message-Id: <20210621154928.332375869@linuxfoundation.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210621154921.212599475@linuxfoundation.org> References: <20210621154921.212599475@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 @@ -90,8 +90,8 @@ struct bridge_mcast_stats { #endif 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; } @@ -182,12 +187,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); @@ -195,7 +203,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; }