public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: "Denis V. Lunev" <den@openvz.org>,
	"David S. Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	Daniel Borkmann <daniel@iogearbox.net>,
	David Ahern <dsahern@kernel.org>,
	Yajun Deng <yajun.deng@linux.dev>,
	Roopa Prabhu <roopa@nvidia.com>,
	Christian Brauner <brauner@kernel.org>,
	netdev@vger.kernel.org, Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>,
	Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>,
	Konstantin Khorenko <khorenko@virtuozzo.com>,
	kernel@openvz.org, devel@openvz.org,
	Sasha Levin <sashal@kernel.org>,
	wangyuweihx@gmail.com
Subject: [PATCH AUTOSEL 5.15 08/20] neigh: fix possible DoS due to net iface start/stop loop
Date: Wed, 24 Aug 2022 21:37:00 -0400	[thread overview]
Message-ID: <20220825013713.22656-8-sashal@kernel.org> (raw)
In-Reply-To: <20220825013713.22656-1-sashal@kernel.org>

From: "Denis V. Lunev" <den@openvz.org>

[ 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" <davem@davemloft.net>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: David Ahern <dsahern@kernel.org>
Cc: Yajun Deng <yajun.deng@linux.dev>
Cc: Roopa Prabhu <roopa@nvidia.com>
Cc: Christian Brauner <brauner@kernel.org>
Cc: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Cc: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
Cc: Konstantin Khorenko <khorenko@virtuozzo.com>
Cc: kernel@openvz.org
Cc: devel@openvz.org
Investigated-by: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 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 ff049733ccee..f0be42c140b9 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -279,14 +279,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,
@@ -357,9 +366,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;
 }
 
@@ -1735,7 +1744,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


  parent reply	other threads:[~2022-08-25  1:40 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-25  1:36 [PATCH AUTOSEL 5.15 01/20] fs/ntfs3: Fix work with fragmented xattr Sasha Levin
2022-08-25  1:36 ` [PATCH AUTOSEL 5.15 02/20] ASoC: sh: rz-ssi: Improve error handling in rz_ssi_probe() error path Sasha Levin
2022-08-25  1:36 ` [PATCH AUTOSEL 5.15 03/20] drm/amd/display: Avoid MPC infinite loop Sasha Levin
2022-08-25  1:36 ` [PATCH AUTOSEL 5.15 04/20] drm/amd/display: Fix HDMI VSIF V3 incorrect issue Sasha Levin
2022-08-25  1:36 ` [PATCH AUTOSEL 5.15 05/20] drm/amd/display: For stereo keep "FLIP_ANY_FRAME" Sasha Levin
2022-08-25  1:36 ` [PATCH AUTOSEL 5.15 06/20] drm/amd/display: clear optc underflow before turn off odm clock Sasha Levin
2022-08-25  1:36 ` [PATCH AUTOSEL 5.15 07/20] ksmbd: return STATUS_BAD_NETWORK_NAME error status if share is not configured Sasha Levin
2022-08-25  1:37 ` Sasha Levin [this message]
2022-08-25  1:37 ` [PATCH AUTOSEL 5.15 09/20] s390/hypfs: avoid error message under KVM Sasha Levin
2022-08-25  1:37 ` [PATCH AUTOSEL 5.15 10/20] ksmbd: don't remove dos attribute xattr on O_TRUNC open Sasha Levin
2022-08-25  1:37 ` [PATCH AUTOSEL 5.15 11/20] drm/amd/pm: add missing ->fini_microcode interface for Sienna Cichlid Sasha Levin
2022-08-25  1:37 ` [PATCH AUTOSEL 5.15 12/20] drm/amd/display: Fix pixel clock programming Sasha Levin
2022-08-25  1:37 ` [PATCH AUTOSEL 5.15 13/20] drm/amdgpu: Increase tlb flush timeout for sriov Sasha Levin
2022-08-25  1:37 ` [PATCH AUTOSEL 5.15 14/20] drm/amd/display: avoid doing vm_init multiple time Sasha Levin
2022-08-25  1:37 ` [PATCH AUTOSEL 5.15 15/20] netfilter: conntrack: NF_CONNTRACK_PROCFS should no longer default to y Sasha Levin
2022-08-25  1:37 ` [PATCH AUTOSEL 5.15 16/20] testing: selftests: nft_flowtable.sh: use random netns names Sasha Levin
2022-08-25  1:37 ` [PATCH AUTOSEL 5.15 17/20] btrfs: move lockdep class helpers to locking.c Sasha Levin
2022-08-25  1:37 ` [PATCH AUTOSEL 5.15 18/20] btrfs: fix lockdep splat with reloc root extent buffers Sasha Levin
2022-08-25  1:37 ` [PATCH AUTOSEL 5.15 19/20] btrfs: tree-checker: check for overlapping extent items Sasha Levin
2022-08-25  1:37 ` [PATCH AUTOSEL 5.15 20/20] ftrace: Fix NULL pointer dereference in is_ftrace_trampoline when ftrace is dead Sasha Levin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220825013713.22656-8-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=alexander.mikhalitsyn@virtuozzo.com \
    --cc=brauner@kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=den@openvz.org \
    --cc=devel@openvz.org \
    --cc=dsahern@kernel.org \
    --cc=edumazet@google.com \
    --cc=kernel@openvz.org \
    --cc=khorenko@virtuozzo.com \
    --cc=kuba@kernel.org \
    --cc=kuznet@ms2.inr.ac.ru \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=roopa@nvidia.com \
    --cc=stable@vger.kernel.org \
    --cc=wangyuweihx@gmail.com \
    --cc=yajun.deng@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox