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.
CRs-Fixed: 2062245
BUG=20663075
Change-Id: Ib1071ca5bd437cd3c4f71b56147e4858f3b9ebec
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 39e9acf..e119855 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -136,6 +136,8 @@
}
#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 ceae0ea..c094ac9 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -111,6 +111,13 @@
head = &hinfo->bhash[inet_bhashfn(net, port,
hinfo->bhash_size)];
spin_lock_bh(&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 == port)
goto tb_found;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index cf7cfa4..08605a4 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -789,6 +789,13 @@
.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,
.maxlen = sizeof(int),
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 74001f1..fe24424 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -290,6 +290,11 @@
} 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;