Skip to content

Commit 60ca151

Browse files
Hakon-Buggejfvogel
authored andcommitted
net: rds: Use address family to designate IPv4 or IPv6 addresses
The condition to interpret the supplied address in rds_cancel_sent_to() was the length of the supplied user-data. We need to tighten the API here to the extent possible, subject to SKGXP passing in sizeof(struct sockaddr_storage) as the optlen, independent of the actual address size. We will 1) make sure the data passed in to the kernel is "big enough", 2) that the address is either AF_INET or AF_INET6, and 3) that the bound address is ipv6_addr_v4mapped() in the AF_INET case and not in the AF_INET6 case. Orabug: 28720071 Signed-off-by: Håkon Bugge <[email protected]> Reviewed-by: Darren Kenny <[email protected]>
1 parent 738eb59 commit 60ca151

File tree

1 file changed

+33
-15
lines changed

1 file changed

+33
-15
lines changed

net/rds/af_rds.c

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,9 @@ static int rds_cancel_sent_to(struct rds_sock *rs, char __user *optval,
307307
int len)
308308
{
309309
struct sockaddr_in6 sin6;
310-
struct sockaddr_in sin;
310+
int cpy_len;
311311
int ret = 0;
312+
bool is_v4;
312313

313314
/* racing with another thread binding seems ok here */
314315
if (ipv6_addr_any(&rs->rs_bound_addr)) {
@@ -319,20 +320,37 @@ static int rds_cancel_sent_to(struct rds_sock *rs, char __user *optval,
319320
if (len < sizeof(struct sockaddr_in)) {
320321
ret = -EINVAL;
321322
goto out;
322-
} else if (len < sizeof(struct sockaddr_in6)) {
323-
/* Assume IPv4 */
324-
if (copy_from_user(&sin, optval, sizeof(struct sockaddr_in))) {
325-
ret = -EFAULT;
326-
goto out;
327-
}
328-
ipv6_addr_set_v4mapped(sin.sin_addr.s_addr, &sin6.sin6_addr);
329-
sin6.sin6_port = sin.sin_port;
330-
} else {
331-
if (copy_from_user(&sin6, optval,
332-
sizeof(struct sockaddr_in6))) {
333-
ret = -EFAULT;
334-
goto out;
335-
}
323+
}
324+
325+
/* Lets restrict copying to at most sizeof(sin6) */
326+
cpy_len = min_t(int, (int)sizeof(sin6), len);
327+
if (copy_from_user(&sin6, optval, cpy_len)) {
328+
ret = -EFAULT;
329+
goto out;
330+
}
331+
332+
/* We only support IPv4 and IPv6 */
333+
if (sin6.sin6_family != AF_INET && sin6.sin6_family != AF_INET6) {
334+
ret = -EINVAL;
335+
goto out;
336+
}
337+
338+
is_v4 = (sin6.sin6_family == AF_INET);
339+
340+
/* Check that the bound address matches the supplied af */
341+
if (ipv6_addr_v4mapped(&rs->rs_bound_sin6.sin6_addr) != is_v4) {
342+
ret = -EINVAL;
343+
goto out;
344+
}
345+
346+
if (is_v4) {
347+
const struct sockaddr_in *sin4p = (struct sockaddr_in *)&sin6;
348+
349+
ipv6_addr_set_v4mapped(sin4p->sin_addr.s_addr, &sin6.sin6_addr);
350+
sin6.sin6_port = sin4p->sin_port;
351+
} else if (cpy_len != sizeof(sin6)) {
352+
ret = -EINVAL;
353+
goto out;
336354
}
337355

338356
rds_send_drop_to(rs, &sin6);

0 commit comments

Comments
 (0)