Received: by 2002:a05:6358:45e:b0:b5:b6eb:e1f9 with SMTP id 30csp2022700rwe; Fri, 2 Sep 2022 07:28:46 -0700 (PDT) X-Google-Smtp-Source: AA6agR75SwpBnrK2I75D/O6OVb9tE1W2+dSA/ruB/8jNPkLYnd9oPtCoigESrmcoaGLsX3NtQRuh X-Received: by 2002:a05:6402:c45:b0:442:c549:8e6b with SMTP id cs5-20020a0564020c4500b00442c5498e6bmr33336447edb.123.1662128925962; Fri, 02 Sep 2022 07:28:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1662128925; cv=none; d=google.com; s=arc-20160816; b=WMcUeDgqgjdEEm9YAkZOllgallAI5jJOCUj8yBxnJtH8UCmgcjE3glLQcZB9+JXoQg UVndQ0pTlx/gNrq1/Metxr4d8vx86iX56YSVk8oXXbgXfTj/HmNM/b/b1NuJ4HAmn0HM e6ajJV//frAJbFHX6F0KaEjLbnfgluMMb4LLmoRF6w2xbOGEXqjzhqolrC0SUb/iBgRr lK6x/hb6R5s56Qk8w6qLgjuePHVipbi1pHeau6KAl6k2yAWCpjkcooziIlogSzQgCfwv oa83orO8vy8jt0ojb/TzF5pF/gI41NI8i1DJpaLdK2eYOax7TfW+/NXw0/pLOsvPhxAc nZyA== 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=Y8q8XwAk1y8utyz5kLsbkeoawpYAHIr9nx+UosQqGI4=; b=jf/vZSG3cKeQ1rwVzZGiXEn9lhy+5zz3K+0w+BYcvno90Rl3gpym0HHmHMGuvTPxqa vCUM6OtuEOMKGSbqQpFTBfkb34nfjueJnj9Mr5AklwYkikaqF3PvLUYSfL/P4SzjIPAm Z7Td6dAMOtS8dUVtzf/FxZUXNkzblRH2HabNLAYF1JEKtGC75WzE5YOpzYJ+da+FLq0g 8ZA7NRL284F7v2ecN1I4bFsIDMzJMB1bxL+ReHTijtXlgLtjW+pktP0eKFlgHJl6F2nC Eg8L/L+6RvJJsNmSxzPrxb8TN1y5/bZ3pTDxw49yOTJirPx5Xv1oFyiTNCJDhgjY7M7t 7jaA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=x4xPb0+e; 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=linuxfoundation.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id k11-20020a50ce4b000000b00445fba6c607si1444217edj.140.2022.09.02.07.28.16; Fri, 02 Sep 2022 07:28:45 -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=@linuxfoundation.org header.s=korg header.b=x4xPb0+e; 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=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237289AbiIBMlJ (ORCPT + 99 others); Fri, 2 Sep 2022 08:41:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42526 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237232AbiIBMiv (ORCPT ); Fri, 2 Sep 2022 08:38:51 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5ABEF474D6; Fri, 2 Sep 2022 05:30:21 -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 dfw.source.kernel.org (Postfix) with ESMTPS id 73F4762196; Fri, 2 Sep 2022 12:29:52 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 497C4C433C1; Fri, 2 Sep 2022 12:29:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1662121791; bh=0qF/oYmMy+Nd9dHjixWzVS8ZidgujaNkK2EyJt3lh8c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=x4xPb0+eomvKU9feZyFtAPKvAF9YVm5+atKcNT1bcfFLm8wY+qTRLm33gn5wsrwi8 LVz8EjjgV4C8D5udQ3FxIZAgKJ+Kd8GC5UB2jm+H41RvZ+W/PMhdEZ9moMS6TkB2NY 3h1Wtglv716SPabVE6a4oqEKp18AMqH5ZT/2XOdU= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Daniel Borkmann , David Ahern , Yajun Deng , Roopa Prabhu , Christian Brauner , netdev@vger.kernel.org, Alexey Kuznetsov , Alexander Mikhalitsyn , Konstantin Khorenko , kernel@openvz.org, devel@openvz.org, "Denis V. Lunev" , Sasha Levin Subject: [PATCH 5.4 67/77] neigh: fix possible DoS due to net iface start/stop loop Date: Fri, 2 Sep 2022 14:19:16 +0200 Message-Id: <20220902121405.911113172@linuxfoundation.org> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20220902121403.569927325@linuxfoundation.org> References: <20220902121403.569927325@linuxfoundation.org> User-Agent: quilt/0.67 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-7.1 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: Denis V. Lunev [ Upstream commit 66ba215cb51323e4e55e38fd5f250e0fae0cbc94 ] Normal processing of ARP request (usually this is Ethernet broadcast packet) coming to the host is looking like the following: * the packet comes to arp_process() call and is passed through routing procedure * the request is put into the queue using pneigh_enqueue() if corresponding ARP record is not local (common case for container records on the host) * the request is processed by timer (within 80 jiffies by default) and ARP reply is sent from the same arp_process() using NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED condition (flag is set inside pneigh_enqueue()) And here the problem comes. Linux kernel calls pneigh_queue_purge() which destroys the whole queue of ARP requests on ANY network interface start/stop event through __neigh_ifdown(). This is actually not a problem within the original world as network interface start/stop was accessible to the host 'root' only, which could do more destructive things. But the world is changed and there are Linux containers available. Here container 'root' has an access to this API and could be considered as untrusted user in the hosting (container's) world. Thus there is an attack vector to other containers on node when container's root will endlessly start/stop interfaces. We have observed similar situation on a real production node when docker container was doing such activity and thus other containers on the node become not accessible. The patch proposed doing very simple thing. It drops only packets from the same namespace in the pneigh_queue_purge() where network interface state change is detected. This is enough to prevent the problem for the whole node preserving original semantics of the code. v2: - do del_timer_sync() if queue is empty after pneigh_queue_purge() v3: - rebase to net tree Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: Daniel Borkmann Cc: David Ahern Cc: Yajun Deng Cc: Roopa Prabhu Cc: Christian Brauner Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: Alexey Kuznetsov Cc: Alexander Mikhalitsyn Cc: Konstantin Khorenko Cc: kernel@openvz.org Cc: devel@openvz.org Investigated-by: Alexander Mikhalitsyn Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/core/neighbour.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 8b6140e67e7f8..6056b8e545658 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -280,14 +280,23 @@ static int neigh_del_timer(struct neighbour *n) return 0; } -static void pneigh_queue_purge(struct sk_buff_head *list) +static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net) { + unsigned long flags; struct sk_buff *skb; - while ((skb = skb_dequeue(list)) != NULL) { - dev_put(skb->dev); - kfree_skb(skb); + spin_lock_irqsave(&list->lock, flags); + skb = skb_peek(list); + while (skb != NULL) { + struct sk_buff *skb_next = skb_peek_next(skb, list); + if (net == NULL || net_eq(dev_net(skb->dev), net)) { + __skb_unlink(skb, list); + dev_put(skb->dev); + kfree_skb(skb); + } + skb = skb_next; } + spin_unlock_irqrestore(&list->lock, flags); } static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev, @@ -358,9 +367,9 @@ static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev, write_lock_bh(&tbl->lock); neigh_flush_dev(tbl, dev, skip_perm); pneigh_ifdown_and_unlock(tbl, dev); - - del_timer_sync(&tbl->proxy_timer); - pneigh_queue_purge(&tbl->proxy_queue); + pneigh_queue_purge(&tbl->proxy_queue, dev_net(dev)); + if (skb_queue_empty_lockless(&tbl->proxy_queue)) + del_timer_sync(&tbl->proxy_timer); return 0; } @@ -1741,7 +1750,7 @@ int neigh_table_clear(int index, struct neigh_table *tbl) /* It is not clean... Fix it to unload IPv6 module safely */ cancel_delayed_work_sync(&tbl->gc_work); del_timer_sync(&tbl->proxy_timer); - pneigh_queue_purge(&tbl->proxy_queue); + pneigh_queue_purge(&tbl->proxy_queue, NULL); neigh_ifdown(tbl, NULL); if (atomic_read(&tbl->entries)) pr_crit("neighbour leakage\n"); -- 2.35.1