From patchwork Fri Aug 28 14:50:27 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ralf Lici X-Patchwork-Id: 5294 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:c317:b0:87d:ab56:3700 with SMTP id jk23csp51097mab; Fri, 28 Aug 2026 07:50:58 -0700 (PDT) X-Forwarded-Encrypted: i=2; AHgh+RrgpeOMgE7iRpU8wBRbnCZNiRMQzIbYa7iNod4GaIoF0goni2tpvahy1BjtH52YY+oOJ/dBMAKNrNA=@openvpn.net X-Received: by 2002:a05:6820:1f03:b0:6b0:40d9:8ac6 with SMTP id 006d021491bc7-6b1c65c0755mr6888174eaf.9.1787928658316; Fri, 28 Aug 2026 07:50:58 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1787928658; cv=none; d=google.com; s=arc-20260327; b=QeOA7c0S+9E3SQ6XAS1xMOBXWAoTw0xNlu/Ipbro7WzD42jVY//MFsPlxh2WK4XS0v qEsdDmIoJo0oe+1HGK8w2TTJ6MXV8HsOqA78j094TXt5VXKh89sYtesgTU4F30RtVFAS DTgSk64UYcVx0zccAO3Fl60PWvhHWzZPjtCBqRnh/+2f5qdfew0NJ3A7ZOg8cZxFZ6uM z+dVanfN0oI3+AvqMCLYIK4qGI6tvGbghnlD+1QhwSJcq+sfqiilvAOPjBiuGMOUzbzi 8cHqA/pvOS4TRnRZZHgnP0pVQ6dP20CGN7OIpljpPBgy1lMCm9iT5lGBelkyhiFmeD5s 0L0g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=errors-to:content-transfer-encoding:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence:subject :mime-version:references:in-reply-to:message-id:date:to:from :dkim-signature:dkim-signature:dkim-signature:dkim-signature; bh=tClRIUGyA55VhPe3NOA8IHNCvXbiHNuJVk3aYt69FyI=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=WX7PJIAjQCMf7KtJJKv8adkOAiUwnqYRYIMoP6AdReB7Ia+5bMeEvomRIAe+KCilWQ aMvappqoQePZ7EFn48thIayIOTemFsYqt4kGCLfVlF1kevO6v1ytWz1TK/VVuqG8f8Of g3OWRFyV4QjbAMpah/wlo7rFa1lIKg7a+zAu2VVWxmSMVMNEYykPV917iA9ufOGd/fCt RtR1r84aBI2w1IKZvJGG2HP9q2clBbMXgy+Tqu5TIvDvg/Auv0XXmx1AzqQvqUBtcLft gieazqUYiR4gHhvjp8EfP8nxazELGP44HQOBg/ifU5i1ymO4+h+ERP2WlSWeai7pSD97 ywMg==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=OQMgUkcb; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=elqDQuQW; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=K6ajQTMY; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=yuzbJ6hd; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id 006d021491bc7-6b1ce0bb5d4si2574838eaf.14.2026.08.28.07.50.57 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 28 Aug 2026 07:50:58 -0700 (PDT) Received-SPF: pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) client-ip=216.105.38.7; Authentication-Results: mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=OQMgUkcb; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=elqDQuQW; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=K6ajQTMY; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=yuzbJ6hd; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.sourceforge.net; s=beta; h=Content-Transfer-Encoding:Content-Type: List-Subscribe:List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id: Subject:MIME-Version:References:In-Reply-To:Message-ID:Date:To:From:Sender: Reply-To:Cc:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=tClRIUGyA55VhPe3NOA8IHNCvXbiHNuJVk3aYt69FyI=; b=OQMgUkcbkm/ge5cxRXt0jT0ONh SWJcYFgxnwX+SDTJ/UiJbLknOrC0DKy+kjqsMJSJMvrOkONLe6TuazlRkn4gUQxVnmTB5amUcqAhM 3PCovlQ9ztkDFYlfnAJfn7HwlbSFtwpwIT41I9/pdMnJo3ZVw69E4E8//0UNliG37Fkc=; Received: from [127.0.0.1] (helo=sfs-ml-2.v29.lw.sourceforge.com) by sfs-ml-2.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1wzxuv-0000qh-RC; Fri, 28 Aug 2026 14:50:54 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-2.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1wzxuu-0000qI-Sh for openvpn-devel@lists.sourceforge.net; Fri, 28 Aug 2026 14:50:53 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=qltw84WDSXhVRMZbKrtV9oCHvmhpOCFBhSIDfqS5hB8=; b=elqDQuQWCahO7BctQ0uN38n4Hq rJwXOmIilWHjnnAhy1IM8rZNIqgHprUh8ANYF8ATLsu1cMI7jpt1uvje7e17bIi4QxAA+6l+sHfE2 Uy55sT0iy2RlshdkiHLLdu0intdtg0azLNYynyBtk4sjBGtqtMUyEjDYr1jwElM/QIyc=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID: Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=qltw84WDSXhVRMZbKrtV9oCHvmhpOCFBhSIDfqS5hB8=; b=K6ajQTMYuomZD10nQn26dWZbgu dsDX2bhAg/25cGo8w5tFNHgTJL9iEtmNcBiUWQhl0mrc9/7NvvA99IVVw/9G8InUKwSPXLoDCWTOj 3Sig6vyl7/OnSb18K+835XAo6CQnhiJj7MmAWZBFQhb1jg4sYggxyHscOIgjXajXnbqk=; Received: from mout-b-202.mailbox.org ([195.10.208.62]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1wzxuu-0005qe-4L for openvpn-devel@lists.sourceforge.net; Fri, 28 Aug 2026 14:50:53 +0000 Received: from smtp102.mailbox.org (smtp102.mailbox.org [IPv6:2001:67c:2050:b231:465::102]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-b-202.mailbox.org (Postfix) with ESMTPS id 4hWhC75fXszKnTQ for ; Fri, 28 Aug 2026 16:50:43 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mandelbit.com; s=MBO0001; t=1787928643; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qltw84WDSXhVRMZbKrtV9oCHvmhpOCFBhSIDfqS5hB8=; b=yuzbJ6hd8UQdXJ3QO9eakKZ5jVzSSXTUgKQV4xe0xNFFkMvSlXIg73qHeBuml66fXVBuav xfC0EDDqJQcuH5OvLc8A2KEVzp34TPA5x1YUhCNO0t0toP2SEYWOJOcmQHvlO2q+EmEF0p VAgAgCSDNGztPpOix7iBzfK0Wc//oSOteeOPDaK8TpsKsnH4tn/0TTTfFX9bQRTItIGTb5 epdseoJeEs2JG4GnEYpz3SgXUHU1eS8B8Ng8uvv004zaiPBOP+slaFwld+MSCVYZcsQk4k CuiZUfWoWibtItbyMj6PLbP8ILo8vv5Wpf8OWX55kRP2nKNQbaou0qQa8JcXpg== Authentication-Results: outgoing_mbo_mout; dkim=none; spf=pass (outgoing_mbo_mout: domain of ralf@mandelbit.com designates 2001:67c:2050:b231:465::102 as permitted sender) smtp.mailfrom=ralf@mandelbit.com From: Ralf Lici To: openvpn-devel@lists.sourceforge.net Date: Fri, 28 Aug 2026 16:50:27 +0200 Message-ID: <733af95bec0add37f18117c674543d4191f89d26.1787925761.git.ralf@mandelbit.com> In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: 4hWhC75fXszKnTQ X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "sfi-spamd-2.hosts.colo.sdot.me", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: The UDP output fallback clears bind->local in place when the remembered source address is no longer usable. The bind is RCU-published and read locklessly by concurrent TX, so an IPv6 reader can observ [...] Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-Headers-End: 1wzxuu-0005qe-4L Subject: [Openvpn-devel] [PATCH ovpn net v3 6/6] ovpn: replace bind when clearing stale local source X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox X-GMAIL-THRID: 1874779080484845483 X-GMAIL-MSGID: 1874779080484845483 The UDP output fallback clears bind->local in place when the remembered source address is no longer usable. The bind is RCU-published and read locklessly by concurrent TX, so an IPv6 reader can observe a torn address. Retry the route lookup with source address autoselection without modifying the bind. After a successful lookup, revalidate the bind and route key under peer->lock, reset the dst cache, and best-effort publish a replacement bind with a wildcard local address. Do not cache the resolved dst when clearing the local source. Replacing the source invalidates all per-CPU cache entries, while dst_cache_set_ip4 and dst_cache_set_ip6 update only the current CPU slot. The current packet can still use the resolved route; if bind allocation fails, a later cache miss retries the repair. Fixes: 08857b5ec5d9 ("ovpn: implement basic TX path (UDP)") Signed-off-by: Ralf Lici --- Changes since v2 https://lore.kernel.org/openvpn-devel/082540583b9145d89e1cdd5a74c485ea3a53d285.1785308184.git.ralf@mandelbit.com/ - Split former 4/5 into this plus the previous two patches. (Sabrina) - No functional changes. No changes since v1 https://lore.kernel.org/openvpn-devel/082540583b9145d89e1cdd5a74c485ea3a53d285.1785253480.git.ralf@mandelbit.com/ drivers/net/ovpn/udp.c | 81 +++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c index eeef4a7229f5..055cdb1bee13 100644 --- a/drivers/net/ovpn/udp.c +++ b/drivers/net/ovpn/udp.c @@ -185,7 +185,7 @@ static void ovpn_dst_cache_check_key(struct ovpn_peer *peer, * to detect whether the bind was replaced while the route lookup was running. * * Return: true if the lookup result still matches the current peer state and - * may update the dst cache. + * may update the dst cache or replace the bind. */ static bool ovpn_dst_cache_current(const struct ovpn_peer *peer, const struct ovpn_bind *bind, @@ -218,6 +218,9 @@ static int ovpn_udp4_output(struct ovpn_peer *peer, struct ovpn_bind *bind, struct sk_buff *skb, const struct ovpn_route_key *key) { + struct sockaddr_storage remote; + struct in_addr local = {}; + bool reset_local = false; struct rtable *rt; struct flowi4 fl = { .saddr = bind->local.ipv4.s_addr, @@ -236,24 +239,17 @@ static int ovpn_udp4_output(struct ovpn_peer *peer, struct ovpn_bind *bind, if (fl.saddr && unlikely(!inet_confirm_addr(sock_net(sk), NULL, 0, fl.saddr, RT_SCOPE_HOST))) { - /* we may end up here when the cached address is not usable - * anymore. In this case we reset address/cache and perform a - * new look up + /* The learned local address is not usable anymore. + * Retry with source address autoselection. */ fl.saddr = 0; - spin_lock_bh(&peer->lock); - bind->local.ipv4.s_addr = 0; - spin_unlock_bh(&peer->lock); - dst_cache_reset(cache); + reset_local = true; } rt = ip_route_output_flow(sock_net(sk), &fl, sk); if (IS_ERR(rt) && PTR_ERR(rt) == -EINVAL) { fl.saddr = 0; - spin_lock_bh(&peer->lock); - bind->local.ipv4.s_addr = 0; - spin_unlock_bh(&peer->lock); - dst_cache_reset(cache); + reset_local = true; rt = ip_route_output_flow(sock_net(sk), &fl, sk); } @@ -267,10 +263,28 @@ static int ovpn_udp4_output(struct ovpn_peer *peer, struct ovpn_bind *bind, goto err; } - /* avoid storing a stale cache */ + /* avoid storing a stale cache or local address */ spin_lock_bh(&peer->lock); - if (likely(ovpn_dst_cache_current(peer, bind, key))) - dst_cache_set_ip4(cache, &rt->dst, fl.saddr); + if (likely(ovpn_dst_cache_current(peer, bind, key))) { + if (!reset_local) { + dst_cache_set_ip4(cache, &rt->dst, fl.saddr); + spin_unlock_bh(&peer->lock); + goto transmit; + } + + /* invalidate per-CPU dst entries that may still carry + * the stale source + */ + dst_cache_reset(cache); + + /* preserve the current remote */ + memcpy(&remote, &bind->remote, sizeof(struct sockaddr_in)); + /* The current packet already has a valid wildcard-source route. + * If replacing the bind fails, leave the stale local in place; + * a later cache miss will retry the repair. + */ + ovpn_peer_reset_sockaddr(peer, &remote, &local); + } spin_unlock_bh(&peer->lock); transmit: @@ -300,6 +314,9 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind, struct sk_buff *skb, const struct ovpn_route_key *key) { + struct in6_addr local = in6addr_any; + struct sockaddr_storage remote; + bool reset_local = false; struct dst_entry *dst; int ret; @@ -320,15 +337,11 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind, if (!ipv6_addr_any(&fl.saddr) && unlikely(!ipv6_chk_addr(sock_net(sk), &fl.saddr, NULL, 0))) { - /* we may end up here when the cached address is not usable - * anymore. In this case we reset address/cache and perform a - * new look up + /* The learned local address is not usable anymore. + * Retry with source address autoselection. */ fl.saddr = in6addr_any; - spin_lock_bh(&peer->lock); - bind->local.ipv6 = in6addr_any; - spin_unlock_bh(&peer->lock); - dst_cache_reset(cache); + reset_local = true; } dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl, NULL); @@ -340,10 +353,28 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind, goto err; } - /* avoid storing a stale cache */ + /* avoid storing a stale cache or local address */ spin_lock_bh(&peer->lock); - if (likely(ovpn_dst_cache_current(peer, bind, key))) - dst_cache_set_ip6(cache, dst, &fl.saddr); + if (likely(ovpn_dst_cache_current(peer, bind, key))) { + if (!reset_local) { + dst_cache_set_ip6(cache, dst, &fl.saddr); + spin_unlock_bh(&peer->lock); + goto transmit; + } + + /* invalidate per-CPU dst entries that may still carry + * the stale source + */ + dst_cache_reset(cache); + + /* preserve the current remote */ + memcpy(&remote, &bind->remote, sizeof(struct sockaddr_in6)); + /* The current packet already has a valid wildcard-source route. + * If replacing the bind fails, leave the stale local in place; + * a later cache miss will retry the repair. + */ + ovpn_peer_reset_sockaddr(peer, &remote, &local); + } spin_unlock_bh(&peer->lock); transmit: