diff options
author | Stephen Hemminger <shemminger@linux-foundation.org> | 2007-10-10 20:30:46 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-10-10 20:30:46 -0400 |
commit | 227b60f5102cda4e4ab792b526a59c8cb20cd9f8 (patch) | |
tree | 2c9e372601ba794894833b0618bc531a9f5d57c4 /net/ipv4/inet_connection_sock.c | |
parent | 06393009000779b00a558fd2f280882cc7dc2008 (diff) |
[INET]: local port range robustness
Expansion of original idea from Denis V. Lunev <den@openvz.org>
Add robustness and locking to the local_port_range sysctl.
1. Enforce that low < high when setting.
2. Use seqlock to ensure atomic update.
The locking might seem like overkill, but there are
cases where sysadmin might want to change value in the
middle of a DoS attack.
Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/inet_connection_sock.c')
-rw-r--r-- | net/ipv4/inet_connection_sock.c | 22 |
1 files changed, 18 insertions, 4 deletions
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index fbe7714f21d0..3cef12835c4b 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c | |||
@@ -33,6 +33,19 @@ EXPORT_SYMBOL(inet_csk_timer_bug_msg); | |||
33 | * This array holds the first and last local port number. | 33 | * This array holds the first and last local port number. |
34 | */ | 34 | */ |
35 | int sysctl_local_port_range[2] = { 32768, 61000 }; | 35 | int sysctl_local_port_range[2] = { 32768, 61000 }; |
36 | DEFINE_SEQLOCK(sysctl_port_range_lock); | ||
37 | |||
38 | void inet_get_local_port_range(int *low, int *high) | ||
39 | { | ||
40 | unsigned seq; | ||
41 | do { | ||
42 | seq = read_seqbegin(&sysctl_port_range_lock); | ||
43 | |||
44 | *low = sysctl_local_port_range[0]; | ||
45 | *high = sysctl_local_port_range[1]; | ||
46 | } while (read_seqretry(&sysctl_port_range_lock, seq)); | ||
47 | } | ||
48 | EXPORT_SYMBOL(inet_get_local_port_range); | ||
36 | 49 | ||
37 | int inet_csk_bind_conflict(const struct sock *sk, | 50 | int inet_csk_bind_conflict(const struct sock *sk, |
38 | const struct inet_bind_bucket *tb) | 51 | const struct inet_bind_bucket *tb) |
@@ -77,10 +90,11 @@ int inet_csk_get_port(struct inet_hashinfo *hashinfo, | |||
77 | 90 | ||
78 | local_bh_disable(); | 91 | local_bh_disable(); |
79 | if (!snum) { | 92 | if (!snum) { |
80 | int low = sysctl_local_port_range[0]; | 93 | int remaining, rover, low, high; |
81 | int high = sysctl_local_port_range[1]; | 94 | |
82 | int remaining = (high - low) + 1; | 95 | inet_get_local_port_range(&low, &high); |
83 | int rover = net_random() % (high - low) + low; | 96 | remaining = high - low; |
97 | rover = net_random() % remaining + low; | ||
84 | 98 | ||
85 | do { | 99 | do { |
86 | head = &hashinfo->bhash[inet_bhashfn(rover, hashinfo->bhash_size)]; | 100 | head = &hashinfo->bhash[inet_bhashfn(rover, hashinfo->bhash_size)]; |