From patchwork Mon Apr 10 06:36:39 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rabin Vincent X-Patchwork-Id: 748847 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3w1gSv3WTPz9s7m for ; Mon, 10 Apr 2017 16:36:47 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751442AbdDJGgo (ORCPT ); Mon, 10 Apr 2017 02:36:44 -0400 Received: from bes.se.axis.com ([195.60.68.10]:38495 "EHLO bes.se.axis.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751134AbdDJGgo (ORCPT ); Mon, 10 Apr 2017 02:36:44 -0400 Received: from localhost (localhost [127.0.0.1]) by bes.se.axis.com (Postfix) with ESMTP id 87C3A2E281; Mon, 10 Apr 2017 08:36:42 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at bes.se.axis.com Received: from bes.se.axis.com ([IPv6:::ffff:127.0.0.1]) by localhost (bes.se.axis.com [::ffff:127.0.0.1]) (amavisd-new, port 10024) with LMTP id jHhzYzPODkEP; Mon, 10 Apr 2017 08:36:41 +0200 (CEST) Received: from boulder02.se.axis.com (boulder02.se.axis.com [10.0.8.16]) by bes.se.axis.com (Postfix) with ESMTPS id DC3DA2E2CD; Mon, 10 Apr 2017 08:36:40 +0200 (CEST) Received: from boulder02.se.axis.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8ECE01A070; Mon, 10 Apr 2017 08:36:40 +0200 (CEST) Received: from boulder02.se.axis.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 82E3C1A065; Mon, 10 Apr 2017 08:36:40 +0200 (CEST) Received: from thoth.se.axis.com (unknown [10.0.2.173]) by boulder02.se.axis.com (Postfix) with ESMTP; Mon, 10 Apr 2017 08:36:40 +0200 (CEST) Received: from lnxrabinv.se.axis.com (lnxrabinv.se.axis.com [10.88.144.1]) by thoth.se.axis.com (Postfix) with ESMTP id 775332F0C; Mon, 10 Apr 2017 08:36:40 +0200 (CEST) Received: by lnxrabinv.se.axis.com (Postfix, from userid 10564) id 6F2A2202FD; Mon, 10 Apr 2017 08:36:40 +0200 (CEST) From: Rabin Vincent To: davem@davemloft.net Cc: netdev@vger.kernel.org, dsa@cumulusnetworks.com, Rabin Vincent Subject: [PATCH] ipv6: Fix idev->addr_list corruption Date: Mon, 10 Apr 2017 08:36:39 +0200 Message-Id: <1491806199-26115-1-git-send-email-rabin.vincent@axis.com> X-Mailer: git-send-email 2.7.0 X-TM-AS-GCONF: 00 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Rabin Vincent addrconf_ifdown() removes elements from the idev->addr_list without holding the idev->lock. If this happens while the loop in __ipv6_dev_get_saddr() is handling the same element, that function ends up in an infinite loop: NMI watchdog: BUG: soft lockup - CPU#1 stuck for 23s! [test:1719] Call Trace: ipv6_get_saddr_eval+0x13c/0x3a0 __ipv6_dev_get_saddr+0xe4/0x1f0 ipv6_dev_get_saddr+0x1b4/0x204 ip6_dst_lookup_tail+0xcc/0x27c ip6_dst_lookup_flow+0x38/0x80 udpv6_sendmsg+0x708/0xba8 sock_sendmsg+0x18/0x30 SyS_sendto+0xb8/0xf8 syscall_common+0x34/0x58 Fixes: 6a923934c33 (Revert "ipv6: Revert optional address flusing on ifdown.") Signed-off-by: Rabin Vincent Acked-by: David Ahern --- net/ipv6/addrconf.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 3631725..80ce478 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3626,14 +3626,19 @@ static int addrconf_ifdown(struct net_device *dev, int how) INIT_LIST_HEAD(&del_list); list_for_each_entry_safe(ifa, tmp, &idev->addr_list, if_list) { struct rt6_info *rt = NULL; + bool keep; addrconf_del_dad_work(ifa); + keep = keep_addr && (ifa->flags & IFA_F_PERMANENT) && + !addr_is_local(&ifa->addr); + if (!keep) + list_move(&ifa->if_list, &del_list); + write_unlock_bh(&idev->lock); spin_lock_bh(&ifa->lock); - if (keep_addr && (ifa->flags & IFA_F_PERMANENT) && - !addr_is_local(&ifa->addr)) { + if (keep) { /* set state to skip the notifier below */ state = INET6_IFADDR_STATE_DEAD; ifa->state = 0; @@ -3645,8 +3650,6 @@ static int addrconf_ifdown(struct net_device *dev, int how) } else { state = ifa->state; ifa->state = INET6_IFADDR_STATE_DEAD; - - list_move(&ifa->if_list, &del_list); } spin_unlock_bh(&ifa->lock);