Skip to content

Commit 6962946

Browse files
Eric Dumazetdavem330
Eric Dumazet
authored andcommitted
udp: properly cope with csum errors
Dmitry reported that UDP sockets being destroyed would trigger the WARN_ON(atomic_read(&sk->sk_rmem_alloc)); in inet_sock_destruct() It turns out we do not properly destroy skb(s) that have wrong UDP checksum. Thanks again to syzkaller team. Fixes : 7c13f97 ("udp: do fwd memory scheduling on dequeue") Reported-by: Dmitry Vyukov <[email protected]> Signed-off-by: Eric Dumazet <[email protected]> Cc: Paolo Abeni <[email protected]> Cc: Hannes Frederic Sowa <[email protected]> Acked-by: Paolo Abeni <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 6a413e2 commit 6962946

File tree

4 files changed

+11
-5
lines changed

4 files changed

+11
-5
lines changed

include/net/sock.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2006,7 +2006,9 @@ void sk_reset_timer(struct sock *sk, struct timer_list *timer,
20062006
void sk_stop_timer(struct sock *sk, struct timer_list *timer);
20072007

20082008
int __sk_queue_drop_skb(struct sock *sk, struct sk_buff *skb,
2009-
unsigned int flags);
2009+
unsigned int flags,
2010+
void (*destructor)(struct sock *sk,
2011+
struct sk_buff *skb));
20102012
int __sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
20112013
int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
20122014

net/core/datagram.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,9 @@ void __skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb, int len)
332332
EXPORT_SYMBOL(__skb_free_datagram_locked);
333333

334334
int __sk_queue_drop_skb(struct sock *sk, struct sk_buff *skb,
335-
unsigned int flags)
335+
unsigned int flags,
336+
void (*destructor)(struct sock *sk,
337+
struct sk_buff *skb))
336338
{
337339
int err = 0;
338340

@@ -342,6 +344,8 @@ int __sk_queue_drop_skb(struct sock *sk, struct sk_buff *skb,
342344
if (skb == skb_peek(&sk->sk_receive_queue)) {
343345
__skb_unlink(skb, &sk->sk_receive_queue);
344346
atomic_dec(&skb->users);
347+
if (destructor)
348+
destructor(sk, skb);
345349
err = 0;
346350
}
347351
spin_unlock_bh(&sk->sk_receive_queue.lock);
@@ -375,7 +379,7 @@ EXPORT_SYMBOL(__sk_queue_drop_skb);
375379

376380
int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags)
377381
{
378-
int err = __sk_queue_drop_skb(sk, skb, flags);
382+
int err = __sk_queue_drop_skb(sk, skb, flags, NULL);
379383

380384
kfree_skb(skb);
381385
sk_mem_reclaim_partial(sk);

net/ipv4/udp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1501,7 +1501,7 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock,
15011501
return err;
15021502

15031503
csum_copy_err:
1504-
if (!__sk_queue_drop_skb(sk, skb, flags)) {
1504+
if (!__sk_queue_drop_skb(sk, skb, flags, udp_skb_destructor)) {
15051505
UDP_INC_STATS(sock_net(sk), UDP_MIB_CSUMERRORS, is_udplite);
15061506
UDP_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
15071507
}

net/ipv6/udp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
441441
return err;
442442

443443
csum_copy_err:
444-
if (!__sk_queue_drop_skb(sk, skb, flags)) {
444+
if (!__sk_queue_drop_skb(sk, skb, flags, udp_skb_destructor)) {
445445
if (is_udp4) {
446446
UDP_INC_STATS(sock_net(sk),
447447
UDP_MIB_CSUMERRORS, is_udplite);

0 commit comments

Comments
 (0)