* [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
` (2 more replies)
0 siblings, 3 replies; 7+ 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] 7+ 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-30 2:05 ` netdev-bot+sashiko 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 2026-10-29 16:30 ` [PATCH net v2 0/2] netlink: fix a dump livelock " patchwork-bot+netdevbpf 2 siblings, 2 replies; 7+ 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 related [flat|nested] 7+ 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 2026-10-30 2:05 ` netdev-bot+sashiko 1 sibling, 0 replies; 7+ 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] 7+ 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 @ 2026-10-30 2:05 ` netdev-bot+sashiko 1 sibling, 0 replies; 7+ messages in thread From: netdev-bot+sashiko @ 2026-10-30 2:05 UTC (permalink / raw) To: jhonata.poma Cc: davem, edumazet, kuba, pabeni, horms, shuah, netdev, linux-kernel, linux-kselftest, kuniyu, m.szyprowski Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider. Critical: 0 · High: 1 · Medium: 0 (1) · Low: 2 If you believe none of the issues are legitimate, please reply to each issue of Medium severity or higher and explain why the AI is wrong. If any of them are legitimate and you plan to respin, please let patchwork know by including "pw-bot: cr" as a separate line at the end of your reply (one such reply per series is enough). - [High] In netlink_dump() (net/netlink/af_netlink.c:2327), a dump can still fail to start because of memory charged by skbs that have… - [Low] The new comment in netlink_dump() ("netlink_recvmsg() continues the dump at or below half of sk_rcvbuf, and the skb must be queued… - [Low] The dump_extack selftest (tools/testing/selftests/net/netlink- dumps.c, comment at lines 158-161, branch at 162-163) still describes… Pre-existing issues: - [Medium] This problem wasn't introduced by this patch, but it has the same trigger the commit describes. -- netlink: check sk_rcvbuf before charging the dump skb This patch changes netlink_dump() so that sk_rmem_alloc is compared against sk_rcvbuf before the new dump skb is charged instead of after. A dump can then start while something else is still charged to the socket. It also refuses an skb that would push sk_rmem_alloc past INT_MAX, so the wraparound fix from ae8f160e7eb2 still holds. > diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c > index a904dc3bcad6b..4129e93a9ff0c 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. > + */ [Severity: Low] Is "the skb must be queued then" guaranteed? netlink_recvmsg() checks its gate without any lock that keeps senders out: netlink_recvmsg() { ... if (READ_ONCE(nlk->cb_running) && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) { ret = netlink_dump(sk, false); ... } netlink_dump() then takes nl_cb_mutex and calls alloc_skb(GFP_KERNEL). Both can sleep before the skb is charged. Several things can happen in that window: - netlink_broadcast_deliver() fills the socket up to rcvbuf, or puts an skb of any truesize into an empty socket. - A rejected broadcast briefly over-charges before its atomic_sub(). - setsockopt(SO_RCVBUF) shrinks rcvbuf. - A second reader's dump skb gets queued first. Any of these can make rmem - skb->truesize >= rcvbuf true after the gate passed. netlink_recvmsg() then sets sk_err while the dump keeps running. A later read seems to resume the dump, so this looks transient. The same races also existed before this patch. Could the comment and the commit message ("so the skb is then always queued") be softened to say this only holds when nothing else charges the socket concurrently? Separately, the plain read of sk->sk_rcvbuf in that gate races with the WRITE_ONCE() in sock_setsockopt(). That part is pre-existing. > 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) { [Severity: High] Can the dump still get stuck when the stale charge alone is at least sk_rcvbuf? The commit message says this fixes "A dump that starts while something else is still charged to a socket with a small receive buffer fails with ENOBUFS and stays running". This check only covers a stale charge that is below sk_rcvbuf. netlink_broadcast_deliver() accepts a notification of any truesize into a socket with nothing charged, through rmem == skb->truesize. The selftest in the next patch uses SO_RCVBUF 2048, which gives sk_rcvbuf 4096. With a buffer that small, one rtnetlink or genetlink notification can have truesize >= sk_rcvbuf. do_one_broadcast() gives the first listener the original skb through p->skb2 = skb_get(p->skb). After the reader dequeues it, the charge stays on the socket until netlink_broadcast_filtered() calls consume_skb(skb). This is the preempted-sender state from the commit message. The broadcaster can also sleep in skb_clone() for later listeners. The reader then sends a dump request: __netlink_dump_start() WRITE_ONCE(nlk->cb_running, true); netlink_dump() rmem - skb->truesize >= rcvbuf -> -ENOBUFS return ret; /* cb_running is still true */ The ack goes through netlink_rcv_skb()->netlink_ack()->netlink_unicast() ->netlink_attachskb(). There rmem = stale + ack truesize, which is above rcvbuf and not equal to the ack truesize, so the ack is dropped. netlink_overrun() then sets sk_err, or does nothing if NETLINK_NO_ENOBUFS is set. When the broadcaster later drops its reference, sock_rfree() only uncharges. It does not wake the reader or call netlink_dump(). netlink_recvmsg() resumes a dump only after skb_recv_datagram() returns an skb, and the queue is empty. So: - the next recvmsg() returns sk_err; - the one after that blocks; - every later dump request gets -EBUSY from __netlink_dump_start(), until some unrelated message arrives. Would it be more robust to never fail the first netlink_dump() call from __netlink_dump_start() because of rcvbuf? Another option is to clear cb_running, or arrange a resume, when that call fails. [Severity: Low] This isn't a bug, but the dump_extack test in tools/testing/selftests/net/netlink-dumps.c still describes the old behaviour: dump_extack() { ... /* Once we fill the buffer we'll see one ENOBUFS followed * by a number of EBUSYs. Then the last recv() will finally * trigger and complete the dump. */ if (ret == FOUND_ERR && (ea.err == ENOBUFS || ea.err == EBUSY)) continue; ... } With this check, the bad RTM_GETNEIGH dumps keep queueing DONE+extack skbs as long as the charge before each one is below sk_rcvbuf. So sk_rmem_alloc ends up in [rcvbuf, rcvbuf + truesize). The ENOBUFS ack for the next dump is then refused in netlink_attachskb(), and netlink_overrun() sets NETLINK_S_CONGESTED. Because of that bit, the later EBUSY acks are dropped as well. The ENOBUFS/EBUSY branch above can no longer be reached. Should the comment and the branch be updated, perhaps to check the new behaviour instead? The next patch in the series only adds a new test and leaves dump_extack unchanged. [Severity: Medium] This isn't a bug introduced by this patch, but the same trigger can also stall a dump after it has started. netlink_recvmsg() is the only place that continues a running dump: netlink_recvmsg() { ... skb_free_datagram(sk, skb); if (READ_ONCE(nlk->cb_running) && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) { ret = netlink_dump(sk, false); ... } The sk_rmem_alloc value read there still includes the charge of a notification that was dequeued but is held through skb_get() in do_one_broadcast(). That charge stays until consume_skb(skb) in netlink_broadcast_filtered(). Suppose that notification's truesize is between rcvbuf/2 and rcvbuf: 1. The dump starts normally under the new check. 2. The reader consumes the first dump skb. 3. The gate sees the stale charge above rcvbuf/2 and does not continue the dump. 4. The next recvmsg() blocks on an empty queue. 5. netlink_skb_destructor()->sock_rfree() later uncharges, but neither wakes the reader nor calls netlink_dump(). A dump that needs several skbs, such as a scan dump, then stalls until some unrelated message arrives. Could this be handled together with the start-of-dump case? The gate and the destructor are not changed here, and they behaved the same way before ae8f160e7eb2. > atomic_sub(skb->truesize, &sk->sk_rmem_alloc); > goto errout_skb; > } -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261027-netlink-dump-livelock-v2-0-c4bb05352a33%40gmail.com ^ permalink raw reply [flat|nested] 7+ 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 2026-10-30 2:05 ` netdev-bot+sashiko 2026-10-29 16:30 ` [PATCH net v2 0/2] netlink: fix a dump livelock " patchwork-bot+netdevbpf 2 siblings, 1 reply; 7+ 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 related [flat|nested] 7+ messages in thread
* Re: [PATCH net v2 2/2] selftests: net: netlink-dumps: start a dump with a notification queued 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 @ 2026-10-30 2:05 ` netdev-bot+sashiko 0 siblings, 0 replies; 7+ messages in thread From: netdev-bot+sashiko @ 2026-10-30 2:05 UTC (permalink / raw) To: jhonata.poma Cc: davem, edumazet, kuba, pabeni, horms, shuah, netdev, linux-kernel, linux-kselftest, kuniyu, m.szyprowski Thank you for your contribution! Sashiko AI review found more severe issue(s) in other patches of this series. This mail is only an FYI, in case you want to address the nit picks below when you respin. Low priority / nit picks for your consideration: - [Low] Whether dump_with_queued_ntf (tools/testing/selftests/net/netlink-dumps.c) can catch the bug… -- selftests: net: netlink-dumps: start a dump with a notification queued This adds a dump_with_queued_ntf test to netlink-dumps.c. The test starts an RTM_GETLINK dump on a socket with SO_RCVBUF 2048 while an lo link notification is still queued. It reads like libnl does, peeking before each read, and expects the dump to finish with a zero status. > diff --git a/tools/testing/selftests/net/netlink-dumps.c b/tools/testing/selftests/net/netlink-dumps.c > index 51129c564d0a6..4a94a25167e25 100644 > --- a/tools/testing/selftests/net/netlink-dumps.c > +++ b/tools/testing/selftests/net/netlink-dumps.c [ ... ] > @@ -260,4 +263,103 @@ TEST(close_with_ref) [ ... ] > +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; [ ... ] > + // 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)); [Severity: Low] Does this test catch the bug on every kernel config? The commit message says "The test fails without the previous patch". That seems to depend on how much memory the kernel charges for the queued notification, and the test never checks that. With SO_RCVBUF 2048, sk_rcvbuf ends up as 4096. Call the truesize of the queued lo RTM_NEWLINK notification T. Call the truesize of the -ENOBUFS ack that netlink_ack() sends A. The old check in netlink_dump(): rmem != skb->truesize && rmem >= rcvbuf rejects the first large dump skb whenever T > 0. What happens next is decided in netlink_attachskb(): if ((rmem == skb->truesize || rmem <= READ_ONCE(sk->sk_rcvbuf)) && !test_bit(NETLINK_S_CONGESTED, &nlk->state)) { If T + A <= 4096, the ack is queued. The unfixed kernel keeps failing the dump from netlink_recvmsg(), the peek/read loop never sees NLMSG_DONE, and EXPECT_TRUE(done) fails as intended. If T + A > 4096, the ack is dropped and netlink_overrun() is called. Once the test reads the notification, the socket is empty. The old rmem == skb->truesize exception then lets the dump go through, so the test passes on an unfixed kernel. When T >= 4096, the fixed check: if (rmem - skb->truesize >= rcvbuf || rmem > INT_MAX) { also rejects the first skb, so in that case the two kernels behave the same. T looks config dependent. netlink_trim() shrinks the notification with pskb_expand_head() into a kmalloc bucket that has to hold the payload plus skb_shared_info. With the default CONFIG_MAX_SKB_FRAGS=17, the lo notification seems to fit the 2 KiB bucket (T around 2304). With CONFIG_MAX_SKB_FRAGS=45, the larger skb_shared_info appears to push it into the 4 KiB bucket (T around 4352). These byte sizes are estimates, not runtime measurements. The same thing could happen in two other cases. One is if the pskb_expand_head() call in netlink_trim() fails, since it runs without direct reclaim and with __GFP_NORETRY. The other is if the lo notification grows in a future kernel. Would it help to read SO_MEMINFO after lo_set_up(inet_sock, false) and before send()? The test could then skip, or fail, unless SK_MEMINFO_RMEM_ALLOC is non-zero and still leaves room for the ack, for example RMEM_ALLOC <= SK_MEMINFO_RCVBUF / 2. Another option is to pick SO_RCVBUF based on the measured notification size. > + > + for (i = 0; i < 100 && !done; i++) { [ ... ] -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261027-netlink-dump-livelock-v2-0-c4bb05352a33%40gmail.com ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net v2 0/2] netlink: fix a dump livelock 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 ` [PATCH net v2 2/2] selftests: net: netlink-dumps: start a dump with a notification queued Jhonata Poma-Hansen via B4 Relay @ 2026-10-29 16:30 ` patchwork-bot+netdevbpf 2 siblings, 0 replies; 7+ messages in thread From: patchwork-bot+netdevbpf @ 2026-10-29 16:30 UTC (permalink / raw) To: Jhonata Poma-Hansen Cc: davem, edumazet, kuba, pabeni, horms, shuah, netdev, linux-kernel, linux-kselftest, kuniyu, m.szyprowski Hello: This series was applied to netdev/net.git (main) by Jakub Kicinski <kuba@kernel.org>: On Tue, 27 Oct 2026 15:04:00 +0100 you wrote: > 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. > > [...] Here is the summary with links: - [net,v2,1/2] netlink: check sk_rcvbuf before charging the dump skb https://git.kernel.org/netdev/net/c/b45d37740cfb - [net,v2,2/2] selftests: net: netlink-dumps: start a dump with a notification queued https://git.kernel.org/netdev/net/c/e615d0a8b201 You are awesome, thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-10-30 2:05 UTC | newest] Thread overview: 7+ 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-30 2:05 ` netdev-bot+sashiko 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 2026-10-30 2:05 ` netdev-bot+sashiko 2026-10-29 16:30 ` [PATCH net v2 0/2] netlink: fix a dump livelock " patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox