llc: Fix race condition in llc_ui_recvmsg
Radu Iliescu [Thu, 19 Jan 2012 03:57:57 +0000 (03:57 +0000)]
There is a race on sk_receive_queue between llc_ui_recvmsg and
sock_queue_rcv_skb.

Our current solution is to protect skb_eat in llc_ui_recvmsg
with the queue spinlock.

Signed-off-by: Radu Iliescu <riliescu@ixiacom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

net/llc/af_llc.c

index a18e6c3..b9bef2c 100644 (file)
@@ -713,6 +713,7 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
        struct sk_buff *skb = NULL;
        struct sock *sk = sock->sk;
        struct llc_sock *llc = llc_sk(sk);
+       unsigned long cpu_flags;
        size_t copied = 0;
        u32 peek_seq = 0;
        u32 *seq;
@@ -838,7 +839,9 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
                        goto copy_uaddr;
 
                if (!(flags & MSG_PEEK)) {
+                       spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
                        sk_eat_skb(sk, skb, 0);
+                       spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
                        *seq = 0;
                }
 
@@ -859,7 +862,9 @@ copy_uaddr:
                llc_cmsg_rcv(msg, skb);
 
        if (!(flags & MSG_PEEK)) {
+                       spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
                        sk_eat_skb(sk, skb, 0);
+                       spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
                        *seq = 0;
        }