rxrpc: Fix network address validation
authorDavid Howells <dhowells@redhat.com>
Mon, 14 Nov 2022 11:24:09 +0000 (11:24 +0000)
committerDavid Howells <dhowells@redhat.com>
Wed, 16 Nov 2022 08:05:11 +0000 (08:05 +0000)
Fix network address validation on entry to uapi functions such as connect()
for AF_RXRPC.  The check for address compatibility with the transport
socket isn't correct and allows an AF_INET6 address to be given to an
AF_INET socket, resulting in an oops now that rxrpc is calling
udp_sendmsg() directly.

Sample program:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/rxrpc.h>
static unsigned char ctrl[256] =
"\x18\x00\x00\x00\x00\x00\x00\x00\x10\x01\x00\x00\x01";
int main(void)
{
struct sockaddr_rxrpc srx = {
.srx_family = AF_RXRPC,
.transport_type = SOCK_DGRAM,
.transport_len = 28,
.transport.sin6.sin6_family = AF_INET6,
};
struct mmsghdr vec = {
.msg_hdr.msg_control = ctrl,
.msg_hdr.msg_controllen = 0x18,
};
int s;
s = socket(AF_RXRPC, SOCK_DGRAM, AF_INET);
if (s < 0) {
perror("socket");
exit(1);
}
if (connect(s, (struct sockaddr *)&srx, sizeof(srx)) < 0) {
perror("connect");
exit(1);
}
if (sendmmsg(s, &vec, 1, MSG_NOSIGNAL | MSG_MORE) < 0) {
perror("sendmmsg");
exit(1);
}
return 0;
}

If working properly, connect() should fail with EAFNOSUPPORT.

Fixes: ed472b0c8783 ("rxrpc: Call udp_sendmsg() directly")
Reported-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org

net/rxrpc/af_rxrpc.c

index 2f3991cf87153a3b85fafd6c75e0b00f4de7ffee..aacdd96a98864f4e5c3d11eed333e4e33992f205 100644 (file)
@@ -93,12 +93,11 @@ static int rxrpc_validate_address(struct rxrpc_sock *rx,
            srx->transport_len > len)
                return -EINVAL;
 
            srx->transport_len > len)
                return -EINVAL;
 
-       if (srx->transport.family != rx->family &&
-           srx->transport.family == AF_INET && rx->family != AF_INET6)
-               return -EAFNOSUPPORT;
-
        switch (srx->transport.family) {
        case AF_INET:
        switch (srx->transport.family) {
        case AF_INET:
+               if (rx->family != AF_INET &&
+                   rx->family != AF_INET6)
+                       return -EAFNOSUPPORT;
                if (srx->transport_len < sizeof(struct sockaddr_in))
                        return -EINVAL;
                tail = offsetof(struct sockaddr_rxrpc, transport.sin.__pad);
                if (srx->transport_len < sizeof(struct sockaddr_in))
                        return -EINVAL;
                tail = offsetof(struct sockaddr_rxrpc, transport.sin.__pad);
@@ -106,6 +105,8 @@ static int rxrpc_validate_address(struct rxrpc_sock *rx,
 
 #ifdef CONFIG_AF_RXRPC_IPV6
        case AF_INET6:
 
 #ifdef CONFIG_AF_RXRPC_IPV6
        case AF_INET6:
+               if (rx->family != AF_INET6)
+                       return -EAFNOSUPPORT;
                if (srx->transport_len < sizeof(struct sockaddr_in6))
                        return -EINVAL;
                tail = offsetof(struct sockaddr_rxrpc, transport) +
                if (srx->transport_len < sizeof(struct sockaddr_in6))
                        return -EINVAL;
                tail = offsetof(struct sockaddr_rxrpc, transport) +