From de34ed91c4ffa4727964a832c46e624dd1495cf5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 30 Apr 2007 14:51:58 -0700 Subject: [UDP]: Do not allow specific bind when wildcard bind exists. When allocating local ports, do not allow a bind to a port with a specific local address when a bind to that port with a wildcard local address already exists. Noticed by Linus. Signed-off-by: David S. Miller --- net/ipv4/udp.c | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index db313d964884..113e0c4c8a92 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -203,6 +203,13 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, result = sysctl_local_port_range[0] + ((result - sysctl_local_port_range[0]) & (UDP_HTABLE_SIZE - 1)); + hash = hash_port_and_addr(result, 0); + if (__udp_lib_port_inuse(hash, result, + 0, udptable)) + continue; + if (!inet_sk(sk)->rcv_saddr) + break; + hash = hash_port_and_addr(result, inet_sk(sk)->rcv_saddr); if (! __udp_lib_port_inuse(hash, result, @@ -214,18 +221,36 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, gotit: *port_rover = snum = result; } else { - hash = hash_port_and_addr(snum, inet_sk(sk)->rcv_saddr); + hash = hash_port_and_addr(snum, 0); head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; sk_for_each(sk2, node, head) - if (sk2->sk_hash == hash && - sk2 != sk && - inet_sk(sk2)->num == snum && - (!sk2->sk_reuse || !sk->sk_reuse) && - (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if - || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && - (*saddr_comp)(sk, sk2) ) + if (sk2->sk_hash == hash && + sk2 != sk && + inet_sk(sk2)->num == snum && + (!sk2->sk_reuse || !sk->sk_reuse) && + (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || + sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && + (*saddr_comp)(sk, sk2)) goto fail; + + if (inet_sk(sk)->rcv_saddr) { + hash = hash_port_and_addr(snum, + inet_sk(sk)->rcv_saddr); + head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; + + sk_for_each(sk2, node, head) + if (sk2->sk_hash == hash && + sk2 != sk && + inet_sk(sk2)->num == snum && + (!sk2->sk_reuse || !sk->sk_reuse) && + (!sk2->sk_bound_dev_if || + !sk->sk_bound_dev_if || + sk2->sk_bound_dev_if == + sk->sk_bound_dev_if) && + (*saddr_comp)(sk, sk2)) + goto fail; + } } inet_sk(sk)->num = snum; sk->sk_hash = hash; -- cgit v1.2.3