Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pppoe: Fix memory leak in pppoe_sendmsg()

syzbot reports a memory leak in pppoe_sendmsg [1].

The problem is in the pppoe_recvmsg() function that handles errors
in the wrong order. For the skb_recv_datagram() function, check
the pointer to skb for NULL first, and then check the 'error' variable,
because the skb_recv_datagram() function can set 'error'
to -EAGAIN in a loop but return a correct pointer to socket buffer
after a number of attempts, though 'error' remains set to -EAGAIN.

skb_recv_datagram
__skb_recv_datagram // Loop. if (err == -EAGAIN) then
// go to the next loop iteration
__skb_try_recv_datagram // if (skb != NULL) then return 'skb'
// else if a signal is received then
// return -EAGAIN

Found by InfoTeCS on behalf of Linux Verification Center
(linuxtesting.org) with Syzkaller.

Link: https://syzkaller.appspot.com/bug?extid=6bdfd184eac7709e5cc9 [1]

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: syzbot+6bdfd184eac7709e5cc9@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=6bdfd184eac7709e5cc9
Signed-off-by: Gavrilov Ilia <Ilia.Gavrilov@infotecs.ru>
Reviewed-by: Guillaume Nault <gnault@redhat.com>
Link: https://lore.kernel.org/r/20240214085814.3894917-1-Ilia.Gavrilov@infotecs.ru
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Gavrilov Ilia and committed by
Jakub Kicinski
dc34ebd5 4e45170d

+9 -14
+9 -14
drivers/net/ppp/pppoe.c
··· 1007 1007 struct sk_buff *skb; 1008 1008 int error = 0; 1009 1009 1010 - if (sk->sk_state & PPPOX_BOUND) { 1011 - error = -EIO; 1012 - goto end; 1013 - } 1010 + if (sk->sk_state & PPPOX_BOUND) 1011 + return -EIO; 1014 1012 1015 1013 skb = skb_recv_datagram(sk, flags, &error); 1016 - if (error < 0) 1017 - goto end; 1014 + if (!skb) 1015 + return error; 1018 1016 1019 - if (skb) { 1020 - total_len = min_t(size_t, total_len, skb->len); 1021 - error = skb_copy_datagram_msg(skb, 0, m, total_len); 1022 - if (error == 0) { 1023 - consume_skb(skb); 1024 - return total_len; 1025 - } 1017 + total_len = min_t(size_t, total_len, skb->len); 1018 + error = skb_copy_datagram_msg(skb, 0, m, total_len); 1019 + if (error == 0) { 1020 + consume_skb(skb); 1021 + return total_len; 1026 1022 } 1027 1023 1028 1024 kfree_skb(skb); 1029 - end: 1030 1025 return error; 1031 1026 } 1032 1027