mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net v2 0/2] netlink: fix a dump livelock with a notification queued
@ 2026-10-27 14:04 Jhonata Poma-Hansen via B4 Relay
  2026-10-27 14:04 ` [PATCH net v2 1/2] netlink: check sk_rcvbuf before charging the dump skb Jhonata Poma-Hansen via B4 Relay
  2026-10-27 14:04 ` [PATCH net v2 2/2] selftests: net: netlink-dumps: start a dump with a notification queued Jhonata Poma-Hansen via B4 Relay
  0 siblings, 2 replies; 4+ messages in thread
From: Jhonata Poma-Hansen via B4 Relay @ 2026-10-27 14:04 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Shuah Khan
  Cc: netdev, linux-kernel, linux-kselftest, Kuniyuki Iwashima,
	Marek Szyprowski, Jhonata Poma-Hansen

A netlink dump that starts while a notification is still charged to a
socket with a small receive buffer fails with ENOBUFS, and every retry
from recvmsg() fails the same way. A reader that peeks before reading,
as libnl does, never consumes the message at the head of the queue and
spins forever. I hit this with "iw dev wlan0 scan" on an arm64 board.

Patch 1 goes back to checking sk_rcvbuf before charging the dump skb,
as before commit ae8f160e7eb2. Patch 2 adds a selftest; it fails
without patch 1 and is skipped without the privileges to create a
netns.

---
Changes in v2:
- Patch 1: check sk_rcvbuf before charging instead of retrying with
  the minimum skb size, which could still be rejected (Sashiko), and
  refuse a skb that would take sk_rmem_alloc past INT_MAX.
- Patch 1: say how the bug was found and how the fix was tested.
- Patch 2: use SO_RCVBUF 2048, which also fails with v1, check the
  NLMSG_DONE status and that a link was dumped, and skip without
  privileges (Sashiko).
- Link to v1: https://patch.msgid.link/20261023-netlink-dump-livelock-v1-0-478214a635d2@gmail.com

To: "David S. Miller" <davem@davemloft.net>
To: Eric Dumazet <edumazet@kernel.org>
To: Jakub Kicinski <kuba@kernel.org>
To: Paolo Abeni <pabeni@redhat.com>
To: Simon Horman <horms@kernel.org>
To: Kuniyuki Iwashima <kuniyu@google.com>
To: Shuah Khan <shuah@kernel.org>
Cc: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-kselftest@vger.kernel.org

---
Jhonata Poma-Hansen (2):
      netlink: check sk_rcvbuf before charging the dump skb
      selftests: net: netlink-dumps: start a dump with a notification queued

 net/netlink/af_netlink.c                    |   6 +-
 tools/testing/selftests/net/netlink-dumps.c | 102 ++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+), 1 deletion(-)
---
base-commit: 734bef548a96e8774d6eef5dfa2026c6edc4e80b
change-id: 20261023-netlink-dump-livelock-e83cf13f977a

Best regards,
--  
Jhonata Poma-Hansen <jhonata.poma@gmail.com>



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH net v2 1/2] netlink: check sk_rcvbuf before charging the dump skb
  2026-10-27 14:04 [PATCH net v2 0/2] netlink: fix a dump livelock with a notification queued Jhonata Poma-Hansen via B4 Relay
@ 2026-10-27 14:04 ` Jhonata Poma-Hansen via B4 Relay
  2026-10-27 16:17   ` Eric Dumazet
  2026-10-27 14:04 ` [PATCH net v2 2/2] selftests: net: netlink-dumps: start a dump with a notification queued Jhonata Poma-Hansen via B4 Relay
  1 sibling, 1 reply; 4+ messages in thread
From: Jhonata Poma-Hansen via B4 Relay @ 2026-10-27 14:04 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Shuah Khan
  Cc: netdev, linux-kernel, linux-kselftest, Kuniyuki Iwashima,
	Marek Szyprowski, Jhonata Poma-Hansen

From: Jhonata Poma-Hansen <jhonata.poma@gmail.com>

Since commit ae8f160e7eb2 ("netlink: Fix wraparounds of
sk->sk_rmem_alloc."), netlink_dump() charges the dump skb first and
queues it only if sk_rmem_alloc is still below sk_rcvbuf. Commit
a215b5723922 ("netlink: make sure we allow at least one dump skb")
added an exception for an empty socket.

A dump that starts while something else is still charged to a socket
with a small receive buffer fails with ENOBUFS and stays running.
Every recvmsg() retries it, fails again and sets sk_err, so a reader
that peeks before reading, as libnl does, gets ENOBUFS on the read
after each peek, never consumes the message at the head of the queue
and spins forever.

I hit this with "iw dev wlan0 scan" hanging at 100% CPU on an arm64
board with a 6.6 based kernel (iw 5.19 sets SO_RCVBUF to 8KiB). A
kprobe trace showed the scan dump starting while the NEW_SCAN_RESULTS
notification iw had just read was still charged to its socket,
because iw had preempted the sender before netlink_broadcast()
returned.

Check the limit before charging, as before ae8f160e7eb2, which also
covers the empty socket. netlink_recvmsg() continues a dump only at
or below half of sk_rcvbuf, so the skb is then always queued, and a
dump goes over the limit by at most one skb. Refuse a skb that would
take sk_rmem_alloc past INT_MAX, so the wraparound stays fixed.

Reproduced on net in a KVM guest with a userspace reproducer and the
selftest in the next patch; both pass with this fix.

Fixes: ae8f160e7eb2 ("netlink: Fix wraparounds of sk->sk_rmem_alloc.")
Signed-off-by: Jhonata Poma-Hansen <jhonata.poma@gmail.com>
---
 net/netlink/af_netlink.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index a904dc3bc..4129e93a9 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -2318,9 +2318,13 @@ static int netlink_dump(struct sock *sk, bool lock_taken)
 	if (!skb)
 		goto errout_skb;
 
+	/* Check the limit before charging the skb: netlink_recvmsg() continues
+	 * the dump at or below half of sk_rcvbuf, and the skb must be queued
+	 * then. Keep sk_rmem_alloc at or below INT_MAX.
+	 */
 	rcvbuf = READ_ONCE(sk->sk_rcvbuf);
 	rmem = atomic_add_return(skb->truesize, &sk->sk_rmem_alloc);
-	if (rmem != skb->truesize && rmem >= rcvbuf) {
+	if (rmem - skb->truesize >= rcvbuf || rmem > INT_MAX) {
 		atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
 		goto errout_skb;
 	}

-- 
2.54.0



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH net v2 2/2] selftests: net: netlink-dumps: start a dump with a notification queued
  2026-10-27 14:04 [PATCH net v2 0/2] netlink: fix a dump livelock with a notification queued Jhonata Poma-Hansen via B4 Relay
  2026-10-27 14:04 ` [PATCH net v2 1/2] netlink: check sk_rcvbuf before charging the dump skb Jhonata Poma-Hansen via B4 Relay
@ 2026-10-27 14:04 ` Jhonata Poma-Hansen via B4 Relay
  1 sibling, 0 replies; 4+ messages in thread
From: Jhonata Poma-Hansen via B4 Relay @ 2026-10-27 14:04 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Shuah Khan
  Cc: netdev, linux-kernel, linux-kselftest, Kuniyuki Iwashima,
	Marek Szyprowski, Jhonata Poma-Hansen

From: Jhonata Poma-Hansen <jhonata.poma@gmail.com>

Add a test which starts a link dump on a socket with SO_RCVBUF 2048
while a link notification is still queued, after a large read made the
kernel attempt large dump skbs. It reads like libnl does, peeking
before each read, and expects the dump to complete with a zero status
and at least one link. The notifications come from bringing lo up and
down, so the test runs in its own netns and is skipped without the
privileges to create one.

The test fails without the previous patch.

Signed-off-by: Jhonata Poma-Hansen <jhonata.poma@gmail.com>
---
 tools/testing/selftests/net/netlink-dumps.c | 102 ++++++++++++++++++++++++++++
 1 file changed, 102 insertions(+)

diff --git a/tools/testing/selftests/net/netlink-dumps.c b/tools/testing/selftests/net/netlink-dumps.c
index 51129c564..4a94a2516 100644
--- a/tools/testing/selftests/net/netlink-dumps.c
+++ b/tools/testing/selftests/net/netlink-dumps.c
@@ -2,9 +2,12 @@
 
 #define _GNU_SOURCE
 
+#include <errno.h>
 #include <fcntl.h>
+#include <sched.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/syscall.h>
@@ -260,4 +263,103 @@ TEST(close_with_ref)
 	usleep(100 * 1000);
 }
 
+static int lo_set_up(int sock, bool up)
+{
+	struct ifreq ifr = {};
+
+	strcpy(ifr.ifr_name, "lo");
+	if (ioctl(sock, SIOCGIFFLAGS, &ifr))
+		return -1;
+	if (up)
+		ifr.ifr_flags |= IFF_UP;
+	else
+		ifr.ifr_flags &= ~IFF_UP;
+	return ioctl(sock, SIOCSIFFLAGS, &ifr);
+}
+
+static const struct {
+	struct nlmsghdr nlhdr;
+	struct ifinfomsg ifm;
+} dump_links = {
+	.nlhdr = {
+		.nlmsg_len	= sizeof(dump_links),
+		.nlmsg_type	= RTM_GETLINK,
+		.nlmsg_flags	= NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
+		.nlmsg_seq	= 1,
+	},
+	.ifm = {
+		.ifi_family	= AF_UNSPEC,
+	},
+};
+
+// A dump started while a notification is still queued must make progress
+// for a reader which peeks before reading, like libnl does
+TEST(dump_with_queued_ntf)
+{
+	struct sockaddr_nl addr = {
+		.nl_family	= AF_NETLINK,
+		.nl_groups	= RTMGRP_LINK,
+	};
+	int netlink_sock, inet_sock, i, ret, links = 0;
+	int rcvbuf = 2048;
+	bool done = false;
+	char buf[32768];
+	ssize_t n;
+
+	ret = unshare(CLONE_NEWNET);
+	if (ret && errno == EPERM)
+		SKIP(return, "Needs CAP_SYS_ADMIN for a netns");
+	ASSERT_EQ(ret, 0);
+
+	inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
+	ASSERT_GE(inet_sock, 0);
+	netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	ASSERT_GE(netlink_sock, 0);
+	ASSERT_EQ(setsockopt(netlink_sock, SOL_SOCKET, SO_RCVBUF,
+			     &rcvbuf, sizeof(rcvbuf)), 0);
+	ASSERT_EQ(bind(netlink_sock, (struct sockaddr *)&addr,
+		       sizeof(addr)), 0);
+
+	// A large read makes the kernel attempt large dump skbs
+	ASSERT_EQ(lo_set_up(inet_sock, true), 0);
+	n = recv(netlink_sock, buf, sizeof(buf), 0);
+	ASSERT_GE(n, (ssize_t)sizeof(struct nlmsghdr));
+
+	// Leave one notification queued, then start the dump
+	ASSERT_EQ(lo_set_up(inet_sock, false), 0);
+	n = send(netlink_sock, &dump_links, sizeof(dump_links), 0);
+	ASSERT_EQ(n, sizeof(dump_links));
+
+	for (i = 0; i < 100 && !done; i++) {
+		struct nlmsghdr *nlh;
+
+		n = recv(netlink_sock, buf, sizeof(buf),
+			 MSG_PEEK | MSG_TRUNC | MSG_DONTWAIT);
+		if (n < 0)
+			continue;
+		n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
+		if (n < 0)
+			continue;
+
+		for (nlh = (struct nlmsghdr *)buf; NLMSG_OK(nlh, n);
+		     nlh = NLMSG_NEXT(nlh, n)) {
+			if (nlh->nlmsg_seq != dump_links.nlhdr.nlmsg_seq)
+				continue;
+			if (nlh->nlmsg_type == NLMSG_ERROR)
+				EXPECT_EQ(*(int *)NLMSG_DATA(nlh), 0);
+			if (nlh->nlmsg_type == RTM_NEWLINK)
+				links++;
+			if (nlh->nlmsg_type == NLMSG_DONE) {
+				EXPECT_EQ(*(int *)NLMSG_DATA(nlh), 0);
+				done = true;
+			}
+		}
+	}
+	EXPECT_TRUE(done);
+	EXPECT_GE(links, 1);
+
+	close(netlink_sock);
+	close(inet_sock);
+}
+
 TEST_HARNESS_MAIN

-- 
2.54.0



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH net v2 1/2] netlink: check sk_rcvbuf before charging the dump skb
  2026-10-27 14:04 ` [PATCH net v2 1/2] netlink: check sk_rcvbuf before charging the dump skb Jhonata Poma-Hansen via B4 Relay
@ 2026-10-27 16:17   ` Eric Dumazet
  0 siblings, 0 replies; 4+ messages in thread
From: Eric Dumazet @ 2026-10-27 16:17 UTC (permalink / raw)
  To: jhonata.poma
  Cc: David S. Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Shuah Khan, netdev, linux-kernel, linux-kselftest,
	Kuniyuki Iwashima, Marek Szyprowski

Le mar. 27 oct. 2026 à 15:04, Jhonata Poma-Hansen via B4 Relay
<devnull+jhonata.poma.gmail.com@kernel.org> a écrit :
>
> From: Jhonata Poma-Hansen <jhonata.poma@gmail.com>
>
> Since commit ae8f160e7eb2 ("netlink: Fix wraparounds of
> sk->sk_rmem_alloc."), netlink_dump() charges the dump skb first and
> queues it only if sk_rmem_alloc is still below sk_rcvbuf. Commit
> a215b5723922 ("netlink: make sure we allow at least one dump skb")
> added an exception for an empty socket.
>
> A dump that starts while something else is still charged to a socket
> with a small receive buffer fails with ENOBUFS and stays running.
> Every recvmsg() retries it, fails again and sets sk_err, so a reader
> that peeks before reading, as libnl does, gets ENOBUFS on the read
> after each peek, never consumes the message at the head of the queue
> and spins forever.

Reviewed-by: Eric Dumazet <edumazet@kernel.org>

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-10-27 16:17 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-27 14:04 [PATCH net v2 0/2] netlink: fix a dump livelock with a notification queued Jhonata Poma-Hansen via B4 Relay
2026-10-27 14:04 ` [PATCH net v2 1/2] netlink: check sk_rcvbuf before charging the dump skb Jhonata Poma-Hansen via B4 Relay
2026-10-27 16:17   ` Eric Dumazet
2026-10-27 14:04 ` [PATCH net v2 2/2] selftests: net: netlink-dumps: start a dump with a notification queued Jhonata Poma-Hansen via B4 Relay

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®