diff options
author | Eric Dumazet <edumazet@google.com> | 2015-01-21 06:45:42 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-01-26 03:44:08 -0500 |
commit | 1dc7b90f7cd050ef6d5e511e652347e52874469c (patch) | |
tree | 5362ed5e14526d303ba83fc1f596f69fb63933ba /net/ipv6 | |
parent | 607954b084d4ad5e6a2e0f795de7803d9c6ae37f (diff) |
ipv6: tcp: fix race in IPV6_2292PKTOPTIONS
IPv6 TCP sockets store in np->pktoptions skbs, and use skb_set_owner_r()
to charge the skb to socket.
It means that destructor must be called while socket is locked.
Therefore, we cannot use skb_get() or atomic_inc(&skb->users)
to protect ourselves : kfree_skb() might race with other users
manipulating sk->sk_forward_alloc
Fix this race by holding socket lock for the duration of
ip6_datagram_recv_ctl()
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 8 |
1 files changed, 2 insertions, 6 deletions
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 66980d8d98d1..8d766d9100cb 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -996,13 +996,9 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
996 | lock_sock(sk); | 996 | lock_sock(sk); |
997 | skb = np->pktoptions; | 997 | skb = np->pktoptions; |
998 | if (skb) | 998 | if (skb) |
999 | atomic_inc(&skb->users); | ||
1000 | release_sock(sk); | ||
1001 | |||
1002 | if (skb) { | ||
1003 | ip6_datagram_recv_ctl(sk, &msg, skb); | 999 | ip6_datagram_recv_ctl(sk, &msg, skb); |
1004 | kfree_skb(skb); | 1000 | release_sock(sk); |
1005 | } else { | 1001 | if (!skb) { |
1006 | if (np->rxopt.bits.rxinfo) { | 1002 | if (np->rxopt.bits.rxinfo) { |
1007 | struct in6_pktinfo src_info; | 1003 | struct in6_pktinfo src_info; |
1008 | src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : | 1004 | src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : |