diff options
-rw-r--r-- | Documentation/networking/ip-sysctl.txt | 9 | ||||
-rw-r--r-- | include/net/ip.h | 10 | ||||
-rw-r--r-- | include/net/netns/ipv4.h | 1 | ||||
-rw-r--r-- | net/ipv4/af_inet.c | 5 | ||||
-rw-r--r-- | net/ipv4/sysctl_net_ipv4.c | 50 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 3 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_ctl.c | 7 | ||||
-rw-r--r-- | net/sctp/socket.c | 10 | ||||
-rw-r--r-- | security/selinux/hooks.c | 3 |
9 files changed, 86 insertions, 12 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index aa1bb49f1dc6..17f2e7791042 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt | |||
@@ -822,6 +822,15 @@ ip_local_reserved_ports - list of comma separated ranges | |||
822 | 822 | ||
823 | Default: Empty | 823 | Default: Empty |
824 | 824 | ||
825 | ip_unprivileged_port_start - INTEGER | ||
826 | This is a per-namespace sysctl. It defines the first | ||
827 | unprivileged port in the network namespace. Privileged ports | ||
828 | require root or CAP_NET_BIND_SERVICE in order to bind to them. | ||
829 | To disable all privileged ports, set this to 0. It may not | ||
830 | overlap with the ip_local_reserved_ports range. | ||
831 | |||
832 | Default: 1024 | ||
833 | |||
825 | ip_nonlocal_bind - BOOLEAN | 834 | ip_nonlocal_bind - BOOLEAN |
826 | If set, allows processes to bind() to non-local IP addresses, | 835 | If set, allows processes to bind() to non-local IP addresses, |
827 | which can be quite useful - but may break some applications. | 836 | which can be quite useful - but may break some applications. |
diff --git a/include/net/ip.h b/include/net/ip.h index ab6761a7c883..bf264a8db1ce 100644 --- a/include/net/ip.h +++ b/include/net/ip.h | |||
@@ -263,11 +263,21 @@ static inline bool sysctl_dev_name_is_allowed(const char *name) | |||
263 | return strcmp(name, "default") != 0 && strcmp(name, "all") != 0; | 263 | return strcmp(name, "default") != 0 && strcmp(name, "all") != 0; |
264 | } | 264 | } |
265 | 265 | ||
266 | static inline int inet_prot_sock(struct net *net) | ||
267 | { | ||
268 | return net->ipv4.sysctl_ip_prot_sock; | ||
269 | } | ||
270 | |||
266 | #else | 271 | #else |
267 | static inline int inet_is_local_reserved_port(struct net *net, int port) | 272 | static inline int inet_is_local_reserved_port(struct net *net, int port) |
268 | { | 273 | { |
269 | return 0; | 274 | return 0; |
270 | } | 275 | } |
276 | |||
277 | static inline int inet_prot_sock(struct net *net) | ||
278 | { | ||
279 | return PROT_SOCK; | ||
280 | } | ||
271 | #endif | 281 | #endif |
272 | 282 | ||
273 | __be32 inet_current_timestamp(void); | 283 | __be32 inet_current_timestamp(void); |
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index 8e3f5b6f26d5..e365732b8051 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h | |||
@@ -135,6 +135,7 @@ struct netns_ipv4 { | |||
135 | 135 | ||
136 | #ifdef CONFIG_SYSCTL | 136 | #ifdef CONFIG_SYSCTL |
137 | unsigned long *sysctl_local_reserved_ports; | 137 | unsigned long *sysctl_local_reserved_ports; |
138 | int sysctl_ip_prot_sock; | ||
138 | #endif | 139 | #endif |
139 | 140 | ||
140 | #ifdef CONFIG_IP_MROUTE | 141 | #ifdef CONFIG_IP_MROUTE |
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index aae410bb655a..28fe8da4e1ac 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -479,7 +479,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
479 | 479 | ||
480 | snum = ntohs(addr->sin_port); | 480 | snum = ntohs(addr->sin_port); |
481 | err = -EACCES; | 481 | err = -EACCES; |
482 | if (snum && snum < PROT_SOCK && | 482 | if (snum && snum < inet_prot_sock(net) && |
483 | !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) | 483 | !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) |
484 | goto out; | 484 | goto out; |
485 | 485 | ||
@@ -1700,6 +1700,9 @@ static __net_init int inet_init_net(struct net *net) | |||
1700 | net->ipv4.sysctl_ip_default_ttl = IPDEFTTL; | 1700 | net->ipv4.sysctl_ip_default_ttl = IPDEFTTL; |
1701 | net->ipv4.sysctl_ip_dynaddr = 0; | 1701 | net->ipv4.sysctl_ip_dynaddr = 0; |
1702 | net->ipv4.sysctl_ip_early_demux = 1; | 1702 | net->ipv4.sysctl_ip_early_demux = 1; |
1703 | #ifdef CONFIG_SYSCTL | ||
1704 | net->ipv4.sysctl_ip_prot_sock = PROT_SOCK; | ||
1705 | #endif | ||
1703 | 1706 | ||
1704 | return 0; | 1707 | return 0; |
1705 | } | 1708 | } |
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index c8d283615c6f..1b861997fdc5 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c | |||
@@ -35,6 +35,8 @@ static int ip_local_port_range_min[] = { 1, 1 }; | |||
35 | static int ip_local_port_range_max[] = { 65535, 65535 }; | 35 | static int ip_local_port_range_max[] = { 65535, 65535 }; |
36 | static int tcp_adv_win_scale_min = -31; | 36 | static int tcp_adv_win_scale_min = -31; |
37 | static int tcp_adv_win_scale_max = 31; | 37 | static int tcp_adv_win_scale_max = 31; |
38 | static int ip_privileged_port_min; | ||
39 | static int ip_privileged_port_max = 65535; | ||
38 | static int ip_ttl_min = 1; | 40 | static int ip_ttl_min = 1; |
39 | static int ip_ttl_max = 255; | 41 | static int ip_ttl_max = 255; |
40 | static int tcp_syn_retries_min = 1; | 42 | static int tcp_syn_retries_min = 1; |
@@ -79,7 +81,12 @@ static int ipv4_local_port_range(struct ctl_table *table, int write, | |||
79 | ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); | 81 | ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); |
80 | 82 | ||
81 | if (write && ret == 0) { | 83 | if (write && ret == 0) { |
82 | if (range[1] < range[0]) | 84 | /* Ensure that the upper limit is not smaller than the lower, |
85 | * and that the lower does not encroach upon the privileged | ||
86 | * port limit. | ||
87 | */ | ||
88 | if ((range[1] < range[0]) || | ||
89 | (range[0] < net->ipv4.sysctl_ip_prot_sock)) | ||
83 | ret = -EINVAL; | 90 | ret = -EINVAL; |
84 | else | 91 | else |
85 | set_local_port_range(net, range); | 92 | set_local_port_range(net, range); |
@@ -88,6 +95,40 @@ static int ipv4_local_port_range(struct ctl_table *table, int write, | |||
88 | return ret; | 95 | return ret; |
89 | } | 96 | } |
90 | 97 | ||
98 | /* Validate changes from /proc interface. */ | ||
99 | static int ipv4_privileged_ports(struct ctl_table *table, int write, | ||
100 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
101 | { | ||
102 | struct net *net = container_of(table->data, struct net, | ||
103 | ipv4.sysctl_ip_prot_sock); | ||
104 | int ret; | ||
105 | int pports; | ||
106 | int range[2]; | ||
107 | struct ctl_table tmp = { | ||
108 | .data = &pports, | ||
109 | .maxlen = sizeof(pports), | ||
110 | .mode = table->mode, | ||
111 | .extra1 = &ip_privileged_port_min, | ||
112 | .extra2 = &ip_privileged_port_max, | ||
113 | }; | ||
114 | |||
115 | pports = net->ipv4.sysctl_ip_prot_sock; | ||
116 | |||
117 | ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); | ||
118 | |||
119 | if (write && ret == 0) { | ||
120 | inet_get_local_port_range(net, &range[0], &range[1]); | ||
121 | /* Ensure that the local port range doesn't overlap with the | ||
122 | * privileged port range. | ||
123 | */ | ||
124 | if (range[0] < pports) | ||
125 | ret = -EINVAL; | ||
126 | else | ||
127 | net->ipv4.sysctl_ip_prot_sock = pports; | ||
128 | } | ||
129 | |||
130 | return ret; | ||
131 | } | ||
91 | 132 | ||
92 | static void inet_get_ping_group_range_table(struct ctl_table *table, kgid_t *low, kgid_t *high) | 133 | static void inet_get_ping_group_range_table(struct ctl_table *table, kgid_t *low, kgid_t *high) |
93 | { | 134 | { |
@@ -964,6 +1005,13 @@ static struct ctl_table ipv4_net_table[] = { | |||
964 | .extra2 = &one, | 1005 | .extra2 = &one, |
965 | }, | 1006 | }, |
966 | #endif | 1007 | #endif |
1008 | { | ||
1009 | .procname = "ip_unprivileged_port_start", | ||
1010 | .maxlen = sizeof(int), | ||
1011 | .data = &init_net.ipv4.sysctl_ip_prot_sock, | ||
1012 | .mode = 0644, | ||
1013 | .proc_handler = ipv4_privileged_ports, | ||
1014 | }, | ||
967 | { } | 1015 | { } |
968 | }; | 1016 | }; |
969 | 1017 | ||
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index aa42123bc301..04db40620ea6 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -302,7 +302,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
302 | return -EINVAL; | 302 | return -EINVAL; |
303 | 303 | ||
304 | snum = ntohs(addr->sin6_port); | 304 | snum = ntohs(addr->sin6_port); |
305 | if (snum && snum < PROT_SOCK && !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) | 305 | if (snum && snum < inet_prot_sock(net) && |
306 | !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) | ||
306 | return -EACCES; | 307 | return -EACCES; |
307 | 308 | ||
308 | lock_sock(sk); | 309 | lock_sock(sk); |
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 55e0169caa4c..8b7416f4e01a 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c | |||
@@ -426,10 +426,9 @@ ip_vs_service_find(struct netns_ipvs *ipvs, int af, __u32 fwmark, __u16 protocol | |||
426 | */ | 426 | */ |
427 | svc = __ip_vs_service_find(ipvs, af, protocol, vaddr, vport); | 427 | svc = __ip_vs_service_find(ipvs, af, protocol, vaddr, vport); |
428 | 428 | ||
429 | if (svc == NULL | 429 | if (!svc && protocol == IPPROTO_TCP && |
430 | && protocol == IPPROTO_TCP | 430 | atomic_read(&ipvs->ftpsvc_counter) && |
431 | && atomic_read(&ipvs->ftpsvc_counter) | 431 | (vport == FTPDATA || ntohs(vport) >= inet_prot_sock(ipvs->net))) { |
432 | && (vport == FTPDATA || ntohs(vport) >= PROT_SOCK)) { | ||
433 | /* | 432 | /* |
434 | * Check if ftp service entry exists, the packet | 433 | * Check if ftp service entry exists, the packet |
435 | * might belong to FTP data connections. | 434 | * might belong to FTP data connections. |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index bee4dd3feabb..d699d2cbf275 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -360,7 +360,7 @@ static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) | |||
360 | } | 360 | } |
361 | } | 361 | } |
362 | 362 | ||
363 | if (snum && snum < PROT_SOCK && | 363 | if (snum && snum < inet_prot_sock(net) && |
364 | !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) | 364 | !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) |
365 | return -EACCES; | 365 | return -EACCES; |
366 | 366 | ||
@@ -1152,8 +1152,10 @@ static int __sctp_connect(struct sock *sk, | |||
1152 | * accept new associations, but it SHOULD NOT | 1152 | * accept new associations, but it SHOULD NOT |
1153 | * be permitted to open new associations. | 1153 | * be permitted to open new associations. |
1154 | */ | 1154 | */ |
1155 | if (ep->base.bind_addr.port < PROT_SOCK && | 1155 | if (ep->base.bind_addr.port < |
1156 | !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) { | 1156 | inet_prot_sock(net) && |
1157 | !ns_capable(net->user_ns, | ||
1158 | CAP_NET_BIND_SERVICE)) { | ||
1157 | err = -EACCES; | 1159 | err = -EACCES; |
1158 | goto out_free; | 1160 | goto out_free; |
1159 | } | 1161 | } |
@@ -1818,7 +1820,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) | |||
1818 | * but it SHOULD NOT be permitted to open new | 1820 | * but it SHOULD NOT be permitted to open new |
1819 | * associations. | 1821 | * associations. |
1820 | */ | 1822 | */ |
1821 | if (ep->base.bind_addr.port < PROT_SOCK && | 1823 | if (ep->base.bind_addr.port < inet_prot_sock(net) && |
1822 | !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) { | 1824 | !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) { |
1823 | err = -EACCES; | 1825 | err = -EACCES; |
1824 | goto out_unlock; | 1826 | goto out_unlock; |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c7c6619431d5..53cb6da5f1c6 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -4365,7 +4365,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
4365 | 4365 | ||
4366 | inet_get_local_port_range(sock_net(sk), &low, &high); | 4366 | inet_get_local_port_range(sock_net(sk), &low, &high); |
4367 | 4367 | ||
4368 | if (snum < max(PROT_SOCK, low) || snum > high) { | 4368 | if (snum < max(inet_prot_sock(sock_net(sk)), low) || |
4369 | snum > high) { | ||
4369 | err = sel_netport_sid(sk->sk_protocol, | 4370 | err = sel_netport_sid(sk->sk_protocol, |
4370 | snum, &sid); | 4371 | snum, &sid); |
4371 | if (err) | 4372 | if (err) |