From patchwork Fri Apr 21 23:40:30 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Ahern X-Patchwork-Id: 753636 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 3w8sjJ4Hkzz9s3s for ; Sat, 22 Apr 2017 09:42:28 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=cumulusnetworks.com header.i=@cumulusnetworks.com header.b="a3hEI7Cy"; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1426898AbdDUXlw (ORCPT ); Fri, 21 Apr 2017 19:41:52 -0400 Received: from mail-it0-f44.google.com ([209.85.214.44]:37338 "EHLO mail-it0-f44.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1424501AbdDUXkg (ORCPT ); Fri, 21 Apr 2017 19:40:36 -0400 Received: by mail-it0-f44.google.com with SMTP id x188so557822itb.0 for ; Fri, 21 Apr 2017 16:40:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cumulusnetworks.com; s=google; h=from:to:cc:subject:date:message-id; bh=q64EHet789xdBLrVaM9dbuE4cPBhl+G8qw8UEoyn3Do=; b=a3hEI7Cyhv+P6T3c7iDxK1UxqU2duxCk495tSX/P7znq8pSEnY+hmkKftZKMXPmEoH zSoIFTswIlUYEe41GIUtg1neQLBRBJu/HWbUIL+vbMNgW68CjO+QqCC7RPCAfDr9eW/s 3gKiyj1iLOoHPzTyISTQ3W0zdOlBS1B05HQvA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=q64EHet789xdBLrVaM9dbuE4cPBhl+G8qw8UEoyn3Do=; b=YHZM4TM4EMjzAc5NqLgOUDPlcOff8pM6WXp47OGC9EWw6sEWQw3JJOccn3tX7fTg7B m3k9jrH6cQpS7yjh//IUANLEsmZckzqdP9OH9ysg9ieFCIMqO5XzQAZDeS4ZjFvvnP9P AW9htrQZVfCz1uk4mzBDTVDUJBoU341ccDuOG8c4I7LadS0k/WITDYO/ecj96Q/UGVV7 eXplLaA58olvXanYvZpxvgQNjWyD8BISgczG7tGjKmwuiU5nUEvLRL/qsbStmK9yvhor Nqofg0snnuEBEV644obcjzhs9uZe9+0FAxcaehXs+LVkryhw9DuEQ7FYgiFugGuV1nl4 sRXQ== X-Gm-Message-State: AN3rC/6lUu6pAvdS6Ua0YxzYLpq1grEzYx5/ib/7TD46LyCKK21dhElF pe+OvqYvgf3FbK4L X-Received: by 10.84.224.12 with SMTP id r12mr18546999plj.69.1492818035844; Fri, 21 Apr 2017 16:40:35 -0700 (PDT) Received: from kenny.it.cumulusnetworks.com. ([216.129.126.126]) by smtp.googlemail.com with ESMTPSA id q1sm17911591pfc.35.2017.04.21.16.40.34 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 21 Apr 2017 16:40:35 -0700 (PDT) From: David Ahern To: netdev@vger.kernel.org Cc: dvyukov@google.com, andreyknvl@google.com, mmanning@brocade.com, David Ahern Subject: [PATCH net] net: ipv6: regenerate host route if moved to gc list Date: Fri, 21 Apr 2017 16:40:30 -0700 Message-Id: <1492818030-17640-1-git-send-email-dsa@cumulusnetworks.com> X-Mailer: git-send-email 2.1.4 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Taking down the loopback device wreaks havoc on IPv6 routes. By extension, taking a VRF device wreaks havoc on its table. Dmitry and Andrey both reported heap out-of-bounds reports in the IPv6 FIB code while running syzkaller fuzzer. The root cause is a dead dst that is on the garbage list gets reinserted into the IPv6 FIB. While on the gc (or perhaps when it gets added to the gc list) the dst->next is set to an IPv4 dst. A subsequent walk of the ipv6 tables causes the out-of-bounds access. Andrey's reproducer was the key to getting to the bottom of this. With IPv6, host routes for an address have the dst->dev set to the loopback device. When the 'lo' device is taken down, rt6_ifdown initiates a walk of the fib evicting routes with the 'lo' device which means all host routes are removed. That process moves the dst which is attached to an inet6_ifaddr to the gc list and marks it as dead. The recent change to keep global IPv6 addresses added a new function fixup_permanent_addr that is called on admin up. That function restarts dad for an inet6_ifaddr and when it completes the host route attached to it is inserted into the fib. Since the route was marked dead and moved to the gc list, we get the reported out-of-bounds accesses. If the device with the address is taken down or the address is removed, the WARN_ON in fib6_del is triggered. All of those faults are fixed by regenerating the host route of the existing one has been moved to the gc list, something that can be determined by checking if the rt6i_ref counter is 0. The update of the route on the ifp is done using cmpxchg as suggested by Li RongQing in a patch a year ago. Fixes: f1705ec197e7 ("net: ipv6: Make address flushing on ifdown optional") Reported-by: Dmitry Vyukov Reported-by: Andrey Konovalov Signed-off-by: David Ahern --- net/ipv6/addrconf.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 08f9e8ea7a81..93555528a45b 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3303,14 +3303,16 @@ static void addrconf_gre_config(struct net_device *dev) static int fixup_permanent_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp) { - if (!ifp->rt) { - struct rt6_info *rt; + if (!ifp->rt || !atomic_read(&ifp->rt->rt6i_ref)) { + struct rt6_info *rt, *prev; rt = addrconf_dst_alloc(idev, &ifp->addr, false); if (unlikely(IS_ERR(rt))) return PTR_ERR(rt); - ifp->rt = rt; + prev = cmpxchg(&ifp->rt, ifp->rt, rt); + if (prev) + ip6_rt_put(prev); } if (!(ifp->flags & IFA_F_NOPREFIXROUTE)) {