[Openvpn-devel,ovpn,net,4/4] ovpn: recheck UDP socket family before transmit

Message ID 20260526124544.425791-4-ralf@mandelbit.com
State New
Headers show
Series [Openvpn-devel,ovpn,net,1/4] ovpn: avoid sending UDP packets with source port 0 | expand

Commit Message

Ralf Lici May 26, 2026, 12:45 p.m. UTC
ovpn validates UDP peer remotes against the socket family when the
remote endpoint is configured through netlink. The socket itself,
however, remains owned by userspace and some socket options can still
change the family seen by the transmit path.

For example, IPV6_ADDRFORM can turn an AF_INET6 socket into AF_INET
after ovpn accepted an IPv6 remote. Conversely, IPV6_V6ONLY can make a
dual-stack AF_INET6 socket unable to send to an IPv4 remote.

Recheck the socket family in ovpn_udp_output before selecting the UDP
transmit path. Drop the packet with -EAFNOSUPPORT when the peer remote
family no longer matches the socket state.

Fixes: 08857b5ec5d9 ("ovpn: implement basic TX path (UDP)")
Signed-off-by: Ralf Lici <ralf@mandelbit.com>
---
 drivers/net/ovpn/udp.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

Patch

diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c
index 2610f3e23bf0..9a3d3dc11235 100644
--- a/drivers/net/ovpn/udp.c
+++ b/drivers/net/ovpn/udp.c
@@ -320,18 +320,25 @@  static int ovpn_udp_output(struct ovpn_peer *peer, struct dst_cache *cache,
 		goto out;
 	}
 
+	ret = -EAFNOSUPPORT;
 	switch (bind->remote.in4.sin_family) {
 	case AF_INET:
+		/* userspace might have set IPV6_ONLY */
+		if (unlikely(READ_ONCE(sk->sk_family) == AF_INET6 &&
+			     ipv6_only_sock(sk)))
+			break;
+
 		ret = ovpn_udp4_output(peer, bind, cache, sk, skb);
 		break;
 #if IS_ENABLED(CONFIG_IPV6)
 	case AF_INET6:
+		/* userspace might have set IPV6_ADDRFORM */
+		if (unlikely(READ_ONCE(sk->sk_family) != AF_INET6))
+			break;
+
 		ret = ovpn_udp6_output(peer, bind, cache, sk, skb);
 		break;
 #endif
-	default:
-		ret = -EAFNOSUPPORT;
-		break;
 	}
 
 out: