diff options
author | Stephen Hemminger <shemminger@osdl.org> | 2005-11-03 19:33:23 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@mandriva.com> | 2005-11-05 18:23:15 -0500 |
commit | 6df716340da3a6fdd33d73d7ed4c6f7590ca1c42 (patch) | |
tree | 1b3ba3d1a0a08b9b4eaa624a66414b87a70b6fe9 /net/dccp/ipv4.c | |
parent | 6151b31c9616d71f714fc7ef8e2306f67f3b94c3 (diff) |
[TCP/DCCP]: Randomize port selection
This patch randomizes the port selected on bind() for connections
to help with possible security attacks. It should also be faster
in most cases because there is no need for a global lock.
Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Diffstat (limited to 'net/dccp/ipv4.c')
-rw-r--r-- | net/dccp/ipv4.c | 32 |
1 files changed, 3 insertions, 29 deletions
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 6298cf58ff9e..4b9bc81ae1a3 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -31,8 +31,6 @@ struct inet_hashinfo __cacheline_aligned dccp_hashinfo = { | |||
31 | .lhash_lock = RW_LOCK_UNLOCKED, | 31 | .lhash_lock = RW_LOCK_UNLOCKED, |
32 | .lhash_users = ATOMIC_INIT(0), | 32 | .lhash_users = ATOMIC_INIT(0), |
33 | .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait), | 33 | .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait), |
34 | .portalloc_lock = SPIN_LOCK_UNLOCKED, | ||
35 | .port_rover = 1024 - 1, | ||
36 | }; | 34 | }; |
37 | 35 | ||
38 | EXPORT_SYMBOL_GPL(dccp_hashinfo); | 36 | EXPORT_SYMBOL_GPL(dccp_hashinfo); |
@@ -125,36 +123,15 @@ static int dccp_v4_hash_connect(struct sock *sk) | |||
125 | int ret; | 123 | int ret; |
126 | 124 | ||
127 | if (snum == 0) { | 125 | if (snum == 0) { |
128 | int rover; | ||
129 | int low = sysctl_local_port_range[0]; | 126 | int low = sysctl_local_port_range[0]; |
130 | int high = sysctl_local_port_range[1]; | 127 | int high = sysctl_local_port_range[1]; |
131 | int remaining = (high - low) + 1; | 128 | int remaining = (high - low) + 1; |
129 | int rover = net_random() % (high - low) + low; | ||
132 | struct hlist_node *node; | 130 | struct hlist_node *node; |
133 | struct inet_timewait_sock *tw = NULL; | 131 | struct inet_timewait_sock *tw = NULL; |
134 | 132 | ||
135 | local_bh_disable(); | 133 | local_bh_disable(); |
136 | |||
137 | /* TODO. Actually it is not so bad idea to remove | ||
138 | * dccp_hashinfo.portalloc_lock before next submission to | ||
139 | * Linus. | ||
140 | * As soon as we touch this place at all it is time to think. | ||
141 | * | ||
142 | * Now it protects single _advisory_ variable | ||
143 | * dccp_hashinfo.port_rover, hence it is mostly useless. | ||
144 | * Code will work nicely if we just delete it, but | ||
145 | * I am afraid in contented case it will work not better or | ||
146 | * even worse: another cpu just will hit the same bucket | ||
147 | * and spin there. | ||
148 | * So some cpu salt could remove both contention and | ||
149 | * memory pingpong. Any ideas how to do this in a nice way? | ||
150 | */ | ||
151 | spin_lock(&dccp_hashinfo.portalloc_lock); | ||
152 | rover = dccp_hashinfo.port_rover; | ||
153 | |||
154 | do { | 134 | do { |
155 | rover++; | ||
156 | if ((rover < low) || (rover > high)) | ||
157 | rover = low; | ||
158 | head = &dccp_hashinfo.bhash[inet_bhashfn(rover, | 135 | head = &dccp_hashinfo.bhash[inet_bhashfn(rover, |
159 | dccp_hashinfo.bhash_size)]; | 136 | dccp_hashinfo.bhash_size)]; |
160 | spin_lock(&head->lock); | 137 | spin_lock(&head->lock); |
@@ -187,9 +164,9 @@ static int dccp_v4_hash_connect(struct sock *sk) | |||
187 | 164 | ||
188 | next_port: | 165 | next_port: |
189 | spin_unlock(&head->lock); | 166 | spin_unlock(&head->lock); |
167 | if (++rover > high) | ||
168 | rover = low; | ||
190 | } while (--remaining > 0); | 169 | } while (--remaining > 0); |
191 | dccp_hashinfo.port_rover = rover; | ||
192 | spin_unlock(&dccp_hashinfo.portalloc_lock); | ||
193 | 170 | ||
194 | local_bh_enable(); | 171 | local_bh_enable(); |
195 | 172 | ||
@@ -197,9 +174,6 @@ static int dccp_v4_hash_connect(struct sock *sk) | |||
197 | 174 | ||
198 | ok: | 175 | ok: |
199 | /* All locks still held and bhs disabled */ | 176 | /* All locks still held and bhs disabled */ |
200 | dccp_hashinfo.port_rover = rover; | ||
201 | spin_unlock(&dccp_hashinfo.portalloc_lock); | ||
202 | |||
203 | inet_bind_hash(sk, tb, rover); | 177 | inet_bind_hash(sk, tb, rover); |
204 | if (sk_unhashed(sk)) { | 178 | if (sk_unhashed(sk)) { |
205 | inet_sk(sk)->sport = htons(rover); | 179 | inet_sk(sk)->sport = htons(rover); |