Received: by 2002:a05:6602:18e:0:0:0:0 with SMTP id m14csp4546914ioo; Tue, 31 May 2022 06:51:44 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwMsEqXmLLWmJBGh2GVxsW4EmC8ehRU9GJV21JOB/mZ8wNKTH4yahr1blQHF4DwJxQUflOX X-Received: by 2002:a17:906:5d16:b0:6fe:b420:5e9d with SMTP id g22-20020a1709065d1600b006feb4205e9dmr45771335ejt.254.1654005103769; Tue, 31 May 2022 06:51:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1654005103; cv=none; d=google.com; s=arc-20160816; b=zoiCUK+NoCXt9H85co/5fsmQiHMjmv8U9GvD9b/vtgMVUOPBZ9itCcVVOGy2taaGlu EonaUXK/RO8UBJfLZSBkk0gWtTv5wfqBOsnRWywaXYJQKRwIxw9uJQa+1Va0xs+OPKmI K+mqeUUBycKAoq470jRIylkI7bM7KdSITd/CZhDeitqht1/QqWKaUcyEVqMSe9RS0bJp 8W2zV49ptwXxIO9HXWbea5Pa9NKeo/LQ/10+GUOGZsbnaZELfXG06qbQqFHvq3Sm3+P/ 3mGFOuIuIJUr4c86z0mGS1YOyg1zBwLIpPwGjqakbKHx0lHI9Wo/j4yB7uWtIrPwXp2Z PQZw== 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=TCNpOIqu8zefhyAdk53izqtLva6D6Pzo/Qt2BofcwLU=; b=dr3YjasOfLidO+iMa9aeubMd0TKuNxrwRHzsPgKvfhkMm2zPPunZ0ryrkza+Mdrrkj lu+1fIV2JEILS9YtWnELpmfblt1MJVkYA1j0EKJ14G55M5wobX4GoG0sRqs7y8BY8Qiy gcHI7gnJsCEA+p71rRLZ7uSYDd3vEkCTcaDKQ19xr2clP0VsgP040xrKpNGLumEvbB0U F7KEfptWajq0QAR8lZ1uKPuFN1d6wz0b74rrQMfYHl0k9Amgo0TbSdvijt+/bcSqcEb3 VOWZFdWfNBoG/8rok54g5ZPLE49+LeU25gvwPEAQUmOz2Ph7w4qRp53thezkjiVOneE+ bNhg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=LKW6nV+K; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 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 out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id va1-20020a17090711c100b006fee2aa8759si2321116ejb.797.2022.05.31.06.50.59; Tue, 31 May 2022 06:51:43 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=LKW6nV+K; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 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 S240141AbiE3O2W (ORCPT + 99 others); Mon, 30 May 2022 10:28:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42666 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241442AbiE3ORg (ORCPT ); Mon, 30 May 2022 10:17:36 -0400 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3C994527F0; Mon, 30 May 2022 06:47:19 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id E788AB80DAC; Mon, 30 May 2022 13:47:17 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4BA8FC36AEB; Mon, 30 May 2022 13:47:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1653918436; bh=ymzWjDHXG7HZZr+a7YADqPiXCSYJgmQtXeMkZqAhPos=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LKW6nV+KT8pfct7ve99b7Nj705ar0LAmiGMoNpCVXAgvyT5JUnlDoqrviDTer9Z04 d1wusOU38OgpyT4gy9CFwblb6ba4Zuo0qeGm1/doD5T90VLiXsHAYR7YV9gKS2ZSP+ NEf7UUNwOZK8b7n+Q8S2EdQDDe2xA0FqZHzPxVpRuc4duVmhdrMrUO5idAJavfwkQ5 rGpAsnGO3GcOj8qj03ONiZrrhGsSPWe193tsKtlCJYdDacTWfsgshc0nqlPyUCn9/t MgJbviGF690Dh4hoVkZduHWytUgNDBKS7nWNLgU27U0Z4qM+2yXI9xkmNYhPpvtdng mNthaRby/RJPA== From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Niels Dossche , Paolo Abeni , Jakub Kicinski , Sasha Levin , davem@davemloft.net, edumazet@google.com, yoshfuji@linux-ipv6.org, dsahern@kernel.org, netdev@vger.kernel.org Subject: [PATCH AUTOSEL 5.4 06/55] ipv6: fix locking issues with loops over idev->addr_list Date: Mon, 30 May 2022 09:46:12 -0400 Message-Id: <20220530134701.1935933-6-sashal@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220530134701.1935933-1-sashal@kernel.org> References: <20220530134701.1935933-1-sashal@kernel.org> MIME-Version: 1.0 X-stable: review X-Patchwork-Hint: Ignore Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-7.7 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Niels Dossche [ Upstream commit 51454ea42c1ab4e0c2828bb0d4d53957976980de ] idev->addr_list needs to be protected by idev->lock. However, it is not always possible to do so while iterating and performing actions on inet6_ifaddr instances. For example, multiple functions (like addrconf_{join,leave}_anycast) eventually call down to other functions that acquire the idev->lock. The current code temporarily unlocked the idev->lock during the loops, which can cause race conditions. Moving the locks up is also not an appropriate solution as the ordering of lock acquisition will be inconsistent with for example mc_lock. This solution adds an additional field to inet6_ifaddr that is used to temporarily add the instances to a temporary list while holding idev->lock. The temporary list can then be traversed without holding idev->lock. This change was done in two places. In addrconf_ifdown, the list_for_each_entry_safe variant of the list loop is also no longer necessary as there is no deletion within that specific loop. Suggested-by: Paolo Abeni Signed-off-by: Niels Dossche Acked-by: Paolo Abeni Link: https://lore.kernel.org/r/20220403231523.45843-1-dossche.niels@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- include/net/if_inet6.h | 8 ++++++++ net/ipv6/addrconf.c | 30 ++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index a01981d7108f..f6d614926e9e 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -64,6 +64,14 @@ struct inet6_ifaddr { struct hlist_node addr_lst; struct list_head if_list; + /* + * Used to safely traverse idev->addr_list in process context + * if the idev->lock needed to protect idev->addr_list cannot be held. + * In that case, add the items to this list temporarily and iterate + * without holding idev->lock. + * See addrconf_ifdown and dev_forward_change. + */ + struct list_head if_list_aux; struct list_head tmp_list; struct inet6_ifaddr *ifpub; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 92b32d131e1c..efea88fb3cd5 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -789,6 +789,7 @@ static void dev_forward_change(struct inet6_dev *idev) { struct net_device *dev; struct inet6_ifaddr *ifa; + LIST_HEAD(tmp_addr_list); if (!idev) return; @@ -807,14 +808,24 @@ static void dev_forward_change(struct inet6_dev *idev) } } + read_lock_bh(&idev->lock); list_for_each_entry(ifa, &idev->addr_list, if_list) { if (ifa->flags&IFA_F_TENTATIVE) continue; + list_add_tail(&ifa->if_list_aux, &tmp_addr_list); + } + read_unlock_bh(&idev->lock); + + while (!list_empty(&tmp_addr_list)) { + ifa = list_first_entry(&tmp_addr_list, + struct inet6_ifaddr, if_list_aux); + list_del(&ifa->if_list_aux); if (idev->cnf.forwarding) addrconf_join_anycast(ifa); else addrconf_leave_anycast(ifa); } + inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF, NETCONFA_FORWARDING, dev->ifindex, &idev->cnf); @@ -3713,7 +3724,8 @@ static int addrconf_ifdown(struct net_device *dev, int how) unsigned long event = how ? NETDEV_UNREGISTER : NETDEV_DOWN; struct net *net = dev_net(dev); struct inet6_dev *idev; - struct inet6_ifaddr *ifa, *tmp; + struct inet6_ifaddr *ifa; + LIST_HEAD(tmp_addr_list); bool keep_addr = false; bool was_ready; int state, i; @@ -3805,16 +3817,23 @@ static int addrconf_ifdown(struct net_device *dev, int how) write_lock_bh(&idev->lock); } - list_for_each_entry_safe(ifa, tmp, &idev->addr_list, if_list) { + list_for_each_entry(ifa, &idev->addr_list, if_list) + list_add_tail(&ifa->if_list_aux, &tmp_addr_list); + write_unlock_bh(&idev->lock); + + while (!list_empty(&tmp_addr_list)) { struct fib6_info *rt = NULL; bool keep; + ifa = list_first_entry(&tmp_addr_list, + struct inet6_ifaddr, if_list_aux); + list_del(&ifa->if_list_aux); + addrconf_del_dad_work(ifa); keep = keep_addr && (ifa->flags & IFA_F_PERMANENT) && !addr_is_local(&ifa->addr); - write_unlock_bh(&idev->lock); spin_lock_bh(&ifa->lock); if (keep) { @@ -3845,15 +3864,14 @@ static int addrconf_ifdown(struct net_device *dev, int how) addrconf_leave_solict(ifa->idev, &ifa->addr); } - write_lock_bh(&idev->lock); if (!keep) { + write_lock_bh(&idev->lock); list_del_rcu(&ifa->if_list); + write_unlock_bh(&idev->lock); in6_ifa_put(ifa); } } - write_unlock_bh(&idev->lock); - /* Step 5: Discard anycast and multicast list */ if (how) { ipv6_ac_destroy_dev(idev); -- 2.35.1