From patchwork Wed Jul 29 16:28:37 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ralf Lici X-Patchwork-Id: 5185 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:fd0b:b0:87d:ab56:3700 with SMTP id cw11csp2194062mac; Wed, 29 Jul 2026 09:29:14 -0700 (PDT) X-Forwarded-Encrypted: i=2; AHgh+Rpzu8RF3kEWaBRE1QuuEntB2JtlpuynBt8zwbTdjZzAq3sFtdezjFumGduiVFgSmSmxOIgAj+UpXvc=@openvpn.net X-Received: by 2002:a05:6870:1f0f:b0:456:b9d7:3aa8 with SMTP id 586e51a60fabf-4586cc69be6mr3879224fac.41.1785342554247; Wed, 29 Jul 2026 09:29:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1785342554; cv=none; d=google.com; s=arc-20260327; b=rge6sS1Qz/igPXeUcc7KlWFPotDChyfvuB66tgIeyYsM6tSzK+ZemrdkADcd9mB1im b2RhVVqn4hIBp96jWxB3h7juHepFtdrb25TPCSsj+U7ZQuXX4L5/+FXz849cSF49/y0Z gyvIIRk78009/rPVzEBl4ytz2UQJ8oiGozLeetih6+9Vg6nZCk6oY7woO+qAQnGDNVG4 m4VyKckKaOmhet/AaIOsElb0lewh+rE3weFYuU+0gyWdWP6vOX5Aj5i/KKxOJLAo7+ht m8rqgsr7ovJns0Ok84kNecy57k0hjwfIM+0vUcKi5v1ECbuOc96tYvWf/zwMd9wP/+8Z 5DTA== 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=yHppWm0QbGrkE5b9zORJsgAVWomOYhNIKbGUti+XkvU=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=H328CmnC+Xxe5+Q4c8V0+F4YHUMRxm0Ad9chrarSousyJGFfiX/puLDD+DeuE6+4eA 8xjL4cBLSMMgf+T13oHhRCLRYOPpfLMwyHX9Koowf0DPi3JgtNrRWpStx4kllac/p0UZ 6gyLvSBvk4fpIZjNJ4K96ZUKYOwsP5aXDp2JzRxePLDAJ/4CJB7t3cZoNsKuOTCajuGw DBT17JfPxPh7krz/1PnTfuzi9TaSnXljcXX/8V1s8on8emVX5Vizukb/gJiRVpjcpnkG EsO50zfl2+3ZLSQlpJKTEUE7h/LDMGnbkkF9+93yEjef3DAEZQ31QrVezGlzW2rG1XA8 zVcA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=ZiRVQb6b; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=TcrpsGwY; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=A8O4UPJE; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=EUcYBuN0; 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 586e51a60fabf-45886b5d2efsi2975906fac.249.2026.07.29.09.29.13 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 29 Jul 2026 09:29:14 -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=ZiRVQb6b; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=TcrpsGwY; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=A8O4UPJE; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=EUcYBuN0; 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=yHppWm0QbGrkE5b9zORJsgAVWomOYhNIKbGUti+XkvU=; b=ZiRVQb6bx6sZ1HJjvXOs68aosD OwYeTVouU7fDhfQyosa0PWswuCsKA5gr7uK1ozCGVlk9sYsPTR1zyWnuhhtswWRdsRcz2lZbjSjfM sLsxCOoG4iuBhNyJHzzIQwR5020KtK9rx5XlWLVee3+1qPQI1Lo1BQO8TJuKvkwHXdF4=; Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1wp79Y-0003Jn-5W; Wed, 29 Jul 2026 16:29:05 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1wp79T-0003JE-Ds for openvpn-devel@lists.sourceforge.net; Wed, 29 Jul 2026 16:29:01 +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:Cc:To:From:Sender:Reply-To: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=lxY+EDssr+94eItIEB5ihHFLohUc1bZa1il+eY6Vjn4=; b=TcrpsGwY/TtkjTKl0FNJnh9k1Z e2XM2I4LxJD75uUpGZueSeab5aKNIqSBAlR/d3r99HkV1zN3yRoeGyuBUq5MdVGUNsaQeKS/mHRL4 t28CQN0extw6me/HfJJ+/fQtoIShX1xkVyDmyHFNH6xY7QIo5kh2zjyd7rkJtVLLMVRM=; 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:Cc:To:From:Sender:Reply-To: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=lxY+EDssr+94eItIEB5ihHFLohUc1bZa1il+eY6Vjn4=; b=A8O4UPJEMnsTxMFNxub1jxH/DO FGFjs9Y/8aJeQT4VjCBAn53YWT05wxOsUkqGdokTx6rDxP4WsH/YsdnokkGYlAcnV3RcdoPL+TXNj 4Cp6sga36L9HCfdwxXtFREBgb+jshU9j/b6Ek8JVLTHMIk3UV5f0dDMXBOFQFzp7veSI=; Received: from mout-b-210.mailbox.org ([195.10.208.40]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1wp79S-0003CN-WD for openvpn-devel@lists.sourceforge.net; Wed, 29 Jul 2026 16:29:00 +0000 Received: from smtp102.mailbox.org (unknown [10.196.197.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-210.mailbox.org (Postfix) with ESMTPS id 4h9HpC0S7TzFqy6; Wed, 29 Jul 2026 18:28:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mandelbit.com; s=MBO0001; t=1785342531; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=lxY+EDssr+94eItIEB5ihHFLohUc1bZa1il+eY6Vjn4=; b=EUcYBuN0WUWODLoqbHx5De/sUzRFeUXQDmGQzjsXbftbpHoHAWRcBfEPk4rPsCskDSRAxR BdtOVuiFM+qKy5rXGVhOQgbwGFUGb5CvqNmQf36dAxxey8lU1R5Vnhn1HunRHXEBPE8YPN gRisYc+4jJQeFzy7quv0a8obdKHr3GRem71mUR85X9biMNVZpHHnctdfGQ381kcv2DZsuM ak/zEWiVR6FZLZPeniaYWzzn+nclgmDb9vXi7T908ELLuW5l+5Z588KO1S4n8lMpfu5fkb +1ya5cBF79HP/4qdpDDDSiUEKbWqtAqrFZkvAm3x4FMnlWkkCvIpnyMgBpsvUw== From: Ralf Lici To: openvpn-devel@lists.sourceforge.net Date: Wed, 29 Jul 2026 18:28:37 +0200 Message-ID: In-Reply-To: References: MIME-Version: 1.0 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: ovpn operates on a userspace-owned UDP socket, which may be manipulated in various ways by userspace. If the socket is never bound, connected, or used for communication, it may not have a source port [...] Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -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 X-Headers-End: 1wp79S-0003CN-WD Subject: [Openvpn-devel] [PATCH ovpn net v3 1/4] ovpn: avoid sending UDP packets with source port 0 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: 1872067354338010517 X-GMAIL-MSGID: 1872067354338010517 ovpn operates on a userspace-owned UDP socket, which may be manipulated in various ways by userspace. If the socket is never bound, connected, or used for communication, it may not have a source port assigned. Similarly, if the socket was connect()'ed to AF_INET or AF_INET6, it can be disconnected by connect() with AF_UNSPEC, which resets the source port unless the socket was explicitly bound. Since we must not transmit packets with source port 0, gate UDP TX on the presence of a valid source port and drop packets otherwise. To avoid ambiguity, sample the current source port once before route lookup and header build and enforce the check on that value. Emit a ratelimited warning when this drop path is hit so the broken socket state is visible. Return local UDP output errors to the common TX completion path so locally dropped packets are not counted as successful transport TX and do not refresh the peer keepalive timer. Fixes: 08857b5ec5d9 ("ovpn: implement basic TX path (UDP)") Signed-off-by: Ralf Lici --- No functional changes since v2 https://lore.kernel.org/openvpn-devel/97aecfd6a289211b3a1e3ed03ebd80bd896dde9b.1780663425.git.ralf@mandelbit.com/ Changes since v1 https://lore.kernel.org/openvpn-devel/20260526124544.425791-1-ralf@mandelbit.com/ - Emit a ratelimited warning when UDP TX sees source port 0. - Make ovpn_udp_send_skb return local UDP output errors instead of freeing the skb internally. - Propagate local UDP TX errors to ovpn_encrypt_post so failed local drops do not update link TX stats or last_sent. - Update UDP TX kdoc to document skb ownership on success/error. drivers/net/ovpn/io.c | 4 +++- drivers/net/ovpn/udp.c | 33 +++++++++++++++++++++++---------- drivers/net/ovpn/udp.h | 4 ++-- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c index 9a66d693039a..74fdcbcadafe 100644 --- a/drivers/net/ovpn/io.c +++ b/drivers/net/ovpn/io.c @@ -282,7 +282,9 @@ void ovpn_encrypt_post(void *data, int ret) switch (sock->sk->sk_protocol) { case IPPROTO_UDP: - ovpn_udp_send_skb(peer, sock->sk, skb); + ret = ovpn_udp_send_skb(peer, sock->sk, skb); + if (unlikely(ret < 0)) + goto err_unlock; break; case IPPROTO_TCP: ovpn_tcp_send_skb(peer, sock->sk, skb); diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c index 17d65d1595ed..9facc8261178 100644 --- a/drivers/net/ovpn/udp.c +++ b/drivers/net/ovpn/udp.c @@ -152,13 +152,20 @@ static int ovpn_udp4_output(struct ovpn_peer *peer, struct ovpn_bind *bind, */ .saddr = READ_ONCE(bind->local.ipv4.s_addr), .daddr = bind->remote.in4.sin_addr.s_addr, - .fl4_sport = inet_sk(sk)->inet_sport, + .fl4_sport = READ_ONCE(inet_sk(sk)->inet_sport), .fl4_dport = bind->remote.in4.sin_port, .flowi4_proto = sk->sk_protocol, .flowi4_mark = sk->sk_mark, }; int ret; + /* an uninitialized socket or connect(AF_UNSPEC) can cause this */ + if (unlikely(!fl.fl4_sport)) { + net_warn_ratelimited("%s: peer %u: UDP source port is 0\n", + netdev_name(peer->ovpn->dev), peer->id); + return -EADDRNOTAVAIL; + } + local_bh_disable(); rt = dst_cache_get_ip4(cache, &fl.saddr); if (rt) @@ -228,7 +235,7 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind, struct flowi6 fl = { .daddr = bind->remote.in6.sin6_addr, - .fl6_sport = inet_sk(sk)->inet_sport, + .fl6_sport = READ_ONCE(inet_sk(sk)->inet_sport), .fl6_dport = bind->remote.in6.sin6_port, .flowi6_proto = sk->sk_protocol, .flowi6_mark = sk->sk_mark, @@ -240,6 +247,13 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind, */ ovpn_peer_local_ipv6(peer, bind, &fl.saddr); + /* an uninitialized socket or connect(AF_UNSPEC) can cause this */ + if (unlikely(!fl.fl6_sport)) { + net_warn_ratelimited("%s: peer %u: UDP source port is 0\n", + netdev_name(peer->ovpn->dev), peer->id); + return -EADDRNOTAVAIL; + } + local_bh_disable(); dst = dst_cache_get_ip6(cache, &fl.saddr); if (dst) @@ -298,7 +312,8 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind, * @skb: the packet to send * * rcu_read_lock should be held on entry. - * On return, the skb is consumed. + * On success, the skb is passed to the transport stack and consumed. On + * error, ownership remains with the caller. * * Return: 0 on success or a negative error code otherwise */ @@ -345,21 +360,19 @@ static int ovpn_udp_output(struct ovpn_peer *peer, struct dst_cache *cache, * @peer: the destination peer * @sk: peer socket * @skb: the packet to send + * + * Return: 0 on success or a negative error code otherwise */ -void ovpn_udp_send_skb(struct ovpn_peer *peer, struct sock *sk, - struct sk_buff *skb) +int ovpn_udp_send_skb(struct ovpn_peer *peer, struct sock *sk, + struct sk_buff *skb) { - int ret; - skb->dev = peer->ovpn->dev; skb->mark = READ_ONCE(sk->sk_mark); /* no checksum performed at this layer */ skb->ip_summed = CHECKSUM_NONE; /* crypto layer -> transport (UDP) */ - ret = ovpn_udp_output(peer, &peer->dst_cache, sk, skb); - if (unlikely(ret < 0)) - kfree_skb(skb); + return ovpn_udp_output(peer, &peer->dst_cache, sk, skb); } static void ovpn_udp_encap_destroy(struct sock *sk) diff --git a/drivers/net/ovpn/udp.h b/drivers/net/ovpn/udp.h index fe26fbe25c5a..5b67112162a5 100644 --- a/drivers/net/ovpn/udp.h +++ b/drivers/net/ovpn/udp.h @@ -19,7 +19,7 @@ int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, struct socket *sock, struct ovpn_priv *ovpn); void ovpn_udp_socket_detach(struct ovpn_socket *ovpn_sock); -void ovpn_udp_send_skb(struct ovpn_peer *peer, struct sock *sk, - struct sk_buff *skb); +int ovpn_udp_send_skb(struct ovpn_peer *peer, struct sock *sk, + struct sk_buff *skb); #endif /* _NET_OVPN_UDP_H_ */ From patchwork Wed Jul 29 16:28:38 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ralf Lici X-Patchwork-Id: 5188 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:fd0b:b0:87d:ab56:3700 with SMTP id cw11csp2194118mac; Wed, 29 Jul 2026 09:29:17 -0700 (PDT) X-Forwarded-Encrypted: i=2; AHgh+Rpayy1sDWlZ5+DIomKGRwe0g6WZL6bq8EAs09Q4dbl4rmHljNGH3h6vFIQa/TR+DOyh+a2mpyxItDY=@openvpn.net X-Received: by 2002:a05:6820:8185:b0:6a3:7f5b:ab81 with SMTP id 006d021491bc7-6ac96cfe01cmr3603272eaf.44.1785342557491; Wed, 29 Jul 2026 09:29:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1785342557; cv=none; d=google.com; s=arc-20260327; b=mtN3pnkRDUe4O2wFypkaC2pFsvZu2r/z5Ce3FbVIl/9qA0Gd0zL1PqKO+XRCnbXYIU utv557qfUjG4Gy/PjIlIiIBl/uwTqPkNnc6AqEyX2epeKC90sR9pDWIeY2+iz8Zo2eRF /8FJaAicrcuj6A93mhdIb6AcI3wXaS7pcyU74goSnx4KEODiRRrWLJjQdrq/nVqr5m8h dNNlG9xGgGoZrKIk0mNgLewR29I9ZHE2RZ7J+WDah2MV7aV4oaj6E43Aw0+rj9AFCMDN P68RqYLgQE+xNT8rErMmvNKZQirIIEWJQ1tMV8yDcdIVL7Rjs0Xg4n+evvaT75TBZFLk tuxw== 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=N9kCpckhMQLff/TYp/EkZBV35abTPedJ0Uw3hD8SpZU=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=fh2uQrdEA5rG7nnHqm8OV11aCipiftNva/8qjjra3Jwky62zNmzRB3yyYqkKJUpbjO XMDWORXgVTCnqbRiybijYUtOsnzSg1ZJEDwUmjq9/1fngiFG3C5vFood/8VsSXN4sa0v OIkdGEMwZkOK6YkmDvUKCv4fux+X7Q2tL7LGcoXTL23X798z/G7tmgiampjWtBWCo6KJ JpzpG05KKkCVeaNBNa1FjOYO+0BUzL7a+g1T+DawTW36r/EpLSi6dO/WvZLLLNJvc/g3 SkHtxAdqYZdtjmz46rGQjlLxbw9Ccv3uSmeFrPdbbEHoCOaKAfyIMm9UjNE8K4dyrr5h brBw==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=nPfZktl5; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=LgYzWW39; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=WY4eqi00; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=x8c7O5cB; 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 586e51a60fabf-458863b51absi2916972fac.19.2026.07.29.09.29.17 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 29 Jul 2026 09:29:17 -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=nPfZktl5; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=LgYzWW39; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=WY4eqi00; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=x8c7O5cB; 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=N9kCpckhMQLff/TYp/EkZBV35abTPedJ0Uw3hD8SpZU=; b=nPfZktl5qv4YlMwT2mPjtgfugq lY/tHevOc9dX30VYT/i3b+FqZpglEZORjY/6YBBs4D/VkQ+b7FfE76cW7AHmQib007qnjN4PxZQ2+ zmhe2zAmqaQz1UFG4iQRlj06/mSIriS24HfSCVWlhxXUc2Lr3qUqrUMtO79Wi+7JPepA=; Received: from [127.0.0.1] (helo=sfs-ml-3.v29.lw.sourceforge.com) by sfs-ml-3.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1wp79X-0007am-RJ; Wed, 29 Jul 2026 16:29:08 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-3.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1wp79R-0007Zo-Sy for openvpn-devel@lists.sourceforge.net; Wed, 29 Jul 2026 16:29:02 +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:Cc:To:From:Sender:Reply-To: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=wweY5uwv5rswMQNyuAHugl2+Q99goT1ksKybVZYTsz8=; b=LgYzWW39+vx1yPJMlq33c1nMuU zn2Y6b4CUKYhXGCD3fLKbX68NCyC4CVxsQC6ZR6bVFTBuAm6xptjpOGkyg9jiVMfyx/FL57XIhcnO Z44nXvuHwW0TQNwzGiAzUA2Vrl+GkePlaiFOw1X/X+wpVipIqBo9x08aMKVVhbaHmVn0=; 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:Cc:To:From:Sender:Reply-To: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=wweY5uwv5rswMQNyuAHugl2+Q99goT1ksKybVZYTsz8=; b=WY4eqi00PxpRlb2946TOnIfNy6 ykVpdI7yZDZ6x8p71uAoOTC70xXndzCfAdDt/LsIsZgtLRru9e3yRvqAcAMsSwf6tpKX1DCBWlU+x LiajkiG/ruoRfWB5sFYOagyaJZP0K18n05hPAcMxCr4N0eOW3NPJOYc/fq2JOcbT2vsc=; Received: from mout-b-106.mailbox.org ([195.10.208.46]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1wp79T-0003CP-Q3 for openvpn-devel@lists.sourceforge.net; Wed, 29 Jul 2026 16:29:02 +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-106.mailbox.org (Postfix) with ESMTPS id 4h9HpC6HWmzNlkR; Wed, 29 Jul 2026 18:28:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mandelbit.com; s=MBO0001; t=1785342531; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wweY5uwv5rswMQNyuAHugl2+Q99goT1ksKybVZYTsz8=; b=x8c7O5cBQFsQxqWDjS+LBO7KZX2QII6rnJwElca+f+7aaFK/CQEYkhf8JdMrpv9f/iY2bZ CFq4gtiTQqkdW7cDKfX1VV/7ydTfr07Nx8+fHPa08KYwXBxksaFbHVFDTQ7i2eYdJZ423i ho8iN5gTSYbIVXcTAGNsV008KJ06BxSUzkeGCFe1WnLAro0VBiGvVtJMNC+9ZPjJsg/Dpn KCmsxr+wlYJp0GMQ391ok8GmVPBlRyQb2ZCH4gZz3bspKAHSIDLcZ/gCKaqjVhKxCLjzA1 lpc4yBo9m4d3UBr5lbL9Rh2fNqItgJf6Xhnxt0akWGneSxQgsAzK675q48xpmw== 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: Wed, 29 Jul 2026 18:28:38 +0200 Message-ID: <792f10e4e176de95483065544bbc05e1ca6fa354.1785341335.git.ralf@mandelbit.com> In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: 4h9HpC6HWmzNlkR 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: ovpn accepts a userspace-provided socket and attaches transport-specific state to it. The current checks use sk_protocol to select the UDP or TCP attach path, but sk_protocol alone does not identify t [...] Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -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 X-Headers-End: 1wp79T-0003CP-Q3 Subject: [Openvpn-devel] [PATCH ovpn net v3 2/4] ovpn: validate sockets before attaching peer transports 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: 1872067357442503075 X-GMAIL-MSGID: 1872067357442503075 ovpn accepts a userspace-provided socket and attaches transport-specific state to it. The current checks use sk_protocol to select the UDP or TCP attach path, but sk_protocol alone does not identify the socket layout. For example, a raw socket can have sk_protocol set to IPPROTO_UDP while its storage is not a struct udp_sock. Passing such a socket to the UDP attach path would make ovpn read and write udp_sock fields on the wrong object, potentially accessing memory beyond the actual socket storage. Reject sockets unless they are real UDP datagram or TCP stream sockets before attaching them to ovpn in the peer creation path. This lets netlink report a clear error before calling the socket attach helper. Also switch ovpn_socket_new to sk_is_tcp and sk_is_udp, matching the netlink validation performed before the helper is called. This does not change the accepted socket types, but makes the helper's assumptions explicit. Fixes: f6226ae7a0cd ("ovpn: introduce the ovpn_socket object") Fixes: 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink") Signed-off-by: Ralf Lici --- No changes since v2 https://lore.kernel.org/openvpn-devel/8e0904081feaec3e49972fa34ace74a9e8c1397f.1780663425.git.ralf@mandelbit.com/ No changes since v1 https://lore.kernel.org/openvpn-devel/20260526124544.425791-2-ralf@mandelbit.com/ drivers/net/ovpn/netlink.c | 15 +++++++++++++-- drivers/net/ovpn/socket.c | 16 +++++++++------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c index 8e21fa3e7822..036638920c09 100644 --- a/drivers/net/ovpn/netlink.c +++ b/drivers/net/ovpn/netlink.c @@ -400,10 +400,21 @@ int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info) goto peer_release; } + /* sk_protocol is not enough to determine if this is a real UDP or TCP + * socket + */ + if (!sk_is_udp(sock->sk) && !sk_is_tcp(sock->sk)) { + NL_SET_ERR_MSG_FMT_MOD(info->extack, + "socket is not TCP or UDP"); + sockfd_put(sock); + ret = -EOPNOTSUPP; + goto peer_release; + } + /* Only when using UDP as transport protocol the remote endpoint * can be configured so that ovpn knows where to send packets to. */ - if (sock->sk->sk_protocol == IPPROTO_UDP && + if (sk_is_udp(sock->sk) && !attrs[OVPN_A_PEER_REMOTE_IPV4] && !attrs[OVPN_A_PEER_REMOTE_IPV6]) { NL_SET_ERR_MSG_FMT_MOD(info->extack, @@ -417,7 +428,7 @@ int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info) * will just send bytes over it, without the need to specify a * destination. */ - if (sock->sk->sk_protocol == IPPROTO_TCP && + if (sk_is_tcp(sock->sk) && (attrs[OVPN_A_PEER_REMOTE_IPV4] || attrs[OVPN_A_PEER_REMOTE_IPV6])) { NL_SET_ERR_MSG_FMT_MOD(info->extack, diff --git a/drivers/net/ovpn/socket.c b/drivers/net/ovpn/socket.c index 6cbeb2caaeec..4765f4063b71 100644 --- a/drivers/net/ovpn/socket.c +++ b/drivers/net/ovpn/socket.c @@ -126,13 +126,15 @@ static int ovpn_socket_attach(struct ovpn_socket *ovpn_sock, /** * ovpn_socket_new - create a new socket and initialize it - * @sock: the kernel socket to embed + * @sock: the kernel socket to embed; must be a real UDP or TCP socket * @peer: the peer reachable via this socket * * Return: an openvpn socket on success or a negative error code otherwise */ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer) { + const bool tcp = sk_is_tcp(sock->sk); + const bool udp = sk_is_udp(sock->sk); struct ovpn_socket *ovpn_sock; struct sock *sk = sock->sk; int ret; @@ -142,7 +144,7 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer) /* a TCP socket can only be owned by a single peer, therefore there * can't be any other user */ - if (sk->sk_protocol == IPPROTO_TCP && sk->sk_user_data) { + if (tcp && sk->sk_user_data) { ovpn_sock = ERR_PTR(-EBUSY); goto sock_release; } @@ -150,7 +152,7 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer) /* a UDP socket can be shared across multiple peers, but we must make * sure it is not owned by something else */ - if (sk->sk_protocol == IPPROTO_UDP) { + if (udp) { u8 type = READ_ONCE(udp_sk(sk)->encap_type); /* socket owned by other encapsulation module */ @@ -212,11 +214,11 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer) /* TCP sockets are per-peer, therefore they are linked to their unique * peer */ - if (sk->sk_protocol == IPPROTO_TCP) { + if (tcp) { INIT_WORK(&ovpn_sock->tcp_tx_work, ovpn_tcp_tx_work); ovpn_sock->peer = peer; ovpn_peer_hold(peer); - } else if (sk->sk_protocol == IPPROTO_UDP) { + } else if (udp) { /* in UDP we only link the ovpn instance since the socket is * shared among multiple peers */ @@ -237,9 +239,9 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer) ret = ovpn_socket_attach(ovpn_sock, sock, peer); if (ret < 0) { - if (sk->sk_protocol == IPPROTO_TCP) + if (tcp) ovpn_peer_put(peer); - else if (sk->sk_protocol == IPPROTO_UDP) + else if (udp) netdev_put(peer->ovpn->dev, &ovpn_sock->dev_tracker); sock_put(sk); From patchwork Wed Jul 29 16:28:39 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ralf Lici X-Patchwork-Id: 5186 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:fd0b:b0:87d:ab56:3700 with SMTP id cw11csp2194068mac; Wed, 29 Jul 2026 09:29:14 -0700 (PDT) X-Forwarded-Encrypted: i=2; AHgh+RrPocEeGF2nda8EwbWJlW5VAeHIpc8f6RL2Ig0Kl+c2giTAYzlsiLyoQAfLiqBGcrU2kDoawOBD8d0=@openvpn.net X-Received: by 2002:a05:6808:bcf:b0:49b:24f9:c024 with SMTP id 5614622812f47-4ad7315777dmr1313638b6e.5.1785342554754; Wed, 29 Jul 2026 09:29:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1785342554; cv=none; d=google.com; s=arc-20260327; b=rXOedJLe8v2vgaHhuVgulrAFW1DxpJtShQ8W5A4FV0P5ucW+HQnthqeqBVwdLkBpGI 4V9Z8ywNXyYkBVEo8twHUFMmdBZc6E7VhR+BWefMczKbnkv19o/3vSEun9lRi+0bRnEz lBHIcm/cvYYptiYZ/BRGhoVU3Bl3baCM/I5rvPr/HvGxXq9jVrqFnJFXk/92NOZKHQfn aZ8HqzJpFB17y+qI16ZQJEailifc+zWuHqirAHwwdhYx6LSkABDGSrlpsUK9mjAtWFym 9XuSGeKzbbqt/cixe1pGEcexMM1/cnXkNNjJNHdFbGx3AAVJK/Pd61zxcf0Hg4HQivpB rTCQ== 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=2mXkBB/xa6SImMrCuMlU7T0Pt9ylFqE18n2xA6vIK/M=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=ODO6vkn0+pNd4wNLkM5jCz85PXOsywZNASwiEaT+PaOgG1H2Y4eRgzaOd61ijA8thT 6gEKMLZAOE8J8+XJxuOzFmiAA26EEQ5o2ST95kb4nXweQsOVSQZhMErUxa1ENg1zpiEJ 4Paf2iupSO2adngJormL3acHwzf0d0lkdAJEKmsBhNaQKhlRkdTMm45DwdCbDRn65ngr C/4Xb0J3cZDxeHEabBrid4+VcC97adkMMr2GLIpC9Oec2GLcjgp8P6ZSo5rmZGNmHXKq MgqcnuW2vJxctsBk1bkE9qcW6xT8sCAMJBZ1VeaRX/htkzvqQitXODgwsZFpZarwqGp8 GnBQ==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b="ll5D/Gxj"; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b="ehzX/6M7"; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=LKiMRNeE; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=XsEyI88W; 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 5614622812f47-4ad6eca527bsi1858074b6e.25.2026.07.29.09.29.14 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 29 Jul 2026 09:29:14 -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="ll5D/Gxj"; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b="ehzX/6M7"; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=LKiMRNeE; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=XsEyI88W; 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=2mXkBB/xa6SImMrCuMlU7T0Pt9ylFqE18n2xA6vIK/M=; b=ll5D/GxjmI9+NcsCVMrz+PyUDz okgLIg88vbA+WaiEH1EYfS1WFk35KEIBNvZBEDVJwF/bR0QtSiwcdh0nEYsKhZ/M0Q+hoWqZMGqGy 2uSQnb/vM0VAh74HIxFNSzU4YwL5renFJjfCiwozHPugc3ODNRv+m6974KCJRfj3zXos=; Received: from [127.0.0.1] (helo=sfs-ml-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1wp79Z-0003Rc-VG; Wed, 29 Jul 2026 16:29:09 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1wp79S-0003RQ-Ow for openvpn-devel@lists.sourceforge.net; Wed, 29 Jul 2026 16:29:02 +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:Cc:To:From:Sender:Reply-To: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=SvymDAjBGC9MO6236IgXfrNtTKZGia53Pt6Wyt95zIo=; b=ehzX/6M7kUvC2fJmdDztuk6M39 gnPtYbrKs/L+2AK8/AaOGPMtaXnlm6A4o8QHFCvGo/06lwMheAM7F8LLJ4QwKmXOu5PWTGYDI42wm ePMsoUzpE4Ye+0r1Tk4Ysrzf9DGK9JbAXW1dXI5HNpmD+ZIlC9U9OCjJRM/k7GEicJjk=; 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:Cc:To:From:Sender:Reply-To: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=SvymDAjBGC9MO6236IgXfrNtTKZGia53Pt6Wyt95zIo=; b=LKiMRNeEwrY+mf99zRTvf5OEHx FEEJWHu+KvDm3ogtzA0MZOVxTXr8RwoiU1wYk6+Mr5B9nvn9JBYMyoDMTCqqBlwiKyVt+1iJGyD4B OKZwDhux4rBRHM1MF9704T0oRDN6mnKc+4VrfSYpUw6oRKTDKSDE5dtC/BraTDaI95TI=; Received: from mout-b-201.mailbox.org ([195.10.208.61]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1wp79R-0004Yp-2D for openvpn-devel@lists.sourceforge.net; Wed, 29 Jul 2026 16:29:02 +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-201.mailbox.org (Postfix) with ESMTPS id 4h9HpD4W1SzLlvx; Wed, 29 Jul 2026 18:28:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mandelbit.com; s=MBO0001; t=1785342532; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=SvymDAjBGC9MO6236IgXfrNtTKZGia53Pt6Wyt95zIo=; b=XsEyI88WwZmnnzpfizJ/80NYwT+jzgOoo0bKQ4OTf0zAB9Dc7Vv8VO2QCtakvxaA1xLsWr wXlZ08ycsis7OuPogmVasxfmxsCnvUPWk7Qe39qu74OfgQbr2cQjDTembPaTQhnQL6qJiY kRyEKQN8XXbmy/KRJwcuaTVxH8yEcekj06JrEUxQtgopNxZzNCXHKp9ijOaWEjQghXFfqO Sd/rHT5jDuJkPpl881sK2D3QVPY+8QVsKXwGG+A8nYk28mjqaRrXwqBdxs1SUT1wdS+ngh IfYOvCx4ZrC9SR7STUMOwOoo3UPbFKiqC+HRKcs8qjyoxhW+mwF7uYhdLldDUw== 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: Wed, 29 Jul 2026 18:28:39 +0200 Message-ID: <9528d6be0ca8726f93a31aa64f3ea065f312298e.1785341335.git.ralf@mandelbit.com> In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: 4h9HpD4W1SzLlvx X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "sfi-spamd-1.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: ovpn accepts a userspace-provided socket and a peer remote endpoint through netlink. For UDP peers, the remote endpoint family selects the transmit path used later by ovpn_udp_output. Reject UDP peer remotes that are incompatible with the socket state when they are configured through netlink. An IPv4 UDP socket cannot be used with an IPv6 remote endpoint, and an IPv6-only UDP socke [...] 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_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-Headers-End: 1wp79R-0004Yp-2D Subject: [Openvpn-devel] [PATCH ovpn net v3 3/4] ovpn: reject UDP remotes incompatible with socket family 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: 1872067354742828783 X-GMAIL-MSGID: 1872067354742828783 ovpn accepts a userspace-provided socket and a peer remote endpoint through netlink. For UDP peers, the remote endpoint family selects the transmit path used later by ovpn_udp_output. Reject UDP peer remotes that are incompatible with the socket state when they are configured through netlink. An IPv4 UDP socket cannot be used with an IPv6 remote endpoint, and an IPv6-only UDP socket cannot send to an IPv4 remote endpoint. Reporting this at setup time gives userspace a clear extack and avoids installing a peer that would immediately be unable to transmit. This validation only covers the socket state visible while the netlink request is handled. The socket remains owned by userspace after it is attached to ovpn, so userspace can later change properties such as IPV6_V6ONLY or IPV6_ADDRFORM. The transmit path therefore still has to re-check socket/remote compatibility before sending. Parse the remote endpoint once in the peer new/set paths and reject UDP remotes when the provided socket cannot send to them. Pass the parsed endpoint into the common peer modify helper so the validation and the stored endpoint use the same normalized sockaddr. Fixes: 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink") Signed-off-by: Ralf Lici --- No changes since v2 https://lore.kernel.org/openvpn-devel/b871663007ed51e7a64a94ed2a85aca6ba9aaa17.1780663425.git.ralf@mandelbit.com/ Changes since v1 https://lore.kernel.org/openvpn-devel/20260526124544.425791-3-ralf@mandelbit.com/ - Reword the commit message to clarify that netlink validation is only setup-time diagnostics. - Use a single READ_ONCE snapshot of sk->sk_family in ovpn_nl_udp_remote_compatible. drivers/net/ovpn/netlink.c | 132 ++++++++++++++++++++++++++----------- 1 file changed, 94 insertions(+), 38 deletions(-) diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c index 036638920c09..547899dd5f3a 100644 --- a/drivers/net/ovpn/netlink.c +++ b/drivers/net/ovpn/netlink.c @@ -271,15 +271,17 @@ static int ovpn_nl_peer_precheck(struct ovpn_priv *ovpn, * @peer: the peer to modify * @info: generic netlink info from the user request * @attrs: the attributes from the user request + * @remote: remote address, if provided * * Return: a negative error code in case of failure, 0 on success or 1 on * success and the VPN IPs have been modified (requires rehashing in MP * mode) */ static int ovpn_nl_peer_modify(struct ovpn_peer *peer, struct genl_info *info, - struct nlattr **attrs) + struct nlattr **attrs, + const struct sockaddr_storage *remote) { - struct sockaddr_storage ss = {}; + struct sockaddr_storage empty_remote = {}; void *local_ip = NULL; u32 interv, timeout; bool rehash = false; @@ -287,15 +289,15 @@ static int ovpn_nl_peer_modify(struct ovpn_peer *peer, struct genl_info *info, spin_lock_bh(&peer->lock); - if (ovpn_nl_attr_sockaddr_remote(attrs, &ss)) { + if (remote) { /* we carry the local IP in a generic container. * ovpn_peer_reset_sockaddr() will properly interpret it - * based on ss.ss_family + * based on remote->ss_family */ local_ip = ovpn_nl_attr_local_ip(attrs); /* set peer sockaddr */ - ret = ovpn_peer_reset_sockaddr(peer, &ss, local_ip); + ret = ovpn_peer_reset_sockaddr(peer, remote, local_ip); if (ret < 0) { NL_SET_ERR_MSG_FMT_MOD(info->extack, "cannot set peer sockaddr: %d", @@ -333,7 +335,7 @@ static int ovpn_nl_peer_modify(struct ovpn_peer *peer, struct genl_info *info, netdev_dbg(peer->ovpn->dev, "modify peer id=%u tx_id=%u endpoint=%pIScp VPN-IPv4=%pI4 VPN-IPv6=%pI6c\n", - peer->id, peer->tx_id, &ss, + peer->id, peer->tx_id, remote ?: &empty_remote, &peer->vpn_addrs.ipv4.s_addr, &peer->vpn_addrs.ipv6); spin_unlock_bh(&peer->lock); @@ -344,10 +346,43 @@ static int ovpn_nl_peer_modify(struct ovpn_peer *peer, struct genl_info *info, return ret; } +/** + * ovpn_nl_udp_remote_compatible - check if a UDP socket can use a remote + * @sk: UDP socket to validate + * @remote: remote endpoint to validate against the socket + * @extack: netlink extended ACK for reporting validation errors + * + * Return: 0 if the remote endpoint is compatible with the socket or a negative + * error code otherwise. + */ +static int ovpn_nl_udp_remote_compatible(const struct sock *sk, + const struct sockaddr_storage *remote, + struct netlink_ext_ack *extack) +{ + const unsigned short sock_family = READ_ONCE(sk->sk_family); + + if (sock_family == AF_INET && remote->ss_family == AF_INET6) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "UDP socket is IPv4 but remote is IPv6"); + return -EAFNOSUPPORT; + } + + if (sock_family == AF_INET6 && ipv6_only_sock(sk) && + remote->ss_family == AF_INET) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "UDP socket is IPv6-only but remote is IPv4"); + return -EAFNOSUPPORT; + } + + return 0; +} + int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info) { - struct nlattr *attrs[OVPN_A_PEER_MAX + 1]; + const struct sockaddr_storage *remote = NULL; struct ovpn_priv *ovpn = info->user_ptr[0]; + struct nlattr *attrs[OVPN_A_PEER_MAX + 1]; + struct sockaddr_storage ss = {}; struct ovpn_socket *ovpn_sock; struct socket *sock = NULL; struct ovpn_peer *peer; @@ -411,26 +446,34 @@ int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info) goto peer_release; } - /* Only when using UDP as transport protocol the remote endpoint - * can be configured so that ovpn knows where to send packets to. - */ - if (sk_is_udp(sock->sk) && - !attrs[OVPN_A_PEER_REMOTE_IPV4] && - !attrs[OVPN_A_PEER_REMOTE_IPV6]) { - NL_SET_ERR_MSG_FMT_MOD(info->extack, - "missing remote IP address for UDP socket"); - sockfd_put(sock); - ret = -EINVAL; - goto peer_release; - } + if (ovpn_nl_attr_sockaddr_remote(attrs, &ss)) + remote = &ss; - /* In case of TCP, the socket is connected to the peer and ovpn - * will just send bytes over it, without the need to specify a - * destination. - */ - if (sk_is_tcp(sock->sk) && - (attrs[OVPN_A_PEER_REMOTE_IPV4] || - attrs[OVPN_A_PEER_REMOTE_IPV6])) { + if (sk_is_udp(sock->sk)) { + /* Only when using UDP as transport protocol the remote + * endpoint can be configured so that ovpn knows where to send + * packets to. + */ + if (!remote) { + NL_SET_ERR_MSG_FMT_MOD(info->extack, + "missing remote IP address for UDP socket"); + sockfd_put(sock); + ret = -EINVAL; + goto peer_release; + } + + /* can the socket be used with this remote? */ + ret = ovpn_nl_udp_remote_compatible(sock->sk, remote, + info->extack); + if (ret < 0) { + sockfd_put(sock); + goto peer_release; + } + } else if (remote) { + /* In case of TCP, the socket is connected to the peer and ovpn + * will just send bytes over it, without the need to specify a + * destination. + */ NL_SET_ERR_MSG_FMT_MOD(info->extack, "unexpected remote IP address with TCP socket"); sockfd_put(sock); @@ -456,7 +499,7 @@ int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info) rcu_assign_pointer(peer->sock, ovpn_sock); - ret = ovpn_nl_peer_modify(peer, info, attrs); + ret = ovpn_nl_peer_modify(peer, info, attrs, remote); if (ret < 0) goto sock_release; @@ -485,8 +528,10 @@ int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info) int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info) { - struct nlattr *attrs[OVPN_A_PEER_MAX + 1]; + const struct sockaddr_storage *remote = NULL; struct ovpn_priv *ovpn = info->user_ptr[0]; + struct nlattr *attrs[OVPN_A_PEER_MAX + 1]; + struct sockaddr_storage ss = {}; struct ovpn_socket *sock; struct ovpn_peer *peer; u32 peer_id; @@ -518,22 +563,33 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info) return -ENOENT; } - /* when using a TCP socket the remote IP is not expected */ + if (ovpn_nl_attr_sockaddr_remote(attrs, &ss)) + remote = &ss; + rcu_read_lock(); sock = rcu_dereference(peer->sock); - if (sock && sock->sk->sk_protocol == IPPROTO_TCP && - (attrs[OVPN_A_PEER_REMOTE_IPV4] || - attrs[OVPN_A_PEER_REMOTE_IPV6])) { - rcu_read_unlock(); - NL_SET_ERR_MSG_FMT_MOD(info->extack, - "unexpected remote IP address with TCP socket"); - ovpn_peer_put(peer); - return -EINVAL; + if (sock && remote) { + if (sk_is_udp(sock->sk)) { + ret = ovpn_nl_udp_remote_compatible(sock->sk, remote, + info->extack); + if (ret < 0) { + rcu_read_unlock(); + ovpn_peer_put(peer); + return ret; + } + } else if (sk_is_tcp(sock->sk)) { + /* when using a TCP socket remote IP is not expected */ + NL_SET_ERR_MSG_FMT_MOD(info->extack, + "unexpected remote IP address with TCP socket"); + rcu_read_unlock(); + ovpn_peer_put(peer); + return -EINVAL; + } } rcu_read_unlock(); spin_lock_bh(&ovpn->lock); - ret = ovpn_nl_peer_modify(peer, info, attrs); + ret = ovpn_nl_peer_modify(peer, info, attrs, remote); if (ret < 0) { spin_unlock_bh(&ovpn->lock); ovpn_peer_put(peer); From patchwork Wed Jul 29 16:28:40 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ralf Lici X-Patchwork-Id: 5187 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:fd0b:b0:87d:ab56:3700 with SMTP id cw11csp2194115mac; Wed, 29 Jul 2026 09:29:17 -0700 (PDT) X-Forwarded-Encrypted: i=2; AHgh+Rrs6pG4pfsXY7GkF94oyes61afyoJhzobb5a322U8EHezCFaPzV2FHwZpC7Rxf50TR18UpCtYg2Zs4=@openvpn.net X-Received: by 2002:a05:6808:1441:b0:486:4892:d553 with SMTP id 5614622812f47-4ad5b5dacc9mr3739630b6e.0.1785342557337; Wed, 29 Jul 2026 09:29:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1785342557; cv=none; d=google.com; s=arc-20260327; b=UJHTq4zL/PF59VlrxAWY8Hj8N2bBwKt+ORdozpujt6bfn6i1H01utzJ1kt1mOioax3 loT5KFD0Z/vufkqluD6g+4HFFSCAH61BoDVTFE85ajH1yY97wbLEQb6Pq0fZ6MU1J2m2 vW2FmUZvG+vMFLGoBf1pnvxz0d+cdlGoqGWIruDXfSSdN1iqLcaV1T/Un4sspuy5KXN+ 3Ajeju/TQx8ZN6vpaspgwCY+2sldHa590W2/jKe9kNYpf0N81C64X7LJS0cisY2s70G/ mmFjsiKz6HoiisWcgh1pLeAuAys5YXadX3pDFv2W/gK7WX3v8O0HoMBCOACilk2JtqYc gJTg== 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=CXVVUh8I0j2cG1C+wakZAIlyIbaxhQDJ2z1fGvgiVf0=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=GljY6KjrAC+MjgzRLpSEMlDfjO9EPbZMek7mKPD5qkkGyEejjc/B2z8sv3+FTwiAFg iRu7hN2tQx5HLLJXzkBw9x9cGuGcmepihrsOTNAdi5dIgsuYSukzuz1isJqjtGMeCEM0 lTcrOf06OC5o50v3v0E0nG3JjsclyQ9TSAdJDHGiK/3Zr9QNBiBa6NXszmyWVMAMA3Sb uG5/TZ7BGCW8v8LmNWY2AemtRkvwFxUYwtG2eYyEGQAtXkijf/Y6YABq65s/GwkfFdPp p28cS6icDWC641i3lxbBT3u+njxlrerhVJx/LvFwODGpzB70pJMpZoFJq7cRJiGIzCN6 L+LA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=QsS+9rem; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=aHYpBPgl; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b="JUim/FLu"; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=MiLrkDiL; 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 5614622812f47-4ad6eca6f07si1860925b6e.17.2026.07.29.09.29.17 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 29 Jul 2026 09:29:17 -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=QsS+9rem; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=aHYpBPgl; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b="JUim/FLu"; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=MiLrkDiL; 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=CXVVUh8I0j2cG1C+wakZAIlyIbaxhQDJ2z1fGvgiVf0=; b=QsS+9remvtWQuHtwUYhmi8J6Ur cHIiB5pb/6PGQLKI+YuqQTR2Lturpf/wcgeM/Ky+LsQfdWvWvsGQpI8mo5/N+jg7bNu1xIK+5fTMe 5H2TOCG3uJfQ110Dy/3vJpznZ7da0PVTGVpEuil+k53ERbdzZKmWUvsi9wxvRu/+dtH0=; Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1wp79Y-0003Ju-H7; Wed, 29 Jul 2026 16:29:06 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1wp79W-0003Jf-Kq for openvpn-devel@lists.sourceforge.net; Wed, 29 Jul 2026 16:29:04 +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:Cc:To:From:Sender:Reply-To: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=U4Xaly7IgZfqo/0g50SaPzJK5uWPbtapqdAJdRp3OjQ=; b=aHYpBPglxSYA91Kqt9aLJCgCHK qli0xcf8yq5kAhumpOXWuQXTpMdBj2v0AXQ/t0gF7mFIehkR7nIxLp7W0P154bCIVNPZKCgSORDHc S+kxY2uTGQU6Qxpxhlz5PevaIsi9nNx8NtR9yLjC5MhN3ryQy79neNNByd/lQXPnj2c8=; 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:Cc:To:From:Sender:Reply-To: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=U4Xaly7IgZfqo/0g50SaPzJK5uWPbtapqdAJdRp3OjQ=; b=JUim/FLu6iO6+T/WFe/oErp+MW YYcolKd2GozQti53+JIGHDYXZkD9AeeaoQOGSXTJQSYjRzW2jsWL+1PYDw4KZSYaTphPfFSGdchng 6r4WBEWjIr0bHHCGPKYH0iya0wmxsxLQB/M/cCe6aDjH+y3dFDpSWiuGXpriBMlRF7Sw=; Received: from mout-b-206.mailbox.org ([195.10.208.51]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1wp79U-0003CR-Ne for openvpn-devel@lists.sourceforge.net; Wed, 29 Jul 2026 16:29:04 +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-206.mailbox.org (Postfix) with ESMTPS id 4h9HpF2d3FzV4; Wed, 29 Jul 2026 18:28:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mandelbit.com; s=MBO0001; t=1785342533; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=U4Xaly7IgZfqo/0g50SaPzJK5uWPbtapqdAJdRp3OjQ=; b=MiLrkDiLCIcauByPggPXTZ9LYefbrL+uQhLPhhXshdX0rTUVnEc2CT1n57A1c/vJnHHhsn 8/CEEQVi5/Y5581HE6RL1laAsMz5lHxagMMTIYAe6v+DsknVt0JSoLtZXwBcNwWtds6Pki +UhJuDnJtZrcnrv0hhOhG6lBKFHwvb6feBtB+TIPIKrqDwIM529Gutfe0BjBCqEda+le7C 24o4w8BSHupAhrMdfeOg1Rg+CKTckLFrBYX6ULgvU/dyxNBTNhBE+yORg2LkpqRPX0VEAS Tszjv7JoMnlEtAQm31WBkcWvnxDVBOURx5o44+uiSeRnk9/1REZ1y4gF5JU5SQ== 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: Wed, 29 Jul 2026 18:28:40 +0200 Message-ID: <2b9965ab192b47294fdb26647c65793d9287a7a9.1785341335.git.ralf@mandelbit.com> In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: 4h9HpF2d3FzV4 X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "sfi-spamd-1.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: 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 sti [...] 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_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [195.10.208.51 listed in wl.mailspike.net] X-Headers-End: 1wp79U-0003CR-Ne Subject: [Openvpn-devel] [PATCH ovpn net v3 4/4] ovpn: recheck UDP socket family before transmit 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: 1872067357421869019 X-GMAIL-MSGID: 1872067357421869019 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. When the peer remote family no longer matches the socket state, emit a ratelimited warning, drop the packet with -EAFNOSUPPORT and delete the peer with TRANSPORT_ERROR. Peer deletion is deferred through a common transport-error work item, because the UDP transmit path can run from non-sleepable contexts while ovpn_peer_del may release sockets and sleep. Use the same helper for TCP transport errors instead of keeping a TCP-only deferred delete work item. Fixes: 08857b5ec5d9 ("ovpn: implement basic TX path (UDP)") Signed-off-by: Ralf Lici --- No functional changes since v2 https://lore.kernel.org/openvpn-devel/c5392b0ea96d2c79c2d32470526004e2b0ff1d42.1780663425.git.ralf@mandelbit.com/ Changes since v1 https://lore.kernel.org/openvpn-devel/20260526124544.425791-4-ralf@mandelbit.com/ - Emit ratelimited warnings when UDP TX detects a socket/remote address family mismatch. - Delete the peer with TRANSPORT_ERROR on UDP socket/remote family mismatches, using deferred work because TX can run from non-sleepable contexts. - Move the TCP deferred transport-error deletion work into a common ovpn_peer_del_transport_error helper and reuse it from TCP and UDP. - Read sk->sk_family once before selecting the UDP TX path. - Fix the IPV6_V6ONLY comment typo. drivers/net/ovpn/peer.c | 19 +++++++++++++++++++ drivers/net/ovpn/peer.h | 5 +++-- drivers/net/ovpn/tcp.c | 23 +++-------------------- drivers/net/ovpn/udp.c | 24 +++++++++++++++++++++--- 4 files changed, 46 insertions(+), 25 deletions(-) diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c index 27fcc917c657..e725cb8d1ff2 100644 --- a/drivers/net/ovpn/peer.c +++ b/drivers/net/ovpn/peer.c @@ -83,6 +83,24 @@ static void ovpn_peer_keepalive_send(struct work_struct *work) local_bh_enable(); } +static void ovpn_peer_transport_error_work(struct work_struct *work) +{ + struct ovpn_peer *peer = container_of(work, struct ovpn_peer, + transport_error_work); + + ovpn_peer_del(peer, OVPN_DEL_PEER_REASON_TRANSPORT_ERROR); + ovpn_peer_put(peer); +} + +void ovpn_peer_del_transport_error(struct ovpn_peer *peer) +{ + if (WARN_ON(!ovpn_peer_hold(peer))) + return; + + if (!schedule_work(&peer->transport_error_work)) + ovpn_peer_put(peer); +} + /** * ovpn_peer_new - allocate and initialize a new peer object * @ovpn: the openvpn instance inside which the peer should be created @@ -117,6 +135,7 @@ struct ovpn_peer *ovpn_peer_new(struct ovpn_priv *ovpn, u32 id) kref_init(&peer->refcount); ovpn_peer_stats_init(&peer->vpn_stats); ovpn_peer_stats_init(&peer->link_stats); + INIT_WORK(&peer->transport_error_work, ovpn_peer_transport_error_work); INIT_WORK(&peer->keepalive_work, ovpn_peer_keepalive_send); ret = dst_cache_init(&peer->dst_cache, GFP_KERNEL); diff --git a/drivers/net/ovpn/peer.h b/drivers/net/ovpn/peer.h index c0994c606554..8f1d18eaf74f 100644 --- a/drivers/net/ovpn/peer.h +++ b/drivers/net/ovpn/peer.h @@ -62,6 +62,7 @@ * @refcount: reference counter * @rcu: used to free peer in an RCU safe way * @release_entry: entry for the socket release list + * @transport_error_work: work used to delete peer on transport error * @keepalive_work: used to schedule keepalive sending */ struct ovpn_peer { @@ -97,8 +98,6 @@ struct ovpn_peer { struct proto *prot; const struct proto_ops *ops; } sk_cb; - - struct work_struct defer_del_work; } tcp; struct ovpn_crypto_state crypto; struct dst_cache dst_cache; @@ -117,6 +116,7 @@ struct ovpn_peer { struct kref refcount; struct rcu_head rcu; struct llist_node release_entry; + struct work_struct transport_error_work; struct work_struct keepalive_work; }; @@ -145,6 +145,7 @@ static inline void ovpn_peer_put(struct ovpn_peer *peer) struct ovpn_peer *ovpn_peer_new(struct ovpn_priv *ovpn, u32 id); int ovpn_peer_add(struct ovpn_priv *ovpn, struct ovpn_peer *peer); int ovpn_peer_del(struct ovpn_peer *peer, enum ovpn_del_peer_reason reason); +void ovpn_peer_del_transport_error(struct ovpn_peer *peer); void ovpn_peers_free(struct ovpn_priv *ovpn, struct sock *sock, enum ovpn_del_peer_reason reason); diff --git a/drivers/net/ovpn/tcp.c b/drivers/net/ovpn/tcp.c index 0af14055c39a..117b31d458d6 100644 --- a/drivers/net/ovpn/tcp.c +++ b/drivers/net/ovpn/tcp.c @@ -148,11 +148,7 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb) ovpn_recv(peer, skb); return; err: - /* take reference for deferred peer deletion. should never fail */ - if (WARN_ON(!ovpn_peer_hold(peer))) - goto err_nopeer; - if (!schedule_work(&peer->tcp.defer_del_work)) - ovpn_peer_put(peer); + ovpn_peer_del_transport_error(peer); ovpn_dev_dstats_rx_dropped(peer->ovpn->dev); err_nopeer: kfree_skb(skb); @@ -240,7 +236,7 @@ void ovpn_tcp_socket_wait_finish(struct ovpn_socket *sock) { struct ovpn_peer *peer = sock->peer; - /* NOTE: we don't wait for peer->tcp.defer_del_work to finish: + /* NOTE: we don't wait for peer->transport_error_work to finish: * either the worker is not running or this function * was invoked by that worker. */ @@ -283,9 +279,7 @@ static void ovpn_tcp_send_sock(struct ovpn_peer *peer, struct sock *sk) /* in case of TCP error we can't recover the VPN * stream therefore we abort the connection */ - ovpn_peer_hold(peer); - if (!schedule_work(&peer->tcp.defer_del_work)) - ovpn_peer_put(peer); + ovpn_peer_del_transport_error(peer); /* we bail out immediately and keep tx_in_progress set * to true. This way we prevent more TX attempts @@ -498,15 +492,6 @@ static void ovpn_tcp_build_protos(struct proto *new_prot, const struct proto *orig_prot, const struct proto_ops *orig_ops); -static void ovpn_tcp_peer_del_work(struct work_struct *work) -{ - struct ovpn_peer *peer = container_of(work, struct ovpn_peer, - tcp.defer_del_work); - - ovpn_peer_del(peer, OVPN_DEL_PEER_REASON_TRANSPORT_ERROR); - ovpn_peer_put(peer); -} - /* Set TCP encapsulation callbacks */ int ovpn_tcp_socket_attach(struct ovpn_socket *ovpn_sock, struct ovpn_peer *peer) @@ -539,8 +524,6 @@ int ovpn_tcp_socket_attach(struct ovpn_socket *ovpn_sock, goto err; } - INIT_WORK(&peer->tcp.defer_del_work, ovpn_tcp_peer_del_work); - __sk_dst_reset(ovpn_sock->sk); skb_queue_head_init(&peer->tcp.user_queue); skb_queue_head_init(&peer->tcp.out_queue); diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c index 9facc8261178..31b035978f95 100644 --- a/drivers/net/ovpn/udp.c +++ b/drivers/net/ovpn/udp.c @@ -320,6 +320,7 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind, static int ovpn_udp_output(struct ovpn_peer *peer, struct dst_cache *cache, struct sock *sk, struct sk_buff *skb) { + unsigned short sock_family; struct ovpn_bind *bind; int ret; @@ -336,18 +337,35 @@ static int ovpn_udp_output(struct ovpn_peer *peer, struct dst_cache *cache, goto out; } + sock_family = READ_ONCE(sk->sk_family); + ret = -EAFNOSUPPORT; switch (bind->remote.in4.sin_family) { case AF_INET: + /* userspace might have set IPV6_V6ONLY */ + if (unlikely(sock_family == AF_INET6 && ipv6_only_sock(sk))) { + net_warn_ratelimited("%s: peer %u: IPv4 remote, IPv6-only socket\n", + netdev_name(peer->ovpn->dev), + peer->id); + ovpn_peer_del_transport_error(peer); + 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(sock_family != AF_INET6)) { + net_warn_ratelimited("%s: peer %u: IPv6 remote, IPv4 socket\n", + netdev_name(peer->ovpn->dev), + peer->id); + ovpn_peer_del_transport_error(peer); + break; + } + ret = ovpn_udp6_output(peer, bind, cache, sk, skb); break; #endif - default: - ret = -EAFNOSUPPORT; - break; } out: