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

phonet/pep: fix racy skb_queue_empty() use

The receive queues are protected by their respective spin-lock, not
the socket lock. This could lead to skb_peek() unexpectedly
returning NULL or a pointer to an already dequeued socket buffer.

Fixes: 9641458d3ec4 ("Phonet: Pipe End Point for Phonet Pipes protocol")
Signed-off-by: Rémi Denis-Courmont <courmisch@gmail.com>
Link: https://lore.kernel.org/r/20240218081214.4806-2-remi@remlab.net
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Rémi Denis-Courmont and committed by
Paolo Abeni
7d2a894d 3b2d9bc4

+32 -9
+32 -9
net/phonet/pep.c
··· 917 917 return 0; 918 918 } 919 919 920 + static unsigned int pep_first_packet_length(struct sock *sk) 921 + { 922 + struct pep_sock *pn = pep_sk(sk); 923 + struct sk_buff_head *q; 924 + struct sk_buff *skb; 925 + unsigned int len = 0; 926 + bool found = false; 927 + 928 + if (sock_flag(sk, SOCK_URGINLINE)) { 929 + q = &pn->ctrlreq_queue; 930 + spin_lock_bh(&q->lock); 931 + skb = skb_peek(q); 932 + if (skb) { 933 + len = skb->len; 934 + found = true; 935 + } 936 + spin_unlock_bh(&q->lock); 937 + } 938 + 939 + if (likely(!found)) { 940 + q = &sk->sk_receive_queue; 941 + spin_lock_bh(&q->lock); 942 + skb = skb_peek(q); 943 + if (skb) 944 + len = skb->len; 945 + spin_unlock_bh(&q->lock); 946 + } 947 + 948 + return len; 949 + } 950 + 920 951 static int pep_ioctl(struct sock *sk, int cmd, int *karg) 921 952 { 922 953 struct pep_sock *pn = pep_sk(sk); ··· 960 929 break; 961 930 } 962 931 963 - lock_sock(sk); 964 - if (sock_flag(sk, SOCK_URGINLINE) && 965 - !skb_queue_empty(&pn->ctrlreq_queue)) 966 - *karg = skb_peek(&pn->ctrlreq_queue)->len; 967 - else if (!skb_queue_empty(&sk->sk_receive_queue)) 968 - *karg = skb_peek(&sk->sk_receive_queue)->len; 969 - else 970 - *karg = 0; 971 - release_sock(sk); 932 + *karg = pep_first_packet_length(sk); 972 933 ret = 0; 973 934 break; 974 935