aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2012-04-05 18:17:46 -0400
committerDavid S. Miller <davem@davemloft.net>2012-04-06 04:21:06 -0400
commit4a7e7c2ad540e54c75489a70137bf0ec15d3a127 (patch)
tree6e4b141c33e96f807e3d85bfe217bb5a3c8bcf0a /net
parente34fac1c2e9ec531c2d63a5e3aa9a6d0ef36a1d3 (diff)
netlink: fix races after skb queueing
As soon as an skb is queued into socket receive_queue, another thread can consume it, so we are not allowed to reference skb anymore, or risk use after free. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/netlink/af_netlink.c24
1 files changed, 13 insertions, 11 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 32bb75324e76..faa48f70b7c9 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -829,12 +829,19 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb,
829 return 0; 829 return 0;
830} 830}
831 831
832int netlink_sendskb(struct sock *sk, struct sk_buff *skb) 832static int __netlink_sendskb(struct sock *sk, struct sk_buff *skb)
833{ 833{
834 int len = skb->len; 834 int len = skb->len;
835 835
836 skb_queue_tail(&sk->sk_receive_queue, skb); 836 skb_queue_tail(&sk->sk_receive_queue, skb);
837 sk->sk_data_ready(sk, len); 837 sk->sk_data_ready(sk, len);
838 return len;
839}
840
841int netlink_sendskb(struct sock *sk, struct sk_buff *skb)
842{
843 int len = __netlink_sendskb(sk, skb);
844
838 sock_put(sk); 845 sock_put(sk);
839 return len; 846 return len;
840} 847}
@@ -957,8 +964,7 @@ static int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb)
957 if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && 964 if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf &&
958 !test_bit(0, &nlk->state)) { 965 !test_bit(0, &nlk->state)) {
959 skb_set_owner_r(skb, sk); 966 skb_set_owner_r(skb, sk);
960 skb_queue_tail(&sk->sk_receive_queue, skb); 967 __netlink_sendskb(sk, skb);
961 sk->sk_data_ready(sk, skb->len);
962 return atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1); 968 return atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1);
963 } 969 }
964 return -1; 970 return -1;
@@ -1698,10 +1704,8 @@ static int netlink_dump(struct sock *sk)
1698 1704
1699 if (sk_filter(sk, skb)) 1705 if (sk_filter(sk, skb))
1700 kfree_skb(skb); 1706 kfree_skb(skb);
1701 else { 1707 else
1702 skb_queue_tail(&sk->sk_receive_queue, skb); 1708 __netlink_sendskb(sk, skb);
1703 sk->sk_data_ready(sk, skb->len);
1704 }
1705 return 0; 1709 return 0;
1706 } 1710 }
1707 1711
@@ -1715,10 +1719,8 @@ static int netlink_dump(struct sock *sk)
1715 1719
1716 if (sk_filter(sk, skb)) 1720 if (sk_filter(sk, skb))
1717 kfree_skb(skb); 1721 kfree_skb(skb);
1718 else { 1722 else
1719 skb_queue_tail(&sk->sk_receive_queue, skb); 1723 __netlink_sendskb(sk, skb);
1720 sk->sk_data_ready(sk, skb->len);
1721 }
1722 1724
1723 if (cb->done) 1725 if (cb->done)
1724 cb->done(cb); 1726 cb->done(cb);