aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/infiniband/core/cma.c22
-rw-r--r--include/net/ip.h3
-rw-r--r--net/ipv4/inet_connection_sock.c22
-rw-r--r--net/ipv4/inet_hashtables.c13
-rw-r--r--net/ipv4/sysctl_net_ipv4.c75
-rw-r--r--net/ipv4/tcp_ipv4.c1
-rw-r--r--net/ipv4/udp.c6
-rw-r--r--net/ipv6/inet6_hashtables.c12
-rw-r--r--net/sctp/socket.c11
-rw-r--r--security/selinux/hooks.c39
10 files changed, 146 insertions, 58 deletions
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 9ffb9987450a..2e641b255db4 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -1866,13 +1866,14 @@ err1:
1866static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) 1866static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv)
1867{ 1867{
1868 struct rdma_bind_list *bind_list; 1868 struct rdma_bind_list *bind_list;
1869 int port, ret; 1869 int port, ret, low, high;
1870 1870
1871 bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 1871 bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
1872 if (!bind_list) 1872 if (!bind_list)
1873 return -ENOMEM; 1873 return -ENOMEM;
1874 1874
1875retry: 1875retry:
1876 /* FIXME: add proper port randomization per like inet_csk_get_port */
1876 do { 1877 do {
1877 ret = idr_get_new_above(ps, bind_list, next_port, &port); 1878 ret = idr_get_new_above(ps, bind_list, next_port, &port);
1878 } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); 1879 } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL));
@@ -1880,18 +1881,19 @@ retry:
1880 if (ret) 1881 if (ret)
1881 goto err1; 1882 goto err1;
1882 1883
1883 if (port > sysctl_local_port_range[1]) { 1884 inet_get_local_port_range(&low, &high);
1884 if (next_port != sysctl_local_port_range[0]) { 1885 if (port > high) {
1886 if (next_port != low) {
1885 idr_remove(ps, port); 1887 idr_remove(ps, port);
1886 next_port = sysctl_local_port_range[0]; 1888 next_port = low;
1887 goto retry; 1889 goto retry;
1888 } 1890 }
1889 ret = -EADDRNOTAVAIL; 1891 ret = -EADDRNOTAVAIL;
1890 goto err2; 1892 goto err2;
1891 } 1893 }
1892 1894
1893 if (port == sysctl_local_port_range[1]) 1895 if (port == high)
1894 next_port = sysctl_local_port_range[0]; 1896 next_port = low;
1895 else 1897 else
1896 next_port = port + 1; 1898 next_port = port + 1;
1897 1899
@@ -2769,12 +2771,12 @@ static void cma_remove_one(struct ib_device *device)
2769 2771
2770static int cma_init(void) 2772static int cma_init(void)
2771{ 2773{
2772 int ret; 2774 int ret, low, high;
2773 2775
2774 get_random_bytes(&next_port, sizeof next_port); 2776 get_random_bytes(&next_port, sizeof next_port);
2775 next_port = ((unsigned int) next_port % 2777 inet_get_local_port_range(&low, &high);
2776 (sysctl_local_port_range[1] - sysctl_local_port_range[0])) + 2778 next_port = ((unsigned int) next_port % (high - low)) + low;
2777 sysctl_local_port_range[0]; 2779
2778 cma_wq = create_singlethread_workqueue("rdma_cm"); 2780 cma_wq = create_singlethread_workqueue("rdma_cm");
2779 if (!cma_wq) 2781 if (!cma_wq)
2780 return -ENOMEM; 2782 return -ENOMEM;
diff --git a/include/net/ip.h b/include/net/ip.h
index abf2820a1125..3af3ed9d320b 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -171,7 +171,8 @@ extern unsigned long snmp_fold_field(void *mib[], int offt);
171extern int snmp_mib_init(void *ptr[2], size_t mibsize, size_t mibalign); 171extern int snmp_mib_init(void *ptr[2], size_t mibsize, size_t mibalign);
172extern void snmp_mib_free(void *ptr[2]); 172extern void snmp_mib_free(void *ptr[2]);
173 173
174extern int sysctl_local_port_range[2]; 174extern void inet_get_local_port_range(int *low, int *high);
175
175extern int sysctl_ip_default_ttl; 176extern int sysctl_ip_default_ttl;
176extern int sysctl_ip_nonlocal_bind; 177extern int sysctl_ip_nonlocal_bind;
177 178
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 */
35int sysctl_local_port_range[2] = { 32768, 61000 }; 35int sysctl_local_port_range[2] = { 32768, 61000 };
36DEFINE_SEQLOCK(sysctl_port_range_lock);
37
38void 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}
48EXPORT_SYMBOL(inet_get_local_port_range);
36 49
37int inet_csk_bind_conflict(const struct sock *sk, 50int 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)];
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index fb662621c54e..fac6398e4367 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -279,19 +279,18 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row,
279 int ret; 279 int ret;
280 280
281 if (!snum) { 281 if (!snum) {
282 int low = sysctl_local_port_range[0]; 282 int i, remaining, low, high, port;
283 int high = sysctl_local_port_range[1];
284 int range = high - low;
285 int i;
286 int port;
287 static u32 hint; 283 static u32 hint;
288 u32 offset = hint + inet_sk_port_offset(sk); 284 u32 offset = hint + inet_sk_port_offset(sk);
289 struct hlist_node *node; 285 struct hlist_node *node;
290 struct inet_timewait_sock *tw = NULL; 286 struct inet_timewait_sock *tw = NULL;
291 287
288 inet_get_local_port_range(&low, &high);
289 remaining = high - low;
290
292 local_bh_disable(); 291 local_bh_disable();
293 for (i = 1; i <= range; i++) { 292 for (i = 1; i <= remaining; i++) {
294 port = low + (i + offset) % range; 293 port = low + (i + offset) % remaining;
295 head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)]; 294 head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)];
296 spin_lock(&head->lock); 295 spin_lock(&head->lock);
297 296
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 53ef0f4bbdaa..eb286abcf5dc 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -12,6 +12,7 @@
12#include <linux/sysctl.h> 12#include <linux/sysctl.h>
13#include <linux/igmp.h> 13#include <linux/igmp.h>
14#include <linux/inetdevice.h> 14#include <linux/inetdevice.h>
15#include <linux/seqlock.h>
15#include <net/snmp.h> 16#include <net/snmp.h>
16#include <net/icmp.h> 17#include <net/icmp.h>
17#include <net/ip.h> 18#include <net/ip.h>
@@ -89,6 +90,74 @@ static int ipv4_sysctl_forward_strategy(ctl_table *table,
89 return 1; 90 return 1;
90} 91}
91 92
93extern seqlock_t sysctl_port_range_lock;
94extern int sysctl_local_port_range[2];
95
96/* Update system visible IP port range */
97static void set_local_port_range(int range[2])
98{
99 write_seqlock(&sysctl_port_range_lock);
100 sysctl_local_port_range[0] = range[0];
101 sysctl_local_port_range[1] = range[1];
102 write_sequnlock(&sysctl_port_range_lock);
103}
104
105/* Validate changes from /proc interface. */
106static int ipv4_local_port_range(ctl_table *table, int write, struct file *filp,
107 void __user *buffer,
108 size_t *lenp, loff_t *ppos)
109{
110 int ret;
111 int range[2] = { sysctl_local_port_range[0],
112 sysctl_local_port_range[1] };
113 ctl_table tmp = {
114 .data = &range,
115 .maxlen = sizeof(range),
116 .mode = table->mode,
117 .extra1 = &ip_local_port_range_min,
118 .extra2 = &ip_local_port_range_max,
119 };
120
121 ret = proc_dointvec_minmax(&tmp, write, filp, buffer, lenp, ppos);
122
123 if (write && ret == 0) {
124 if (range[1] <= range[0])
125 ret = -EINVAL;
126 else
127 set_local_port_range(range);
128 }
129
130 return ret;
131}
132
133/* Validate changes from sysctl interface. */
134static int ipv4_sysctl_local_port_range(ctl_table *table, int __user *name,
135 int nlen, void __user *oldval,
136 size_t __user *oldlenp,
137 void __user *newval, size_t newlen)
138{
139 int ret;
140 int range[2] = { sysctl_local_port_range[0],
141 sysctl_local_port_range[1] };
142 ctl_table tmp = {
143 .data = &range,
144 .maxlen = sizeof(range),
145 .mode = table->mode,
146 .extra1 = &ip_local_port_range_min,
147 .extra2 = &ip_local_port_range_max,
148 };
149
150 ret = sysctl_intvec(&tmp, name, nlen, oldval, oldlenp, newval, newlen);
151 if (ret == 0 && newval && newlen) {
152 if (range[1] <= range[0])
153 ret = -EINVAL;
154 else
155 set_local_port_range(range);
156 }
157 return ret;
158}
159
160
92static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file * filp, 161static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file * filp,
93 void __user *buffer, size_t *lenp, loff_t *ppos) 162 void __user *buffer, size_t *lenp, loff_t *ppos)
94{ 163{
@@ -427,10 +496,8 @@ ctl_table ipv4_table[] = {
427 .data = &sysctl_local_port_range, 496 .data = &sysctl_local_port_range,
428 .maxlen = sizeof(sysctl_local_port_range), 497 .maxlen = sizeof(sysctl_local_port_range),
429 .mode = 0644, 498 .mode = 0644,
430 .proc_handler = &proc_dointvec_minmax, 499 .proc_handler = &ipv4_local_port_range,
431 .strategy = &sysctl_intvec, 500 .strategy = &ipv4_sysctl_local_port_range,
432 .extra1 = ip_local_port_range_min,
433 .extra2 = ip_local_port_range_max
434 }, 501 },
435 { 502 {
436 .ctl_name = NET_IPV4_ICMP_ECHO_IGNORE_ALL, 503 .ctl_name = NET_IPV4_ICMP_ECHO_IGNORE_ALL,
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 8855e640e958..38cf73a56731 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2470,6 +2470,5 @@ EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
2470EXPORT_SYMBOL(tcp_proc_register); 2470EXPORT_SYMBOL(tcp_proc_register);
2471EXPORT_SYMBOL(tcp_proc_unregister); 2471EXPORT_SYMBOL(tcp_proc_unregister);
2472#endif 2472#endif
2473EXPORT_SYMBOL(sysctl_local_port_range);
2474EXPORT_SYMBOL(sysctl_tcp_low_latency); 2473EXPORT_SYMBOL(sysctl_tcp_low_latency);
2475 2474
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index ef4d901ee9ad..cb9fc58efb2f 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -147,11 +147,11 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
147 write_lock_bh(&udp_hash_lock); 147 write_lock_bh(&udp_hash_lock);
148 148
149 if (!snum) { 149 if (!snum) {
150 int i; 150 int i, low, high;
151 int low = sysctl_local_port_range[0];
152 int high = sysctl_local_port_range[1];
153 unsigned rover, best, best_size_so_far; 151 unsigned rover, best, best_size_so_far;
154 152
153 inet_get_local_port_range(&low, &high);
154
155 best_size_so_far = UINT_MAX; 155 best_size_so_far = UINT_MAX;
156 best = rover = net_random() % (high - low) + low; 156 best = rover = net_random() % (high - low) + low;
157 157
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index ae6b0e7eb488..1c2c27655435 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -254,18 +254,18 @@ int inet6_hash_connect(struct inet_timewait_death_row *death_row,
254 int ret; 254 int ret;
255 255
256 if (snum == 0) { 256 if (snum == 0) {
257 const int low = sysctl_local_port_range[0]; 257 int i, port, low, high, remaining;
258 const int high = sysctl_local_port_range[1];
259 const int range = high - low;
260 int i, port;
261 static u32 hint; 258 static u32 hint;
262 const u32 offset = hint + inet6_sk_port_offset(sk); 259 const u32 offset = hint + inet6_sk_port_offset(sk);
263 struct hlist_node *node; 260 struct hlist_node *node;
264 struct inet_timewait_sock *tw = NULL; 261 struct inet_timewait_sock *tw = NULL;
265 262
263 inet_get_local_port_range(&low, &high);
264 remaining = high - low;
265
266 local_bh_disable(); 266 local_bh_disable();
267 for (i = 1; i <= range; i++) { 267 for (i = 1; i <= remaining; i++) {
268 port = low + (i + offset) % range; 268 port = low + (i + offset) % remaining;
269 head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)]; 269 head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)];
270 spin_lock(&head->lock); 270 spin_lock(&head->lock);
271 271
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 7cd58ef84eda..9c6a4b5f6264 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -5315,11 +5315,12 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
5315 5315
5316 if (snum == 0) { 5316 if (snum == 0) {
5317 /* Search for an available port. */ 5317 /* Search for an available port. */
5318 unsigned int low = sysctl_local_port_range[0]; 5318 int low, high, remaining, index;
5319 unsigned int high = sysctl_local_port_range[1]; 5319 unsigned int rover;
5320 unsigned int remaining = (high - low) + 1; 5320
5321 unsigned int rover = net_random() % remaining + low; 5321 inet_get_local_port_range(&low, &high);
5322 int index; 5322 remaining = (high - low) + 1;
5323 rover = net_random() % remaining + low;
5323 5324
5324 do { 5325 do {
5325 rover++; 5326 rover++;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 0753b20e23fe..3c3fff33d1ce 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -47,7 +47,7 @@
47#include <linux/netfilter_ipv6.h> 47#include <linux/netfilter_ipv6.h>
48#include <linux/tty.h> 48#include <linux/tty.h>
49#include <net/icmp.h> 49#include <net/icmp.h>
50#include <net/ip.h> /* for sysctl_local_port_range[] */ 50#include <net/ip.h> /* for local_port_range[] */
51#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */ 51#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */
52#include <asm/uaccess.h> 52#include <asm/uaccess.h>
53#include <asm/ioctls.h> 53#include <asm/ioctls.h>
@@ -3232,8 +3232,6 @@ static int selinux_socket_post_create(struct socket *sock, int family,
3232/* Range of port numbers used to automatically bind. 3232/* Range of port numbers used to automatically bind.
3233 Need to determine whether we should perform a name_bind 3233 Need to determine whether we should perform a name_bind
3234 permission check between the socket and the port number. */ 3234 permission check between the socket and the port number. */
3235#define ip_local_port_range_0 sysctl_local_port_range[0]
3236#define ip_local_port_range_1 sysctl_local_port_range[1]
3237 3235
3238static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) 3236static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3239{ 3237{
@@ -3276,20 +3274,27 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
3276 addrp = (char *)&addr6->sin6_addr.s6_addr; 3274 addrp = (char *)&addr6->sin6_addr.s6_addr;
3277 } 3275 }
3278 3276
3279 if (snum&&(snum < max(PROT_SOCK,ip_local_port_range_0) || 3277 if (snum) {
3280 snum > ip_local_port_range_1)) { 3278 int low, high;
3281 err = security_port_sid(sk->sk_family, sk->sk_type, 3279
3282 sk->sk_protocol, snum, &sid); 3280 inet_get_local_port_range(&low, &high);
3283 if (err) 3281
3284 goto out; 3282 if (snum < max(PROT_SOCK, low) || snum > high) {
3285 AVC_AUDIT_DATA_INIT(&ad,NET); 3283 err = security_port_sid(sk->sk_family,
3286 ad.u.net.sport = htons(snum); 3284 sk->sk_type,
3287 ad.u.net.family = family; 3285 sk->sk_protocol, snum,
3288 err = avc_has_perm(isec->sid, sid, 3286 &sid);
3289 isec->sclass, 3287 if (err)
3290 SOCKET__NAME_BIND, &ad); 3288 goto out;
3291 if (err) 3289 AVC_AUDIT_DATA_INIT(&ad,NET);
3292 goto out; 3290 ad.u.net.sport = htons(snum);
3291 ad.u.net.family = family;
3292 err = avc_has_perm(isec->sid, sid,
3293 isec->sclass,
3294 SOCKET__NAME_BIND, &ad);
3295 if (err)
3296 goto out;
3297 }
3293 } 3298 }
3294 3299
3295 switch(isec->sclass) { 3300 switch(isec->sclass) {