mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
netlink: check sk_rcvbuf before charging the dump skb
Since commitae8f160e7e("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. Commita215b57239("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 beforeae8f160e7e, 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:ae8f160e7e("netlink: Fix wraparounds of sk->sk_rmem_alloc.") Signed-off-by: Jhonata Poma-Hansen <jhonata.poma@gmail.com> Reviewed-by: Eric Dumazet <edumazet@kernel.org> Link: https://patch.msgid.link/20261027-netlink-dump-livelock-v2-1-c4bb05352a33@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
c9897252a6
commit
b45d37740c
|
|
@ -2322,9 +2322,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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user