diff options
author | David Ahern <dsa@cumulusnetworks.com> | 2016-08-24 00:05:27 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-08-24 02:11:36 -0400 |
commit | d7226c7a4dd19929d6df4ae04698da2fcf6f875a (patch) | |
tree | 33b158ecdb0ed30ca22110588dc368b91a10f9ed | |
parent | 7b996243fab46092fb3a29c773c54be8152366e4 (diff) |
net: diag: Fix refcnt leak in error path destroying socket
inet_diag_find_one_icsk takes a reference to a socket that is not
released if sock_diag_destroy returns an error. Fix by changing
tcp_diag_destroy to manage the refcnt for all cases and remove
the sock_put calls from tcp_abort.
Fixes: c1e64e298b8ca ("net: diag: Support destroying TCP sockets")
Reported-by: Lorenzo Colitti <lorenzo@google.com>
Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv4/tcp.c | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_diag.c | 7 |
2 files changed, 6 insertions, 3 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 032a96d78c99..ffbb218de520 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -3193,7 +3193,6 @@ int tcp_abort(struct sock *sk, int err) | |||
3193 | local_bh_enable(); | 3193 | local_bh_enable(); |
3194 | return 0; | 3194 | return 0; |
3195 | } | 3195 | } |
3196 | sock_gen_put(sk); | ||
3197 | return -EOPNOTSUPP; | 3196 | return -EOPNOTSUPP; |
3198 | } | 3197 | } |
3199 | 3198 | ||
@@ -3222,7 +3221,6 @@ int tcp_abort(struct sock *sk, int err) | |||
3222 | bh_unlock_sock(sk); | 3221 | bh_unlock_sock(sk); |
3223 | local_bh_enable(); | 3222 | local_bh_enable(); |
3224 | release_sock(sk); | 3223 | release_sock(sk); |
3225 | sock_put(sk); | ||
3226 | return 0; | 3224 | return 0; |
3227 | } | 3225 | } |
3228 | EXPORT_SYMBOL_GPL(tcp_abort); | 3226 | EXPORT_SYMBOL_GPL(tcp_abort); |
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index 4d610934fb39..a748c74aa8b7 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c | |||
@@ -54,11 +54,16 @@ static int tcp_diag_destroy(struct sk_buff *in_skb, | |||
54 | { | 54 | { |
55 | struct net *net = sock_net(in_skb->sk); | 55 | struct net *net = sock_net(in_skb->sk); |
56 | struct sock *sk = inet_diag_find_one_icsk(net, &tcp_hashinfo, req); | 56 | struct sock *sk = inet_diag_find_one_icsk(net, &tcp_hashinfo, req); |
57 | int err; | ||
57 | 58 | ||
58 | if (IS_ERR(sk)) | 59 | if (IS_ERR(sk)) |
59 | return PTR_ERR(sk); | 60 | return PTR_ERR(sk); |
60 | 61 | ||
61 | return sock_diag_destroy(sk, ECONNABORTED); | 62 | err = sock_diag_destroy(sk, ECONNABORTED); |
63 | |||
64 | sock_gen_put(sk); | ||
65 | |||
66 | return err; | ||
62 | } | 67 | } |
63 | #endif | 68 | #endif |
64 | 69 | ||