From d04abc1ab24a0ba0c3803257ac89c7c5b3b9c374 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Tue, 8 Sep 2015 16:06:41 -0600 Subject: [PATCH] net: Fail explicit bind to local reserved ports Reserved ports may have some special use cases which are not suitable for use by general userspace applications. Currently, ports specified in ip_local_reserved_ports will not be returned only in case of automatic port assignment. Add a boolean sysctl flag 'reserved_port_bind'. Default value is 1 which preserves the existing behavior. Setting the value to 0 will prevent userspace applications from binding to these ports even when they are explicitly requested. BUG=20663075 Change-Id: Ib1071ca5bd437cd3c4f71b56147e4858f3b9ebec Signed-off-by: Subash Abhinov Kasiviswanathan --- Documentation/networking/ip-sysctl.txt | 5 +++++ include/net/ip.h | 2 ++ net/ipv4/af_inet.c | 2 ++ net/ipv4/inet_connection_sock.c | 7 +++++++ net/ipv4/sysctl_net_ipv4.c | 7 +++++++ net/ipv4/udp.c | 5 +++++ 6 files changed, 28 insertions(+) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 2042261408b9..ca0476e0a15b 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -829,6 +829,11 @@ ip_local_reserved_ports - list of comma separated ranges Default: Empty +reserved_port_bind - BOOLEAN + If set, allows explicit bind requests to applications requesting + any port within the range of ip_local_reserved_ports. + Default: 1 + ip_nonlocal_bind - BOOLEAN If set, allows processes to bind() to non-local IP addresses, which can be quite useful - but may break some applications. diff --git a/include/net/ip.h b/include/net/ip.h index 4f3ef345f4c2..e5a1d35b9905 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -241,6 +241,8 @@ static inline int inet_is_local_reserved_port(struct net *net, int port) } #endif +extern int sysctl_reserved_port_bind; + /* From inetpeer.c */ extern int inet_peer_threshold; extern int inet_peer_minttl; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 671eb0092915..a243ef1d7aa0 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -135,6 +135,8 @@ static inline int current_has_network(void) } #endif +int sysctl_reserved_port_bind __read_mostly = 1; + /* The inetsw table contains everything that inet_create needs to * build a new socket. */ diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index a4cfa14c73ee..fd1946ca8aec 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -179,6 +179,13 @@ have_snum: head = &hashinfo->bhash[inet_bhashfn(net, snum, hashinfo->bhash_size)]; spin_lock(&head->lock); + + if (inet_is_local_reserved_port(net, snum) && + !sysctl_reserved_port_bind) { + ret = 1; + goto fail_unlock; + } + inet_bind_bucket_for_each(tb, &head->chain) if (net_eq(ib_net(tb), net) && tb->port == snum) goto tb_found; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index b1784c897e6c..24029ecf17ac 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -902,6 +902,13 @@ static struct ctl_table ipv4_net_table[] = { .mode = 0644, .proc_handler = proc_do_large_bitmap, }, + { + .procname = "reserved_port_bind", + .data = &sysctl_reserved_port_bind, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, { .procname = "ip_no_pmtu_disc", .data = &init_net.ipv4.sysctl_ip_no_pmtu_disc, diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 510fcd68aaef..424e036f9c4f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -257,6 +257,11 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, } else { hslot = udp_hashslot(udptable, net, snum); spin_lock_bh(&hslot->lock); + + if (inet_is_local_reserved_port(net, snum) && + !sysctl_reserved_port_bind) + goto fail_unlock; + if (hslot->count > 10) { int exist; unsigned int slot2 = udp_sk(sk)->udp_portaddr_hash ^ snum;