mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
tproxy: fix hash locking issue when using port redirection in __inet_inherit_port()
When __inet_inherit_port() is called on a tproxy connection the wrong locks are held for the inet_bind_bucket it is added to. __inet_inherit_port() made an implicit assumption that the listener's port number (and thus its bind bucket). Unfortunately, if you're using the TPROXY target to redirect skbs to a transparent proxy that assumption is not true anymore and things break. This patch adds code to __inet_inherit_port() so that it can handle this case by looking up or creating a new bind bucket for the child socket and updates callers of __inet_inherit_port() to gracefully handle __inet_inherit_port() failing. Reported by and original patch from Stephen Buck <[email protected]>. See http://marc.info/?t=128169268200001&r=1&w=2 for the original discussion. Signed-off-by: KOVACS Krisztian <[email protected]> Signed-off-by: Patrick McHardy <[email protected]>
This commit is contained in:
parent
6006db84a9
commit
093d282321
6 changed files with 56 additions and 16 deletions
|
|
@ -392,7 +392,7 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb,
|
|||
|
||||
newsk = dccp_create_openreq_child(sk, req, skb);
|
||||
if (newsk == NULL)
|
||||
goto exit;
|
||||
goto exit_nonewsk;
|
||||
|
||||
sk_setup_caps(newsk, dst);
|
||||
|
||||
|
|
@ -409,16 +409,20 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb,
|
|||
|
||||
dccp_sync_mss(newsk, dst_mtu(dst));
|
||||
|
||||
if (__inet_inherit_port(sk, newsk) < 0) {
|
||||
sock_put(newsk);
|
||||
goto exit;
|
||||
}
|
||||
__inet_hash_nolisten(newsk, NULL);
|
||||
__inet_inherit_port(sk, newsk);
|
||||
|
||||
return newsk;
|
||||
|
||||
exit_overflow:
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
|
||||
exit_nonewsk:
|
||||
dst_release(dst);
|
||||
exit:
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
|
||||
dst_release(dst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -564,7 +564,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
|
|||
|
||||
newsk = dccp_create_openreq_child(sk, req, skb);
|
||||
if (newsk == NULL)
|
||||
goto out;
|
||||
goto out_nonewsk;
|
||||
|
||||
/*
|
||||
* No need to charge this sock to the relevant IPv6 refcnt debug socks
|
||||
|
|
@ -632,18 +632,22 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
|
|||
newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
|
||||
newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
|
||||
|
||||
if (__inet_inherit_port(sk, newsk) < 0) {
|
||||
sock_put(newsk);
|
||||
goto out;
|
||||
}
|
||||
__inet6_hash(newsk, NULL);
|
||||
__inet_inherit_port(sk, newsk);
|
||||
|
||||
return newsk;
|
||||
|
||||
out_overflow:
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
|
||||
out_nonewsk:
|
||||
dst_release(dst);
|
||||
out:
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
|
||||
if (opt != NULL && opt != np->opt)
|
||||
sock_kfree_s(sk, opt, opt->tot_len);
|
||||
dst_release(dst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue