Skip to content

Commit cc14b1c

Browse files
Hakon-Buggegerd-rausch
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: 28720018 Signed-off-by: Håkon Bugge <[email protected]> Reviewed-by: Darren Kenny <[email protected]>
1 parent af15390 commit cc14b1c

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
@@ -328,8 +328,9 @@ static int rds_cancel_sent_to(struct rds_sock *rs, char __user *optval,
328328
int len)
329329
{
330330
struct sockaddr_in6 sin6;
331-
struct sockaddr_in sin;
331+
int cpy_len;
332332
int ret = 0;
333+
bool is_v4;
333334

334335
/* racing with another thread binding seems ok here */
335336
if (ipv6_addr_any(&rs->rs_bound_addr)) {
@@ -340,20 +341,37 @@ static int rds_cancel_sent_to(struct rds_sock *rs, char __user *optval,
340341
if (len < sizeof(struct sockaddr_in)) {
341342
ret = -EINVAL;
342343
goto out;
343-
} else if (len < sizeof(struct sockaddr_in6)) {
344-
/* Assume IPv4 */
345-
if (copy_from_user(&sin, optval, sizeof(struct sockaddr_in))) {
346-
ret = -EFAULT;
347-
goto out;
348-
}
349-
ipv6_addr_set_v4mapped(sin.sin_addr.s_addr, &sin6.sin6_addr);
350-
sin6.sin6_port = sin.sin_port;
351-
} else {
352-
if (copy_from_user(&sin6, optval,
353-
sizeof(struct sockaddr_in6))) {
354-
ret = -EFAULT;
355-
goto out;
356-
}
344+
}
345+
346+
/* Lets restrict copying to at most sizeof(sin6) */
347+
cpy_len = min_t(int, (int)sizeof(sin6), len);
348+
if (copy_from_user(&sin6, optval, cpy_len)) {
349+
ret = -EFAULT;
350+
goto out;
351+
}
352+
353+
/* We only support IPv4 and IPv6 */
354+
if (sin6.sin6_family != AF_INET && sin6.sin6_family != AF_INET6) {
355+
ret = -EINVAL;
356+
goto out;
357+
}
358+
359+
is_v4 = (sin6.sin6_family == AF_INET);
360+
361+
/* Check that the bound address matches the supplied af */
362+
if (ipv6_addr_v4mapped(&rs->rs_bound_sin6.sin6_addr) != is_v4) {
363+
ret = -EINVAL;
364+
goto out;
365+
}
366+
367+
if (is_v4) {
368+
const struct sockaddr_in *sin4p = (struct sockaddr_in *)&sin6;
369+
370+
ipv6_addr_set_v4mapped(sin4p->sin_addr.s_addr, &sin6.sin6_addr);
371+
sin6.sin6_port = sin4p->sin_port;
372+
} else if (cpy_len != sizeof(sin6)) {
373+
ret = -EINVAL;
374+
goto out;
357375
}
358376

359377
rds_send_drop_to(rs, &sin6);

0 commit comments

Comments
 (0)