diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2012-04-05 18:17:46 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-04-06 04:21:06 -0400 |
commit | 4a7e7c2ad540e54c75489a70137bf0ec15d3a127 (patch) | |
tree | 6e4b141c33e96f807e3d85bfe217bb5a3c8bcf0a /net | |
parent | e34fac1c2e9ec531c2d63a5e3aa9a6d0ef36a1d3 (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.c | 24 |
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 | ||
832 | int netlink_sendskb(struct sock *sk, struct sk_buff *skb) | 832 | static 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 | |||
841 | int 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); |