Skip to content

Commit 826799e

Browse files
J. Bruce FieldsTrond Myklebust
authored andcommitted
sunrpc: safely reallow resvport min/max inversion
Commits ffb6ca3 and e08ea3a 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: ffb6ca3 "sunrpc: Prevent resvport min/max inversion..." Fixes: e08ea3a "sunrpc: Prevent rexvport min/max inversion..." Signed-off-by: J. Bruce Fields <bfields@redhat.com> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
1 parent fc18751 commit 826799e

File tree

1 file changed

+18
-16
lines changed

1 file changed

+18
-16
lines changed

net/sunrpc/xprtsock.c

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,15 @@ static struct ctl_table xs_tunables_table[] = {
129129
.mode = 0644,
130130
.proc_handler = proc_dointvec_minmax,
131131
.extra1 = &xprt_min_resvport_limit,
132-
.extra2 = &xprt_max_resvport
132+
.extra2 = &xprt_max_resvport_limit
133133
},
134134
{
135135
.procname = "max_resvport",
136136
.data = &xprt_max_resvport,
137137
.maxlen = sizeof(unsigned int),
138138
.mode = 0644,
139139
.proc_handler = proc_dointvec_minmax,
140-
.extra1 = &xprt_min_resvport,
140+
.extra1 = &xprt_min_resvport_limit,
141141
.extra2 = &xprt_max_resvport_limit
142142
},
143143
{
@@ -1615,11 +1615,17 @@ static void xs_udp_timer(struct rpc_xprt *xprt, struct rpc_task *task)
16151615
spin_unlock_bh(&xprt->transport_lock);
16161616
}
16171617

1618-
static unsigned short xs_get_random_port(void)
1618+
static int xs_get_random_port(void)
16191619
{
1620-
unsigned short range = xprt_max_resvport - xprt_min_resvport + 1;
1621-
unsigned short rand = (unsigned short) prandom_u32() % range;
1622-
return rand + xprt_min_resvport;
1620+
unsigned short min = xprt_min_resvport, max = xprt_max_resvport;
1621+
unsigned short range;
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;
16231629
}
16241630

16251631
/**
@@ -1675,9 +1681,9 @@ static void xs_set_srcport(struct sock_xprt *transport, struct socket *sock)
16751681
transport->srcport = xs_sock_getport(sock);
16761682
}
16771683

1678-
static unsigned short xs_get_srcport(struct sock_xprt *transport)
1684+
static int xs_get_srcport(struct sock_xprt *transport)
16791685
{
1680-
unsigned short port = transport->srcport;
1686+
int port = transport->srcport;
16811687

16821688
if (port == 0 && transport->xprt.resvport)
16831689
port = xs_get_random_port();
@@ -1698,7 +1704,7 @@ static int xs_bind(struct sock_xprt *transport, struct socket *sock)
16981704
{
16991705
struct sockaddr_storage myaddr;
17001706
int err, nloop = 0;
1701-
unsigned short port = xs_get_srcport(transport);
1707+
int port = xs_get_srcport(transport);
17021708
unsigned short last;
17031709

17041710
/*
@@ -1716,8 +1722,8 @@ static int xs_bind(struct sock_xprt *transport, struct socket *sock)
17161722
* transport->xprt.resvport == 1) xs_get_srcport above will
17171723
* ensure that port is non-zero and we will bind as needed.
17181724
*/
1719-
if (port == 0)
1720-
return 0;
1725+
if (port <= 0)
1726+
return port;
17211727

17221728
memcpy(&myaddr, &transport->srcaddr, transport->xprt.addrlen);
17231729
do {
@@ -3154,12 +3160,8 @@ static int param_set_uint_minmax(const char *val,
31543160

31553161
static int param_set_portnr(const char *val, const struct kernel_param *kp)
31563162
{
3157-
if (kp->arg == &xprt_min_resvport)
3158-
return param_set_uint_minmax(val, kp,
3159-
RPC_MIN_RESVPORT,
3160-
xprt_max_resvport);
31613163
return param_set_uint_minmax(val, kp,
3162-
xprt_min_resvport,
3164+
RPC_MIN_RESVPORT,
31633165
RPC_MAX_RESVPORT);
31643166
}
31653167

0 commit comments

Comments
 (0)