]> git.hungrycats.org Git - linux/commitdiff
[NET]: In sock_queue_rcv_skb(), do not deref skb->len after it is queued to the socket.
authorDavid S. Miller <davem@nuts.ninka.net>
Mon, 24 Nov 2003 11:44:51 +0000 (03:44 -0800)
committerLinus Torvalds <torvalds@home.osdl.org>
Mon, 24 Nov 2003 11:44:51 +0000 (03:44 -0800)
In implementations that use no socket locking, such as RAW sockets,
once we queue the SKB to the socket another cpu can remove the SKB
from the socket queue and free up the SKB making the skb->len access
touch freed memory.

Based upon a report from Burton Windle, kernel bugzilla #937

include/net/sock.h

index 22801b214d98227080251100ac5cf3c0b42b7a27..ac2eccb7ff9aa77caf177961a9f20ad597a8dbbd 100644 (file)
@@ -917,6 +917,7 @@ static inline void skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
 static inline int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
        int err = 0;
+       int skb_len;
 
        /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
           number of warnings when compiling with -W --ANK
@@ -937,9 +938,18 @@ static inline int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 
        skb->dev = NULL;
        skb_set_owner_r(skb, sk);
+
+       /* Cache the SKB length before we tack it onto the receive
+        * queue.  Once it is added it no longer belongs to us and
+        * may be freed by other threads of control pulling packets
+        * from the queue.
+        */
+       skb_len = skb->len;
+
        skb_queue_tail(&sk->sk_receive_queue, skb);
+
        if (!sock_flag(sk, SOCK_DEAD))
-               sk->sk_data_ready(sk, skb->len);
+               sk->sk_data_ready(sk, skb_len);
 out:
        return err;
 }