aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2018-10-18 15:27:02 -0400
committerTrond Myklebust <trond.myklebust@hammerspace.com>2018-10-18 17:20:57 -0400
commit826799e66e8683e5698e140bb9ef69afc8c0014e (patch)
tree8c1998d6ef140e64bd45152d035c087aa356e292
parentfc187514d8af3a676c7bd7922439f9f5e5c6223f (diff)
sunrpc: safely reallow resvport min/max inversion
Commits ffb6ca33b04b and e08ea3a96fc7 prevent setting xprt_min_resvport greater than xprt_max_resvport, but may also break simple code that sets one parameter then the other, if the new range does not overlap the old. Also it looks racy to me, unless there's some serialization I'm not seeing. Granted it would probably require malicious privileged processes (unless there's a chance these might eventually be settable in unprivileged containers), but still it seems better not to let userspace panic the kernel. Simpler seems to be to allow setting the parameters to whatever you want but interpret xprt_min_resvport > xprt_max_resvport as the empty range. Fixes: ffb6ca33b04b "sunrpc: Prevent resvport min/max inversion..." Fixes: e08ea3a96fc7 "sunrpc: Prevent rexvport min/max inversion..." Signed-off-by: J. Bruce Fields <bfields@redhat.com> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
-rw-r--r--net/sunrpc/xprtsock.c34
1 files changed, 18 insertions, 16 deletions
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 039444eb138f..9bb86cd3ee56 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -129,7 +129,7 @@ static struct ctl_table xs_tunables_table[] = {
129 .mode = 0644, 129 .mode = 0644,
130 .proc_handler = proc_dointvec_minmax, 130 .proc_handler = proc_dointvec_minmax,
131 .extra1 = &xprt_min_resvport_limit, 131 .extra1 = &xprt_min_resvport_limit,
132 .extra2 = &xprt_max_resvport 132 .extra2 = &xprt_max_resvport_limit
133 }, 133 },
134 { 134 {
135 .procname = "max_resvport", 135 .procname = "max_resvport",
@@ -137,7 +137,7 @@ static struct ctl_table xs_tunables_table[] = {
137 .maxlen = sizeof(unsigned int), 137 .maxlen = sizeof(unsigned int),
138 .mode = 0644, 138 .mode = 0644,
139 .proc_handler = proc_dointvec_minmax, 139 .proc_handler = proc_dointvec_minmax,
140 .extra1 = &xprt_min_resvport, 140 .extra1 = &xprt_min_resvport_limit,
141 .extra2 = &xprt_max_resvport_limit 141 .extra2 = &xprt_max_resvport_limit
142 }, 142 },
143 { 143 {
@@ -1615,11 +1615,17 @@ static void xs_udp_timer(struct rpc_xprt *xprt, struct rpc_task *task)
1615 spin_unlock_bh(&xprt->transport_lock); 1615 spin_unlock_bh(&xprt->transport_lock);
1616} 1616}
1617 1617
1618static unsigned short xs_get_random_port(void) 1618static int xs_get_random_port(void)
1619{ 1619{
1620 unsigned short range = xprt_max_resvport - xprt_min_resvport + 1; 1620 unsigned short min = xprt_min_resvport, max = xprt_max_resvport;
1621 unsigned short rand = (unsigned short) prandom_u32() % range; 1621 unsigned short range;
1622 return rand + xprt_min_resvport; 1622 unsigned short rand;
1623
1624 if (max < min)
1625 return -EADDRINUSE;
1626 range = max - min + 1;
1627 rand = (unsigned short) prandom_u32() % range;
1628 return rand + min;
1623} 1629}
1624 1630
1625/** 1631/**
@@ -1675,9 +1681,9 @@ static void xs_set_srcport(struct sock_xprt *transport, struct socket *sock)
1675 transport->srcport = xs_sock_getport(sock); 1681 transport->srcport = xs_sock_getport(sock);
1676} 1682}
1677 1683
1678static unsigned short xs_get_srcport(struct sock_xprt *transport) 1684static int xs_get_srcport(struct sock_xprt *transport)
1679{ 1685{
1680 unsigned short port = transport->srcport; 1686 int port = transport->srcport;
1681 1687
1682 if (port == 0 && transport->xprt.resvport) 1688 if (port == 0 && transport->xprt.resvport)
1683 port = xs_get_random_port(); 1689 port = xs_get_random_port();
@@ -1698,7 +1704,7 @@ static int xs_bind(struct sock_xprt *transport, struct socket *sock)
1698{ 1704{
1699 struct sockaddr_storage myaddr; 1705 struct sockaddr_storage myaddr;
1700 int err, nloop = 0; 1706 int err, nloop = 0;
1701 unsigned short port = xs_get_srcport(transport); 1707 int port = xs_get_srcport(transport);
1702 unsigned short last; 1708 unsigned short last;
1703 1709
1704 /* 1710 /*
@@ -1716,8 +1722,8 @@ static int xs_bind(struct sock_xprt *transport, struct socket *sock)
1716 * transport->xprt.resvport == 1) xs_get_srcport above will 1722 * transport->xprt.resvport == 1) xs_get_srcport above will
1717 * ensure that port is non-zero and we will bind as needed. 1723 * ensure that port is non-zero and we will bind as needed.
1718 */ 1724 */
1719 if (port == 0) 1725 if (port <= 0)
1720 return 0; 1726 return port;
1721 1727
1722 memcpy(&myaddr, &transport->srcaddr, transport->xprt.addrlen); 1728 memcpy(&myaddr, &transport->srcaddr, transport->xprt.addrlen);
1723 do { 1729 do {
@@ -3154,12 +3160,8 @@ static int param_set_uint_minmax(const char *val,
3154 3160
3155static int param_set_portnr(const char *val, const struct kernel_param *kp) 3161static int param_set_portnr(const char *val, const struct kernel_param *kp)
3156{ 3162{
3157 if (kp->arg == &xprt_min_resvport)
3158 return param_set_uint_minmax(val, kp,
3159 RPC_MIN_RESVPORT,
3160 xprt_max_resvport);
3161 return param_set_uint_minmax(val, kp, 3163 return param_set_uint_minmax(val, kp,
3162 xprt_min_resvport, 3164 RPC_MIN_RESVPORT,
3163 RPC_MAX_RESVPORT); 3165 RPC_MAX_RESVPORT);
3164} 3166}
3165 3167