Received: by 2002:a05:6358:4e97:b0:b3:742d:4702 with SMTP id ce23csp700848rwb; Thu, 11 Aug 2022 08:30:42 -0700 (PDT) X-Google-Smtp-Source: AA6agR6BwJ7KVQpvNDJqvg8cjcr3VUMgcLcD5dkAiUAC0czVQ32fCOPvy9vy41s/57GBTFy+qVvr X-Received: by 2002:a17:907:6d11:b0:730:a382:d5ba with SMTP id sa17-20020a1709076d1100b00730a382d5bamr23275373ejc.371.1660231842016; Thu, 11 Aug 2022 08:30:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1660231842; cv=none; d=google.com; s=arc-20160816; b=H1MUR3BRxOUJ4gR7ZhjpEDCl3gR86zIfG6wgKUP2hwytoWrwyH6juFH5+p7O1FsfrW xN/fbxawHLsjehF+WMirX0gkKHlIvDSIszI296KFwbhLILtCIoFs2ahoeYy0zYLIUTUO WE0jIxnpY9bu8WG1TGwmwqc8kShSDG0rhCJBYZn+dscbhggdr2fYNQqc7gNotiPFZeZJ 9r82ZPSGWQtX02ZjBsGpJNd6uvTzjEJ8UilNwR1Vqx2CgzY7zmqtKcUVOYURC4DTR8at Z1deQD7LCPbTwnWOC1mA4Ii05AOkTe9xZFULRToksCv+7VlpcW2qKcob+RbwlipQuesx QGVw== 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; bh=+G/L4ZLqc43iDBeJooNvbI6eo7KgEeUoogOnj6UqcBI=; b=EVmJnrkUl2qXNMezg40+Rn4aXEc03v80v9odaJfIVAJNlfZshIWrFploJkE8BNpsZW f3uGKs9wbdX2z0e7AE5ILj8qRU6FS2EA3RHmhoMIb5DAf2Q6vJtqlGqox2I+LJ80ceit IxfzTLTwGwzHw59TmQRCB7tU9if9jirh4wyOzN0iJJjfQ37qZS7S+46kr1bjaGPcvdaI IIYoaL2gSTrSo085w15iwrTqSR6/I/UA2xTAYV4GG3W7suuzUoOusqOCqYRvZhjcA0c0 mzD7ieo2WdwO+2aGwqmmNdVMLQmdksoN+r+mIH5qAwgEBBpF1GIyt+ZOOSL9TaFJ9Yuq ExLA== ARC-Authentication-Results: i=1; mx.google.com; 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=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id qa32-20020a17090786a000b0073276700562si7110257ejc.282.2022.08.11.08.30.15; Thu, 11 Aug 2022 08:30:42 -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; 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=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235662AbiHKPVN (ORCPT + 99 others); Thu, 11 Aug 2022 11:21:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39138 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234338AbiHKPVM (ORCPT ); Thu, 11 Aug 2022 11:21:12 -0400 Received: from relay.virtuozzo.com (relay.virtuozzo.com [130.117.225.111]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2DACE5A8A5; Thu, 11 Aug 2022 08:21:10 -0700 (PDT) Received: from dev010.ch-qa.sw.ru ([172.29.1.15]) by relay.virtuozzo.com with esmtp (Exim 4.95) (envelope-from ) id 1oM9xk-00FExA-MG; Thu, 11 Aug 2022 17:20:19 +0200 From: Alexander Mikhalitsyn To: netdev@vger.kernel.org Cc: "Denis V. Lunev" , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Daniel Borkmann , David Ahern , Yajun Deng , Roopa Prabhu , Christian Brauner , linux-kernel@vger.kernel.org, Alexey Kuznetsov , Alexander Mikhalitsyn , Konstantin Khorenko , kernel@openvz.org, devel@openvz.org Subject: [PATCH v3 1/2] neigh: fix possible DoS due to net iface start/stop loop Date: Thu, 11 Aug 2022 18:20:11 +0300 Message-Id: <20220811152012.319641-2-alexander.mikhalitsyn@virtuozzo.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20220811152012.319641-1-alexander.mikhalitsyn@virtuozzo.com> References: <20220729103559.215140-1-alexander.mikhalitsyn@virtuozzo.com> <20220811152012.319641-1-alexander.mikhalitsyn@virtuozzo.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_NONE,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" 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 --- 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 6a8c2596ebab..0e38a05d5b23 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -307,14 +307,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, @@ -385,9 +394,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; } @@ -1787,7 +1796,7 @@ int neigh_table_clear(int index, struct neigh_table *tbl) cancel_delayed_work_sync(&tbl->managed_work); 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.36.1