Commit 4548b683 authored by Krister Johansen's avatar Krister Johansen Committed by David S. Miller

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: default avatarKrister Johansen <kjlx@templeofstupid.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d140199a
...@@ -822,6 +822,15 @@ ip_local_reserved_ports - list of comma separated ranges ...@@ -822,6 +822,15 @@ ip_local_reserved_ports - list of comma separated ranges
Default: Empty Default: Empty
ip_unprivileged_port_start - INTEGER
This is a per-namespace sysctl. It defines the first
unprivileged port in the network namespace. Privileged ports
require root or CAP_NET_BIND_SERVICE in order to bind to them.
To disable all privileged ports, set this to 0. It may not
overlap with the ip_local_reserved_ports range.
Default: 1024
ip_nonlocal_bind - BOOLEAN ip_nonlocal_bind - BOOLEAN
If set, allows processes to bind() to non-local IP addresses, If set, allows processes to bind() to non-local IP addresses,
which can be quite useful - but may break some applications. which can be quite useful - but may break some applications.
......
...@@ -263,11 +263,21 @@ static inline bool sysctl_dev_name_is_allowed(const char *name) ...@@ -263,11 +263,21 @@ static inline bool sysctl_dev_name_is_allowed(const char *name)
return strcmp(name, "default") != 0 && strcmp(name, "all") != 0; return strcmp(name, "default") != 0 && strcmp(name, "all") != 0;
} }
static inline int inet_prot_sock(struct net *net)
{
return net->ipv4.sysctl_ip_prot_sock;
}
#else #else
static inline int inet_is_local_reserved_port(struct net *net, int port) static inline int inet_is_local_reserved_port(struct net *net, int port)
{ {
return 0; return 0;
} }
static inline int inet_prot_sock(struct net *net)
{
return PROT_SOCK;
}
#endif #endif
__be32 inet_current_timestamp(void); __be32 inet_current_timestamp(void);
......
...@@ -135,6 +135,7 @@ struct netns_ipv4 { ...@@ -135,6 +135,7 @@ struct netns_ipv4 {
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
unsigned long *sysctl_local_reserved_ports; unsigned long *sysctl_local_reserved_ports;
int sysctl_ip_prot_sock;
#endif #endif
#ifdef CONFIG_IP_MROUTE #ifdef CONFIG_IP_MROUTE
......
...@@ -479,7 +479,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -479,7 +479,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
snum = ntohs(addr->sin_port); snum = ntohs(addr->sin_port);
err = -EACCES; err = -EACCES;
if (snum && snum < PROT_SOCK && if (snum && snum < inet_prot_sock(net) &&
!ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE))
goto out; goto out;
...@@ -1700,6 +1700,9 @@ static __net_init int inet_init_net(struct net *net) ...@@ -1700,6 +1700,9 @@ static __net_init int inet_init_net(struct net *net)
net->ipv4.sysctl_ip_default_ttl = IPDEFTTL; net->ipv4.sysctl_ip_default_ttl = IPDEFTTL;
net->ipv4.sysctl_ip_dynaddr = 0; net->ipv4.sysctl_ip_dynaddr = 0;
net->ipv4.sysctl_ip_early_demux = 1; net->ipv4.sysctl_ip_early_demux = 1;
#ifdef CONFIG_SYSCTL
net->ipv4.sysctl_ip_prot_sock = PROT_SOCK;
#endif
return 0; return 0;
} }
......
...@@ -35,6 +35,8 @@ static int ip_local_port_range_min[] = { 1, 1 }; ...@@ -35,6 +35,8 @@ static int ip_local_port_range_min[] = { 1, 1 };
static int ip_local_port_range_max[] = { 65535, 65535 }; static int ip_local_port_range_max[] = { 65535, 65535 };
static int tcp_adv_win_scale_min = -31; static int tcp_adv_win_scale_min = -31;
static int tcp_adv_win_scale_max = 31; static int tcp_adv_win_scale_max = 31;
static int ip_privileged_port_min;
static int ip_privileged_port_max = 65535;
static int ip_ttl_min = 1; static int ip_ttl_min = 1;
static int ip_ttl_max = 255; static int ip_ttl_max = 255;
static int tcp_syn_retries_min = 1; static int tcp_syn_retries_min = 1;
...@@ -79,7 +81,12 @@ static int ipv4_local_port_range(struct ctl_table *table, int write, ...@@ -79,7 +81,12 @@ static int ipv4_local_port_range(struct ctl_table *table, int write,
ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
if (write && ret == 0) { if (write && ret == 0) {
if (range[1] < range[0]) /* Ensure that the upper limit is not smaller than the lower,
* and that the lower does not encroach upon the privileged
* port limit.
*/
if ((range[1] < range[0]) ||
(range[0] < net->ipv4.sysctl_ip_prot_sock))
ret = -EINVAL; ret = -EINVAL;
else else
set_local_port_range(net, range); set_local_port_range(net, range);
...@@ -88,6 +95,40 @@ static int ipv4_local_port_range(struct ctl_table *table, int write, ...@@ -88,6 +95,40 @@ static int ipv4_local_port_range(struct ctl_table *table, int write,
return ret; return ret;
} }
/* Validate changes from /proc interface. */
static int ipv4_privileged_ports(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
struct net *net = container_of(table->data, struct net,
ipv4.sysctl_ip_prot_sock);
int ret;
int pports;
int range[2];
struct ctl_table tmp = {
.data = &pports,
.maxlen = sizeof(pports),
.mode = table->mode,
.extra1 = &ip_privileged_port_min,
.extra2 = &ip_privileged_port_max,
};
pports = net->ipv4.sysctl_ip_prot_sock;
ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
if (write && ret == 0) {
inet_get_local_port_range(net, &range[0], &range[1]);
/* Ensure that the local port range doesn't overlap with the
* privileged port range.
*/
if (range[0] < pports)
ret = -EINVAL;
else
net->ipv4.sysctl_ip_prot_sock = pports;
}
return ret;
}
static void inet_get_ping_group_range_table(struct ctl_table *table, kgid_t *low, kgid_t *high) static void inet_get_ping_group_range_table(struct ctl_table *table, kgid_t *low, kgid_t *high)
{ {
...@@ -964,6 +1005,13 @@ static struct ctl_table ipv4_net_table[] = { ...@@ -964,6 +1005,13 @@ static struct ctl_table ipv4_net_table[] = {
.extra2 = &one, .extra2 = &one,
}, },
#endif #endif
{
.procname = "ip_unprivileged_port_start",
.maxlen = sizeof(int),
.data = &init_net.ipv4.sysctl_ip_prot_sock,
.mode = 0644,
.proc_handler = ipv4_privileged_ports,
},
{ } { }
}; };
......
...@@ -302,7 +302,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -302,7 +302,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
return -EINVAL; return -EINVAL;
snum = ntohs(addr->sin6_port); snum = ntohs(addr->sin6_port);
if (snum && snum < PROT_SOCK && !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) if (snum && snum < inet_prot_sock(net) &&
!ns_capable(net->user_ns, CAP_NET_BIND_SERVICE))
return -EACCES; return -EACCES;
lock_sock(sk); lock_sock(sk);
......
...@@ -426,10 +426,9 @@ ip_vs_service_find(struct netns_ipvs *ipvs, int af, __u32 fwmark, __u16 protocol ...@@ -426,10 +426,9 @@ ip_vs_service_find(struct netns_ipvs *ipvs, int af, __u32 fwmark, __u16 protocol
*/ */
svc = __ip_vs_service_find(ipvs, af, protocol, vaddr, vport); svc = __ip_vs_service_find(ipvs, af, protocol, vaddr, vport);
if (svc == NULL if (!svc && protocol == IPPROTO_TCP &&
&& protocol == IPPROTO_TCP atomic_read(&ipvs->ftpsvc_counter) &&
&& atomic_read(&ipvs->ftpsvc_counter) (vport == FTPDATA || ntohs(vport) >= inet_prot_sock(ipvs->net))) {
&& (vport == FTPDATA || ntohs(vport) >= PROT_SOCK)) {
/* /*
* Check if ftp service entry exists, the packet * Check if ftp service entry exists, the packet
* might belong to FTP data connections. * might belong to FTP data connections.
......
...@@ -360,7 +360,7 @@ static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) ...@@ -360,7 +360,7 @@ static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
} }
} }
if (snum && snum < PROT_SOCK && if (snum && snum < inet_prot_sock(net) &&
!ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE))
return -EACCES; return -EACCES;
...@@ -1152,8 +1152,10 @@ static int __sctp_connect(struct sock *sk, ...@@ -1152,8 +1152,10 @@ static int __sctp_connect(struct sock *sk,
* accept new associations, but it SHOULD NOT * accept new associations, but it SHOULD NOT
* be permitted to open new associations. * be permitted to open new associations.
*/ */
if (ep->base.bind_addr.port < PROT_SOCK && if (ep->base.bind_addr.port <
!ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) { inet_prot_sock(net) &&
!ns_capable(net->user_ns,
CAP_NET_BIND_SERVICE)) {
err = -EACCES; err = -EACCES;
goto out_free; goto out_free;
} }
...@@ -1818,7 +1820,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) ...@@ -1818,7 +1820,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
* but it SHOULD NOT be permitted to open new * but it SHOULD NOT be permitted to open new
* associations. * associations.
*/ */
if (ep->base.bind_addr.port < PROT_SOCK && if (ep->base.bind_addr.port < inet_prot_sock(net) &&
!ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) { !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) {
err = -EACCES; err = -EACCES;
goto out_unlock; goto out_unlock;
......
...@@ -4365,7 +4365,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in ...@@ -4365,7 +4365,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
inet_get_local_port_range(sock_net(sk), &low, &high); inet_get_local_port_range(sock_net(sk), &low, &high);
if (snum < max(PROT_SOCK, low) || snum > high) { if (snum < max(inet_prot_sock(sock_net(sk)), low) ||
snum > high) {
err = sel_netport_sid(sk->sk_protocol, err = sel_netport_sid(sk->sk_protocol,
snum, &sid); snum, &sid);
if (err) if (err)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment