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: c1e64e298b ("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>
This commit is contained in:
David Ahern 2016-08-23 21:05:27 -07:00 committed by David S. Miller
parent 7b996243fa
commit d7226c7a4d
2 changed files with 6 additions and 3 deletions

View File

@ -3193,7 +3193,6 @@ int tcp_abort(struct sock *sk, int err)
local_bh_enable(); local_bh_enable();
return 0; return 0;
} }
sock_gen_put(sk);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
@ -3222,7 +3221,6 @@ int tcp_abort(struct sock *sk, int err)
bh_unlock_sock(sk); bh_unlock_sock(sk);
local_bh_enable(); local_bh_enable();
release_sock(sk); release_sock(sk);
sock_put(sk);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(tcp_abort); EXPORT_SYMBOL_GPL(tcp_abort);

View File

@ -54,11 +54,16 @@ static int tcp_diag_destroy(struct sk_buff *in_skb,
{ {
struct net *net = sock_net(in_skb->sk); struct net *net = sock_net(in_skb->sk);
struct sock *sk = inet_diag_find_one_icsk(net, &tcp_hashinfo, req); struct sock *sk = inet_diag_find_one_icsk(net, &tcp_hashinfo, req);
int err;
if (IS_ERR(sk)) if (IS_ERR(sk))
return PTR_ERR(sk); return PTR_ERR(sk);
return sock_diag_destroy(sk, ECONNABORTED); err = sock_diag_destroy(sk, ECONNABORTED);
sock_gen_put(sk);
return err;
} }
#endif #endif