This bug was found with syzkaller on Linux kernel v5.10. This patch series fixes the bug.
Signed-off-by: Alexander Ofitserov oficerovas@altlinux.org Cc: stable@vger.kernel.org
Xin Long (1): rxrpc: use udp tunnel APIs instead of open code in rxrpc_open_socket
David Howells (2): rxrpc: Fix missing dependency on NET_UDP_TUNNEL rxrpc: Enable IPv6 checksums on transport socket
Vadim Fedorenko (1): rxrpc: Fix dependency on IPv6 in udp tunnel config
net/rxrpc/Kconfig | 1 + net/rxrpc/local_object.c | 77 +++++++++++++++------------------------- 2 files changed, 30 insertions(+), 48 deletions(-)
From: Xin Long lucien.xin@gmail.com
[ Upstream commit 1a9b86c9fd9536b5c0dfbf7b4acbb7f61c820b74 ]
In rxrpc_open_socket(), now it's using sock_create_kern() and kernel_bind() to create a udp tunnel socket, and other kernel APIs to set up it. These code can be replaced with udp tunnel APIs udp_sock_create() and setup_udp_tunnel_sock(), and it'll simplify rxrpc_open_socket().
Note that with this patch, the udp tunnel socket will always bind to a random port if transport is not provided by users, which is suggested by David Howells, thanks!
Acked-by: David Howells dhowells@redhat.com Signed-off-by: Xin Long lucien.xin@gmail.com Reviewed-by: Vadim Fedorenko vfedorenko@novek.ru Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Alexander Ofitserov oficerovas@altlinux.org Cc: stable@vger.kernel.org --- net/rxrpc/local_object.c | 72 ++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 48 deletions(-)
diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c index 2c66ee981f395b..8f9c06fd37e984 100644 --- a/net/rxrpc/local_object.c +++ b/net/rxrpc/local_object.c @@ -16,6 +16,7 @@ #include <linux/hashtable.h> #include <net/sock.h> #include <net/udp.h> +#include <net/udp_tunnel.h> #include <net/af_rxrpc.h> #include "ar-internal.h"
@@ -106,58 +107,42 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet, */ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net) { + struct udp_tunnel_sock_cfg tuncfg = {NULL}; + struct sockaddr_rxrpc *srx = &local->srx; + struct udp_port_cfg udp_conf = {0}; struct sock *usk; int ret;
_enter("%p{%d,%d}", - local, local->srx.transport_type, local->srx.transport.family); + local, srx->transport_type, srx->transport.family);
- /* create a socket to represent the local endpoint */ - ret = sock_create_kern(net, local->srx.transport.family, - local->srx.transport_type, 0, &local->socket); + udp_conf.family = srx->transport.family; + if (udp_conf.family == AF_INET) { + udp_conf.local_ip = srx->transport.sin.sin_addr; + udp_conf.local_udp_port = srx->transport.sin.sin_port; + } else { + udp_conf.local_ip6 = srx->transport.sin6.sin6_addr; + udp_conf.local_udp_port = srx->transport.sin6.sin6_port; + } + ret = udp_sock_create(net, &udp_conf, &local->socket); if (ret < 0) { _leave(" = %d [socket]", ret); return ret; }
+ tuncfg.encap_type = UDP_ENCAP_RXRPC; + tuncfg.encap_rcv = rxrpc_input_packet; + tuncfg.sk_user_data = local; + setup_udp_tunnel_sock(net, local->socket, &tuncfg); + /* set the socket up */ usk = local->socket->sk; - inet_sk(usk)->mc_loop = 0; - - /* Enable CHECKSUM_UNNECESSARY to CHECKSUM_COMPLETE conversion */ - inet_inc_convert_csum(usk); - - rcu_assign_sk_user_data(usk, local); - - udp_sk(usk)->encap_type = UDP_ENCAP_RXRPC; - udp_sk(usk)->encap_rcv = rxrpc_input_packet; - udp_sk(usk)->encap_destroy = NULL; - udp_sk(usk)->gro_receive = NULL; - udp_sk(usk)->gro_complete = NULL; - - udp_encap_enable(); -#if IS_ENABLED(CONFIG_AF_RXRPC_IPV6) - if (local->srx.transport.family == AF_INET6) - udpv6_encap_enable(); -#endif usk->sk_error_report = rxrpc_error_report;
- /* if a local address was supplied then bind it */ - if (local->srx.transport_len > sizeof(sa_family_t)) { - _debug("bind"); - ret = kernel_bind(local->socket, - (struct sockaddr *)&local->srx.transport, - local->srx.transport_len); - if (ret < 0) { - _debug("bind failed %d", ret); - goto error; - } - } - - switch (local->srx.transport.family) { + switch (srx->transport.family) { case AF_INET6: /* we want to receive ICMPv6 errors */ - ip6_sock_set_recverr(local->socket->sk); + ip6_sock_set_recverr(usk);
/* Fall through and set IPv4 options too otherwise we don't get * errors from IPv4 packets sent through the IPv6 socket. @@ -165,13 +150,13 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net) fallthrough; case AF_INET: /* we want to receive ICMP errors */ - ip_sock_set_recverr(local->socket->sk); + ip_sock_set_recverr(usk);
/* we want to set the don't fragment bit */ - ip_sock_set_mtu_discover(local->socket->sk, IP_PMTUDISC_DO); + ip_sock_set_mtu_discover(usk, IP_PMTUDISC_DO);
/* We want receive timestamps. */ - sock_enable_timestamps(local->socket->sk); + sock_enable_timestamps(usk); break;
default: @@ -180,15 +165,6 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net)
_leave(" = 0"); return 0; - -error: - kernel_sock_shutdown(local->socket, SHUT_RDWR); - local->socket->sk->sk_user_data = NULL; - sock_release(local->socket); - local->socket = NULL; - - _leave(" = %d", ret); - return ret; }
/*
From: David Howells dhowells@redhat.com
[ Upstream commit dc0e6056decc2c454f4d503fd73f8c57e16579a6 ]
The changes to make rxrpc create the udp socket missed a bit to add the Kconfig dependency on the udp tunnel code to do this.
Fix this by adding making AF_RXRPC select NET_UDP_TUNNEL.
Fixes: 1a9b86c9fd95 ("rxrpc: use udp tunnel APIs instead of open code in rxrpc_open_socket") Reported-by: kernel test robot lkp@intel.com Signed-off-by: Vadim Fedorenko vfedorenko@novek.ru Signed-off-by: David Howells dhowells@redhat.com Reviewed-by: Xin Long lucien.xin@gmail.com cc: alaa@dev.mellanox.co.il cc: Jakub Kicinski kuba@kernel.org Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Alexander Ofitserov oficerovas@altlinux.org Cc: stable@vger.kernel.org --- net/rxrpc/Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/net/rxrpc/Kconfig b/net/rxrpc/Kconfig index d706bb40836574..0885b22e5c0e4c 100644 --- a/net/rxrpc/Kconfig +++ b/net/rxrpc/Kconfig @@ -8,6 +8,7 @@ config AF_RXRPC depends on INET select CRYPTO select KEYS + select NET_UDP_TUNNEL help Say Y or M here to include support for RxRPC session sockets (just the transport part, not the presentation part: (un)marshalling is
From: Vadim Fedorenko vfedorenko@novek.ru
[ Upstream commit 295f830e53f4838344c97e12ce69637e2128ca8d ]
As udp_port_cfg struct changes its members with dependency on IPv6 configuration, the code in rxrpc should also check for IPv6.
Fixes: 1a9b86c9fd95 ("rxrpc: use udp tunnel APIs instead of open code in rxrpc_open_socket") Reported-by: kernel test robot lkp@intel.com Signed-off-by: Vadim Fedorenko vfedorenko@novek.ru Acked-by: David Howells dhowells@redhat.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Alexander Ofitserov oficerovas@altlinux.org Cc: stable@vger.kernel.org --- net/rxrpc/local_object.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c index 8f9c06fd37e984..6215800db33333 100644 --- a/net/rxrpc/local_object.c +++ b/net/rxrpc/local_object.c @@ -120,9 +120,11 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net) if (udp_conf.family == AF_INET) { udp_conf.local_ip = srx->transport.sin.sin_addr; udp_conf.local_udp_port = srx->transport.sin.sin_port; +#if IS_ENABLED(CONFIG_AF_RXRPC_IPV6) } else { udp_conf.local_ip6 = srx->transport.sin6.sin6_addr; udp_conf.local_udp_port = srx->transport.sin6.sin6_port; +#endif } ret = udp_sock_create(net, &udp_conf, &local->socket); if (ret < 0) {
From: David Howells dhowells@redhat.com
[ Upstream commit 39cb9faa5d46d0d0694f4b594ef905f517600c8e ]
AF_RXRPC doesn't currently enable IPv6 UDP Tx checksums on the transport socket it opens and the checksums in the packets it generates end up 0.
It probably should also enable IPv6 UDP Rx checksums and IPv4 UDP checksums. The latter only seem to be applied if the socket family is AF_INET and don't seem to apply if it's AF_INET6. IPv4 packets from an IPv6 socket seem to have checksums anyway.
What seems to have happened is that the inet_inv_convert_csum() call didn't get converted to the appropriate udp_port_cfg parameters - and udp_sock_create() disables checksums unless explicitly told not too.
Fix this by enabling the three udp_port_cfg checksum options.
Fixes: 1a9b86c9fd95 ("rxrpc: use udp tunnel APIs instead of open code in rxrpc_open_socket") Reported-by: Marc Dionne marc.dionne@auristor.com Signed-off-by: David Howells dhowells@redhat.com Reviewed-by: Xin Long lucien.xin@gmail.com Reviewed-by: Marc Dionne marc.dionne@auristor.com cc: Vadim Fedorenko vfedorenko@novek.ru cc: David S. Miller davem@davemloft.net cc: linux-afs@lists.infradead.org Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Alexander Ofitserov oficerovas@altlinux.org Cc: stable@vger.kernel.org --- net/rxrpc/local_object.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c index 6215800db33333..790c270c067850 100644 --- a/net/rxrpc/local_object.c +++ b/net/rxrpc/local_object.c @@ -117,6 +117,7 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net) local, srx->transport_type, srx->transport.family);
udp_conf.family = srx->transport.family; + udp_conf.use_udp_checksums = true; if (udp_conf.family == AF_INET) { udp_conf.local_ip = srx->transport.sin.sin_addr; udp_conf.local_udp_port = srx->transport.sin.sin_port; @@ -124,6 +125,8 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net) } else { udp_conf.local_ip6 = srx->transport.sin6.sin6_addr; udp_conf.local_udp_port = srx->transport.sin6.sin6_port; + udp_conf.use_udp6_tx_checksums = true; + udp_conf.use_udp6_rx_checksums = true; #endif } ret = udp_sock_create(net, &udp_conf, &local->socket);
linux-stable-mirror@lists.linaro.org