]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
netlink: make sure we allow at least one dump skb
authorJakub Kicinski <kuba@kernel.org>
Fri, 11 Jul 2025 00:11:21 +0000 (17:11 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 17 Jul 2025 16:25:03 +0000 (18:25 +0200)
commit a215b5723922f8099078478122f02100e489cb80 upstream.

Commit under Fixes tightened up the memory accounting for Netlink
sockets. Looks like the accounting is too strict for some existing
use cases, Marek reported issues with nl80211 / WiFi iw CLI.

To reduce number of iterations Netlink dumps try to allocate
messages based on the size of the buffer passed to previous
recvmsg() calls. If user space uses a larger buffer in recvmsg()
than sk_rcvbuf we will allocate an skb we won't be able to queue.

Make sure we always allow at least one skb to be queued.
Same workaround is already present in netlink_attachskb().
Alternative would be to cap the allocation size to
  rcvbuf - rmem_alloc
but as I said, the workaround is already present in other places.

Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Link: https://lore.kernel.org/9794af18-4905-46c6-b12c-365ea2f05858@samsung.com
Fixes: ae8f160e7eb2 ("netlink: Fix wraparounds of sk->sk_rmem_alloc.")
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20250711001121.3649033-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/netlink/af_netlink.c

index 4c7af7f5117ae4838ac648fc5a8ae40623fdf596..e853728e1ff6322eb56dad36f51e3b2c352011ea 100644 (file)
@@ -2186,11 +2186,11 @@ static int netlink_dump(struct sock *sk)
        struct netlink_ext_ack extack = {};
        struct netlink_callback *cb;
        struct sk_buff *skb = NULL;
+       unsigned int rmem, rcvbuf;
        struct nlmsghdr *nlh;
        struct module *module;
        int err = -ENOBUFS;
        int alloc_min_size;
-       unsigned int rmem;
        int alloc_size;
 
        mutex_lock(nlk->cb_mutex);
@@ -2220,8 +2220,9 @@ static int netlink_dump(struct sock *sk)
        if (!skb)
                goto errout_skb;
 
+       rcvbuf = READ_ONCE(sk->sk_rcvbuf);
        rmem = atomic_add_return(skb->truesize, &sk->sk_rmem_alloc);
-       if (rmem >= READ_ONCE(sk->sk_rcvbuf)) {
+       if (rmem != skb->truesize && rmem >= rcvbuf) {
                atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
                goto errout_skb;
        }