aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKrister Johansen <kjlx@templeofstupid.com>2017-01-20 20:49:11 -0500
committerDavid S. Miller <davem@davemloft.net>2017-01-24 12:10:51 -0500
commit4548b683b78137f8eadeb312b94e20bb0d4a7141 (patch)
tree8b285d141f533807625336c4524411bf31d48d9f
parentd140199af510ad4749dc5e38b7922135258ba5fd (diff)
Introduce a sysctl that modifies the value of PROT_SOCK.
Add net.ipv4.ip_unprivileged_port_start, which is a per namespace sysctl that denotes the first unprivileged inet port in the namespace. To disable all privileged ports set this to zero. It also checks for overlap with the local port range. The privileged and local range may not overlap. The use case for this change is to allow containerized processes to bind to priviliged ports, but prevent them from ever being allowed to modify their container's network configuration. The latter is accomplished by ensuring that the network namespace is not a child of the user namespace. This modification was needed to allow the container manager to disable a namespace's priviliged port restrictions without exposing control of the network namespace to processes in the user namespace. Signed-off-by: Krister Johansen <kjlx@templeofstupid.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/networking/ip-sysctl.txt9
-rw-r--r--include/net/ip.h10
-rw-r--r--include/net/netns/ipv4.h1
-rw-r--r--net/ipv4/af_inet.c5
-rw-r--r--net/ipv4/sysctl_net_ipv4.c50
-rw-r--r--net/ipv6/af_inet6.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c7
-rw-r--r--net/sctp/socket.c10
-rw-r--r--security/selinux/hooks.c3
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
825ip_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
825ip_nonlocal_bind - BOOLEAN 834ip_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
266static inline int inet_prot_sock(struct net *net)
267{
268 return net->ipv4.sysctl_ip_prot_sock;
269}
270
266#else 271#else
267static inline int inet_is_local_reserved_port(struct net *net, int port) 272static inline int inet_is_local_reserved_port(struct net *net, int port)
268{ 273{
269 return 0; 274 return 0;
270} 275}
276
277static 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 };
35static int ip_local_port_range_max[] = { 65535, 65535 }; 35static int ip_local_port_range_max[] = { 65535, 65535 };
36static int tcp_adv_win_scale_min = -31; 36static int tcp_adv_win_scale_min = -31;
37static int tcp_adv_win_scale_max = 31; 37static int tcp_adv_win_scale_max = 31;
38static int ip_privileged_port_min;
39static int ip_privileged_port_max = 65535;
38static int ip_ttl_min = 1; 40static int ip_ttl_min = 1;
39static int ip_ttl_max = 255; 41static int ip_ttl_max = 255;
40static int tcp_syn_retries_min = 1; 42static 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. */
99static 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
92static void inet_get_ping_group_range_table(struct ctl_table *table, kgid_t *low, kgid_t *high) 133static 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)