| Message ID | 20260204141441.528655-1-ralf@mandelbit.com |
|---|---|
| State | Awaiting Upstream |
| Headers |
Return-Path: <openvpn-devel-bounces@lists.sourceforge.net>
Delivered-To: patchwork@openvpn.net
Received: by 2002:a05:7000:6911:b0:80a:3855:ce6a with SMTP id
o17csp3124771map;
Wed, 4 Feb 2026 06:16:22 -0800 (PST)
X-Forwarded-Encrypted: i=2;
AJvYcCXDjC2JMjE49ADMwlVg0JWYyjRwV6y7GAAhsqWQ+h2wOIHSBLObgwO6/Y/Z2USI2D9gp99sXXi/11E=@openvpn.net
X-Received: by 2002:a05:6870:400d:b0:40a:5f51:c9e5 with SMTP id
586e51a60fabf-40a5f522243mr824344fac.42.1770214582082;
Wed, 04 Feb 2026 06:16:22 -0800 (PST)
ARC-Seal: i=1; a=rsa-sha256; t=1770214582; cv=none;
d=google.com; s=arc-20240605;
b=NxdoYqtxRttWdqt4Hng6XoNNT1IyfuJhUAGdiAXK+HnvWtuNU/MYPRG1rExbB4VDko
97DBJknvYpnX7px6/vzTg5VkTm2IFnZEhS0peiyNhw2HL/xn9WcNUfVKKfe0rOwAOFmz
Z1j2UaQNOnALS5KjxCxqmuuDLjd2DdFQgD5Ea46yeXEIxCv5QgrjrAeD8XTSJEb1uOXl
PrwiPs88UiQ1u4og3yeUY4jMUT0VCu0gAUB9oM0p8sUp5tDiaPSM+GYcKn56dR1XBxTK
S/WV4NeTMmISSSYLdaQwVfy6LGn/TBM0cweb0B8edw1GkW9lCPnp3oOIZjh5/o6GF1ml
R/HQ==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;
s=arc-20240605;
h=errors-to:content-transfer-encoding:cc:list-subscribe:list-help
:list-post:list-archive:list-unsubscribe:list-id:precedence:subject
:mime-version:message-id:date:to:from:dkim-signature:dkim-signature
:dkim-signature:dkim-signature;
bh=m5A2z005XoiORiCcmzdt8AMf+sW3xZxHeXfVDaSathc=;
fh=bDmbXayvKcQuWZaaz4JM7kgnS3MJBk3QUq2ehqNuBVc=;
b=DTKHzGjlVDdK1nWlWc9TOXDNnXDkuiqbyhvApLXUt4cE+hOSekxI9nzFJccErrbgM4
1/V5TNBm9C34WNutxaVOPNxMs18CWEeRkh37NofGkKMZCufhsxnDo2jp4C1zxvW+delu
WyP722C93YOw/kjMiyAcD8a9dg8mGCSyaghoFbmYJLdgs8iXV+gzSIt/G+YvMTv50Ybg
rii25rQLh5OEuhYObrwYY4Y+DpaG3eXLuLmJaforwxEOdqwb9+uRKUKXy8lDKY+kEuDn
dsdoPg460A2vY9Jc6NVT+um9itCn6kOvUKp6UIZwtT4IrdNJgEwu/N5hcm/ur0sGbfM5
jbDg==;
dara=google.com
ARC-Authentication-Results: i=1; mx.google.com;
dkim=pass header.i=@lists.sourceforge.net header.s=beta
header.b=eQZisFdG;
dkim=neutral (body hash did not verify) header.i=@sourceforge.net
header.s=x header.b=Yc5kNsOp;
dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x
header.b=Dw1qtsba;
dkim=neutral (body hash did not verify) header.i=@mandelbit.com
header.s=google header.b=KYD8+F5t;
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;
dara=neutral header.i=@openvpn.net
Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7])
by mx.google.com with ESMTPS id
586e51a60fabf-40a545cb049si1897441fac.370.2026.02.04.06.16.21
(version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
Wed, 04 Feb 2026 06:16:21 -0800 (PST)
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=eQZisFdG;
dkim=neutral (body hash did not verify) header.i=@sourceforge.net
header.s=x header.b=Yc5kNsOp;
dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x
header.b=Dw1qtsba;
dkim=neutral (body hash did not verify) header.i=@mandelbit.com
header.s=google header.b=KYD8+F5t;
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;
dara=neutral header.i=@openvpn.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:Cc:
List-Subscribe:List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:
Subject:MIME-Version:Message-ID:Date:To:From:Sender:Reply-To:Content-ID:
Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc
:Resent-Message-ID:In-Reply-To:References:List-Owner;
bh=m5A2z005XoiORiCcmzdt8AMf+sW3xZxHeXfVDaSathc=; b=eQZisFdGP9kd9YWwasjAVL46sl
FxoL8p+QxJhE/3GkYlRomrQxy0SAayiUdyW2zZz79TuTAy/mTTzw+WPmAs76+0cBczgPcHaP+5Juc
S3oKj97t3i4z414JhXZuwIIo2twH2BqQD0sF/9dit7S6oHgv38oFPPMUlE5f30NEzqco=;
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 <openvpn-devel-bounces@lists.sourceforge.net>)
id 1vndfw-0003t3-Bb;
Wed, 04 Feb 2026 14:16:13 +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 <ralf@mandelbit.com>) id 1vndfu-0003sp-KJ
for openvpn-devel@lists.sourceforge.net;
Wed, 04 Feb 2026 14:16:11 +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: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:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:
List-Subscribe:List-Post:List-Owner:List-Archive;
bh=4jVD5okv43vV1yGjworwUEWoqxgOrQQFhNgQYxfTs6U=; b=Yc5kNsOpNAvjLJrd7N/KDKLphv
6Kx6fokfPLV0Wf9Iz+jsVnHTVyM/vxCvaMuF5FAB5++sAYWumPIyN3gMrC/H8WQidMvawVk7N+Bko
b85ftaTrt3XYeluzgmhC3Pnx/scbt//rcDsEPg2357FhrDG6QjTOUEtai7sRokeOOToc=;
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x
;
h=Content-Transfer-Encoding:MIME-Version: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:In-Reply-To:
References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:
List-Owner:List-Archive; bh=4jVD5okv43vV1yGjworwUEWoqxgOrQQFhNgQYxfTs6U=; b=D
w1qtsbawnfXK/nx42C3sHJq+hbQ9/ii9DTBPR9LnI2pQAjJsp4wMgaNXb4H+fiQ+2gptf4lJ8PHjD
yFWVQ3v2yEKWU0tt3gAon8gtzpr2P9h66mk5Lw9OTXkvMH2ol/uTYUHQJiecQBRaavvBuWRWy1zOk
5M8Wme5RtfL0odsk=;
Received: from mail-wm1-f41.google.com ([209.85.128.41])
by sfi-mx-2.v28.lw.sourceforge.com with esmtps
(TLS1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.95)
id 1vndfu-0000w7-QP for openvpn-devel@lists.sourceforge.net;
Wed, 04 Feb 2026 14:16:11 +0000
Received: by mail-wm1-f41.google.com with SMTP id
5b1f17b1804b1-47ee07570deso58783435e9.1
for <openvpn-devel@lists.sourceforge.net>;
Wed, 04 Feb 2026 06:16:10 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=mandelbit.com; s=google; t=1770214564; x=1770819364;
darn=lists.sourceforge.net;
h=content-transfer-encoding:mime-version:message-id:date:subject:cc
:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=4jVD5okv43vV1yGjworwUEWoqxgOrQQFhNgQYxfTs6U=;
b=KYD8+F5tsnGiHpD9+fFBSOsv1npgCvLJPMdkrBlMOjrmxTdAcHrcLpdpdt6RfNeYBX
ApcXILJE/T2sUgLv2tvGDjmqCnDXnSH2Dnp67JiJxQoNzlmjrVm5FYhZvwpRh+dh1alY
e9X86Yh3E+k7IzfayQYVfBlUXLMx5X398KgTp9p/uVngG485LhfSmdCclzGkmdjYKN/R
p5IuUujhYQ2/cvI/nV+DyJJ6CCDelHsI2/W5s7MoxTEXAR4Pjy4uLgpb2N7/TgSGEwUJ
vazFYGPQ/IKf9ogVB5amIDEYZ57kYqYmkG4THpRjlavkbNmYgIDUy3pByL7cAUWa1nq7
Eq9A==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1770214564; x=1770819364;
h=content-transfer-encoding:mime-version:message-id:date:subject:cc
:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date
:message-id:reply-to;
bh=4jVD5okv43vV1yGjworwUEWoqxgOrQQFhNgQYxfTs6U=;
b=tlBqC3rtyjUT0zkfgeN8eUxgyEWLatogUqHj9UmRUimJD5cR3f+wMMrKLLt3Px8oyi
dH1l/1UFRQxuW8ZFqpnOsi9gdfMpp3WFDZlnSr7VprL5Pcym4KqvOipBG6CKzTIzjMuy
sjmKJD7aXflbXvloWZ/DAm3+T2aQ3NBpbNdlO5BSFwapp9af0Vdru6eHtLMAjjjtlhhj
2F/MVo6XEObfgXMxdLz2xW4xclrf4AYUwOTVhPYldrF+kPjQp6sgZ8Z//Vx89lHe1BXG
6erXihI+OB/Fz1FR4srMAHyU3RqmMqGa0wXHfdQKG67+ACG9X9aI9ZYjy8S5CI29qkQu
5jdg==
X-Gm-Message-State: AOJu0YwsPLIZaJhY5nrpfxct1V0KigtyQR2+50zaiZiLSqSQJefPtt4P
/jJUtseAjNArI0rGOFG0pba6cmV2eA1zap5jCuW9g/O5hXV8NWWzZ3nL9unBirLe7Vrf1e3Wib2
LmeQ6
X-Gm-Gg: AZuq6aJROMAyhsaRIR3JU020h+Sv3RV6EkYpEQ74cLDbUlm7Aiw6z2k7E34dYlR2T2K
MLolKbRcxSPk75121pQ7E2pbrradhnZ2gmAY3jy0/8+bsRW2YfT/fbroY9cQz47sq1SD3dPeoRh
t0j//dTmMvt9GIXXt/GK22lctGM1rFI+bw2F3MvULoAZvxJ5wGqzIG/fgsULnmbAxLIye3RCL4w
LKfM5ucaURytYDhd2AtUL/xYCXAx8qdJzl8Td5QtN8fExSl0+hjPcdaZ4/hzwmF0Y6BSF4KQsoy
PDubLYFyWlx8zf9OBaWhXK6N9Yj+Cy0oRjNcxtYxjOiar84yEOrR0xBSJLFV5hVEt7dkSviXBU5
eHCRDoIDYy1m8/OpsdyAZOsK/VoZoT9RSi2VzSa2kPp4LnWBGgA6V4zlZ94LWZlMEupS4M6NU5X
D58DY+Bg==
X-Received: by 2002:a05:600c:820a:b0:46e:4586:57e4 with SMTP id
5b1f17b1804b1-4830e987d12mr47682485e9.24.1770214563430;
Wed, 04 Feb 2026 06:16:03 -0800 (PST)
Received: from fedora ([2a01:e11:600c:d1a0:3dc8:57d2:efb7:51a8])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-4831088d318sm75877975e9.10.2026.02.04.06.16.02
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Wed, 04 Feb 2026 06:16:03 -0800 (PST)
From: Ralf Lici <ralf@mandelbit.com>
To: openvpn-devel@lists.sourceforge.net
Date: Wed, 4 Feb 2026 15:14:41 +0100
Message-ID: <20260204141441.528655-1-ralf@mandelbit.com>
X-Mailer: git-send-email 2.52.0
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: When processing TCP stream data in ovpn_tcp_recv,
we receive
large cloned skbs from __strp_rcv that may contain multiple coalesced
packets.
The current implementation has two bugs: 1. Header offset overflow: Using
pskb_pull with large offsets on coalesced skbs causes skb->data - skb->head
to exceed the u16 storage of skb->network_header. This causes
skb_reset_network_header to f [...]
Content analysis details: (-0.2 points, 5.0 required)
pts rule name description
---- ----------------------
--------------------------------------------------
-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.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.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2)
[209.85.128.41 listed in wl.mailspike.net]
X-Headers-End: 1vndfu-0000w7-QP
Subject: [Openvpn-devel] [PATCH ovpn net] ovpn: tcp - fix packet extraction
from stream
X-BeenThere: openvpn-devel@lists.sourceforge.net
X-Mailman-Version: 2.1.21
Precedence: list
List-Id: <openvpn-devel.lists.sourceforge.net>
List-Unsubscribe: <https://lists.sourceforge.net/lists/options/openvpn-devel>,
<mailto:openvpn-devel-request@lists.sourceforge.net?subject=unsubscribe>
List-Archive:
<http://sourceforge.net/mailarchive/forum.php?forum_name=openvpn-devel>
List-Post: <mailto:openvpn-devel@lists.sourceforge.net>
List-Help: <mailto:openvpn-devel-request@lists.sourceforge.net?subject=help>
List-Subscribe: <https://lists.sourceforge.net/lists/listinfo/openvpn-devel>,
<mailto:openvpn-devel-request@lists.sourceforge.net?subject=subscribe>
Cc: Sabrina Dubroca <sd@queasysnail.net>
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Errors-To: openvpn-devel-bounces@lists.sourceforge.net
X-getmail-retrieved-from-mailbox: Inbox
X-GMAIL-THRID: =?utf-8?q?1856204525561934733?=
X-GMAIL-MSGID: =?utf-8?q?1856204525561934733?=
|
| Series |
[Openvpn-devel,ovpn,net] ovpn: tcp - fix packet extraction from stream
|
|
Commit Message
Ralf Lici
Feb. 4, 2026, 2:14 p.m. UTC
When processing TCP stream data in ovpn_tcp_recv, we receive large
cloned skbs from __strp_rcv that may contain multiple coalesced packets.
The current implementation has two bugs:
1. Header offset overflow: Using pskb_pull with large offsets on
coalesced skbs causes skb->data - skb->head to exceed the u16 storage
of skb->network_header. This causes skb_reset_network_header to fail
on the inner decapsulated packet, resulting in packet drops.
2. Unaligned protocol headers: Extracting packets from arbitrary
positions within the coalesced TCP stream provides no alignment
guarantees for the packet data causing performance penalties on
architectures without efficient unaligned access. Additionally,
openvpn's 2-byte length prefix on TCP packets causes the subsequent
4-byte opcode and packet ID fields to be inherently misaligned.
Fix both issues by allocating a new skb for each openvpn packet and
using skb_copy_bits to extract only the packet content into the new
buffer, skipping the 2-byte length prefix. Also, check the length before
invoking the function that performs the allocation to avoid creating an
invalid skb.
If the packet has to be forwarded to userspace the 2-byte prefix can be
pushed to the head safely, without misalignment.
As a side effect, this approach also avoids the expensive linearization
that pskb_pull triggers on cloned skbs with page fragments. In testing,
this resulted in TCP throughput improvements of up to 74%.
Fixes: 11851cbd60ea ("ovpn: implement TCP transport")
Signed-off-by: Ralf Lici <ralf@mandelbit.com>
---
drivers/net/ovpn/tcp.c | 53 ++++++++++++++++++++++++++++--------------
1 file changed, 36 insertions(+), 17 deletions(-)
Comments
On Wed, 2026-02-04 at 15:14 +0100, Ralf Lici wrote: > When processing TCP stream data in ovpn_tcp_recv, we receive large > cloned skbs from __strp_rcv that may contain multiple coalesced > packets. > The current implementation has two bugs: > > 1. Header offset overflow: Using pskb_pull with large offsets on > coalesced skbs causes skb->data - skb->head to exceed the u16 > storage > of skb->network_header. This causes skb_reset_network_header to > fail > on the inner decapsulated packet, resulting in packet drops. > > 2. Unaligned protocol headers: Extracting packets from arbitrary > positions within the coalesced TCP stream provides no alignment > guarantees for the packet data causing performance penalties on > architectures without efficient unaligned access. Additionally, > openvpn's 2-byte length prefix on TCP packets causes the subsequent > 4-byte opcode and packet ID fields to be inherently misaligned. > > Fix both issues by allocating a new skb for each openvpn packet and > using skb_copy_bits to extract only the packet content into the new > buffer, skipping the 2-byte length prefix. Also, check the length > before > invoking the function that performs the allocation to avoid creating > an > invalid skb. > > If the packet has to be forwarded to userspace the 2-byte prefix can > be > pushed to the head safely, without misalignment. > > As a side effect, this approach also avoids the expensive > linearization > that pskb_pull triggers on cloned skbs with page fragments. In > testing, > this resulted in TCP throughput improvements of up to 74%. > > Fixes: 11851cbd60ea ("ovpn: implement TCP transport") > Signed-off-by: Ralf Lici <ralf@mandelbit.com> > --- > drivers/net/ovpn/tcp.c | 53 ++++++++++++++++++++++++++++------------- > - > 1 file changed, 36 insertions(+), 17 deletions(-) > > diff --git a/drivers/net/ovpn/tcp.c b/drivers/net/ovpn/tcp.c > index b7348da9b040..ffe8db69d76d 100644 > --- a/drivers/net/ovpn/tcp.c > +++ b/drivers/net/ovpn/tcp.c > @@ -70,37 +70,56 @@ static void ovpn_tcp_to_userspace(struct ovpn_peer > *peer, struct sock *sk, > peer->tcp.sk_cb.sk_data_ready(sk); > } > > -static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb) > +static struct sk_buff *ovpn_tcp_skb_packet(const struct ovpn_peer > *peer, > + struct sk_buff *orig_skb, > + const int pkt_len, const > int pkt_off) > { > - struct ovpn_peer *peer = container_of(strp, struct ovpn_peer, > tcp.strp); > - struct strp_msg *msg = strp_msg(skb); > - size_t pkt_len = msg->full_len - 2; > - size_t off = msg->offset + 2; > - u8 opcode; > + struct sk_buff *ovpn_skb; > + int err; > > - /* ensure skb->data points to the beginning of the openvpn > packet */ > - if (!pskb_pull(skb, off)) { > - net_warn_ratelimited("%s: packet too small for peer > %u\n", > - netdev_name(peer->ovpn->dev), > peer->id); > + /* create a new skb with only the content of the current > packet */ > + ovpn_skb = netdev_alloc_skb(peer->ovpn->dev, pkt_len); > + if (unlikely(!ovpn_skb)) > goto err; > - } > > - /* strparser does not trim the skb for us, therefore we do it > now */ > - if (pskb_trim(skb, pkt_len) != 0) { > - net_warn_ratelimited("%s: trimming skb failed for > peer %u\n", > + skb_copy_header(ovpn_skb, orig_skb); > + err = skb_copy_bits(orig_skb, pkt_off, skb_put(ovpn_skb, > pkt_len), > + pkt_len); > + if (unlikely(err)) { > + net_warn_ratelimited("%s: skb_copy_bits failed for > peer %u\n", > netdev_name(peer->ovpn->dev), > peer->id); > + kfree_skb(ovpn_skb); > goto err; > } > > - /* we need the first 4 bytes of data to be accessible > + consume_skb(orig_skb); > + return ovpn_skb; > +err: > + kfree_skb(orig_skb); > + return NULL; > +} > + > +static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb) > +{ > + struct ovpn_peer *peer = container_of(strp, struct ovpn_peer, > tcp.strp); > + struct strp_msg *msg = strp_msg(skb); > + int pkt_len = msg->full_len - 2; > + u8 opcode; > + > + /* we need at least 4 bytes of data in the packet > * to extract the opcode and the key ID later on > */ > - if (!pskb_may_pull(skb, OVPN_OPCODE_SIZE)) { > + if (unlikely(pkt_len < OVPN_OPCODE_SIZE)) { > net_warn_ratelimited("%s: packet too small to fetch > opcode for peer %u\n", > netdev_name(peer->ovpn->dev), > peer->id); > goto err; > } > > + /* extract the packet into a new skb */ > + skb = ovpn_tcp_skb_packet(peer, skb, pkt_len, msg->offset + > 2); > + if (unlikely(!skb)) > + goto err; > + > /* DATA_V2 packets are handled in kernel, the rest goes to > user space */ > opcode = ovpn_opcode_from_skb(skb, 0); > if (unlikely(opcode != OVPN_DATA_V2)) { > @@ -113,7 +132,7 @@ static void ovpn_tcp_rcv(struct strparser *strp, > struct sk_buff *skb) > /* The packet size header must be there when sending > the packet > * to userspace, therefore we put it back > */ > - skb_push(skb, 2); > + *((__force __be16 *)__skb_push(skb, 2)) = > cpu_to_be16(pkt_len); > ovpn_tcp_to_userspace(peer, strp->sk, skb); > return; > } This issue manifests as the following warning (on skb_reset_network_header): [ 126.764066] ------------[ cut here ]------------ [ 126.764541] WARNING: CPU: 1 PID: 22 at ./include/linux/skbuff.h:3122 ovpn_decrypt_post+0x531/0x7b0 [ovpn] [ 126.765698] Modules linked in: ovpn ip6_udp_tunnel udp_tunnel chacha libchacha chacha20poly1305 libpoly1305 veth [last unloaded: ip6_udp_tunnel] [ 126.767085] CPU: 1 UID: 0 PID: 22 Comm: ksoftirqd/1 Not tainted 6.17.0+ #222 PREEMPT(none) [ 126.768053] RIP: 0010:ovpn_decrypt_post+0x531/0x7b0 [ovpn] [ 126.768769] Code: cc cc cc cc 48 2b 93 c8 00 00 00 83 c2 28 0f 88 62 02 00 00 89 c8 29 f0 39 d0 0f 82 2e 02 00 00 b8 86 dd ff ff e9 68 fe ff ff <0f> 0b e9 20 fc ff ff 0f 0b e9 35 fc ff ff 39 c1 0f 82 5b fc ff ff [ 126.770834] RSP: 0018:ffffc900000d77f0 EFLAGS: 00010216 [ 126.771503] RAX: 000000000001034c RBX: ffff88810c7ac100 RCX: 0000000000000588 [ 126.772386] RDX: ffff888116ee0000 RSI: 0000000000000000 RDI: ffffffff8359f040 [ 126.773251] RBP: ffffc900000d7820 R08: 00000000000005a0 R09: ffff888116ef034c [ 126.774126] R10: 0000000000000000 R11: 0000000000000001 R12: ffff888116bec800 [ 126.774980] R13: ffff888108118000 R14: 0000000000000018 R15: ffff888103a6cc00 [ 126.775871] FS: 0000000000000000(0000) GS:ffff8882f446b000(0000) knlGS:0000000000000000 [ 126.776839] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 126.777605] CR2: 00007f5f9d2fc000 CR3: 000000011659b000 CR4: 0000000000750eb0 [ 126.778434] PKRU: 55555554 [ 126.778887] Call Trace: [ 126.779324] <TASK> [ 126.779728] ovpn_recv+0x15b/0x3a0 [ovpn] [ 126.780299] ovpn_tcp_rcv+0xbd/0x320 [ovpn] [ 126.780886] __strp_recv+0x172/0x640 [ 126.781430] strp_recv+0x27/0x30 [ 126.781931] __tcp_read_sock+0x92/0x260 [ 126.782483] ? __pfx_strp_recv+0x10/0x10 [ 126.783055] tcp_read_sock+0x1b/0x30 [ 126.783586] strp_read_sock+0xce/0xe0 [ 126.784162] strp_data_ready+0x6a/0xa0 [ 126.784721] ovpn_tcp_data_ready+0x90/0x220 [ovpn] [ 126.785441] tcp_data_ready+0x30/0xd0 [ 126.785992] tcp_data_queue+0x8a4/0x1000 [ 126.786560] tcp_rcv_established+0x328/0xca0 [ 126.787170] tcp_v4_do_rcv+0x18f/0x3c0 [ 126.787726] tcp_v4_rcv+0xf51/0x1520 [ 126.788264] ip_protocol_deliver_rcu+0x4a/0x200 [ 126.788898] ? process_backlog+0x14b/0x630 [ 126.789552] ip_local_deliver_finish+0xd7/0x220 [ 126.790193] ip_local_deliver+0x63/0x250 [ 126.790769] ? lock_is_held_type+0x9c/0x110 [ 126.791366] ? process_backlog+0x14b/0x630 [ 126.791995] ip_rcv+0x26f/0x340 [ 126.792516] ? process_backlog+0x14b/0x630 [ 126.793114] ? process_backlog+0x14b/0x630 [ 126.793714] __netif_receive_skb_one_core+0x6b/0x80 [ 126.794358] __netif_receive_skb+0x16/0x60 [ 126.794951] process_backlog+0x18b/0x630 [ 126.795515] ? process_backlog+0x6a/0x630 [ 126.796109] __napi_poll.constprop.0+0x2e/0x1e0 [ 126.796721] net_rx_action+0x384/0x420 [ 126.797252] ? local_clock_noinstr+0x13/0xf0 [ 126.797861] handle_softirqs+0xc8/0x3f0 [ 126.798401] ? __pfx_smpboot_thread_fn+0x10/0x10 [ 126.799024] run_ksoftirqd+0x36/0x50 [ 126.799548] smpboot_thread_fn+0xfe/0x230 [ 126.800110] kthread+0x103/0x210 [ 126.800602] ? __pfx_kthread+0x10/0x10 [ 126.801145] ret_from_fork+0x18a/0x1e0 [ 126.801705] ? __pfx_kthread+0x10/0x10 [ 126.802284] ret_from_fork_asm+0x1a/0x30 [ 126.802879] </TASK> [ 126.803288] irq event stamp: 41024 [ 126.803799] hardirqs last enabled at (41032): [<ffffffff8137676c>] __up_console_sem+0x5c/0x70 [ 126.804799] hardirqs last disabled at (41039): [<ffffffff81376751>] __up_console_sem+0x41/0x70 [ 126.805812] softirqs last enabled at (33936): [<ffffffff812e6486>] run_ksoftirqd+0x36/0x50 [ 126.806819] softirqs last disabled at (33941): [<ffffffff812e6486>] run_ksoftirqd+0x36/0x50 [ 126.807822] ---[ end trace 0000000000000000 ]---
Sorry Ralf, December and January flew by and I didn't get a chance to dive deeper into your previous RFC patch. 2026-02-04, 15:14:41 +0100, Ralf Lici wrote: > When processing TCP stream data in ovpn_tcp_recv, we receive large > cloned skbs from __strp_rcv that may contain multiple coalesced packets. > The current implementation has two bugs: > > 1. Header offset overflow: Using pskb_pull with large offsets on > coalesced skbs causes skb->data - skb->head to exceed the u16 storage > of skb->network_header. This causes skb_reset_network_header to fail > on the inner decapsulated packet, resulting in packet drops. > > 2. Unaligned protocol headers: Extracting packets from arbitrary > positions within the coalesced TCP stream provides no alignment > guarantees for the packet data causing performance penalties on > architectures without efficient unaligned access. Additionally, > openvpn's 2-byte length prefix on TCP packets causes the subsequent > 4-byte opcode and packet ID fields to be inherently misaligned. > > Fix both issues by allocating a new skb for each openvpn packet and > using skb_copy_bits to extract only the packet content into the new > buffer, skipping the 2-byte length prefix. Also, check the length before > invoking the function that performs the allocation to avoid creating an > invalid skb. > > If the packet has to be forwarded to userspace the 2-byte prefix can be > pushed to the head safely, without misalignment. > > As a side effect, this approach also avoids the expensive linearization > that pskb_pull triggers on cloned skbs with page fragments. In testing, We don't really avoid the linearization (because netdev_alloc_skb+skb_copy_bits is pretty much doing that) but we're only linearizing pkt_len instead of offset + pkt_len? > this resulted in TCP throughput improvements of up to 74%. Wow. [...] > +static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb) > +{ > + struct ovpn_peer *peer = container_of(strp, struct ovpn_peer, tcp.strp); > + struct strp_msg *msg = strp_msg(skb); > + int pkt_len = msg->full_len - 2; > + u8 opcode; > + > + /* we need at least 4 bytes of data in the packet > * to extract the opcode and the key ID later on > */ > - if (!pskb_may_pull(skb, OVPN_OPCODE_SIZE)) { > + if (unlikely(pkt_len < OVPN_OPCODE_SIZE)) { > net_warn_ratelimited("%s: packet too small to fetch opcode for peer %u\n", > netdev_name(peer->ovpn->dev), peer->id); > goto err; > } > > + /* extract the packet into a new skb */ > + skb = ovpn_tcp_skb_packet(peer, skb, pkt_len, msg->offset + 2); > + if (unlikely(!skb)) > + goto err; err: /* take reference for deferred peer deletion. should never fail */ if (WARN_ON(!ovpn_peer_hold(peer))) goto err_nopeer; schedule_work(&peer->tcp.defer_del_work); dev_dstats_rx_dropped(peer->ovpn->dev); I'm thinking that we may not need to abort the connection if we failed to allocate the new skb or copy the message, since we have a message boundary so we can still parse the following messages out of the stream? But we won't be able to validate that boundary since we can't try to decrypt the packet, so maybe it's better to still abort. (if the "don't abort" idea is wanted, it can be done at a later time, doesn't have to be part of this patch) > + > /* DATA_V2 packets are handled in kernel, the rest goes to user space */ > opcode = ovpn_opcode_from_skb(skb, 0); > if (unlikely(opcode != OVPN_DATA_V2)) { > @@ -113,7 +132,7 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb) > /* The packet size header must be there when sending the packet > * to userspace, therefore we put it back > */ > - skb_push(skb, 2); > + *((__force __be16 *)__skb_push(skb, 2)) = cpu_to_be16(pkt_len); Why switch to __skb_push here? The skb_under_panic() would be nice in the (unexpected) case we have an invalid skb. Here we rely on the extra room that netdev_alloc_skb reserves (NET_SKB_PAD) in case we have to re-push the packet length, right? I'm a bit concerned about the silent assumptions that could lead to writing to arbitrary addresses in memory. > ovpn_tcp_to_userspace(peer, strp->sk, skb); > return; > } > -- > 2.52.0 >
Hi Sabrina! On 04/02/2026 20:46, Sabrina Dubroca wrote: >> this resulted in TCP throughput improvements of up to 74%. > > Wow. I was also astonished by this result! Actually Ralf tested various options (i.e. netdev_alloc_skb vs pskb_extract, on all skbs vs on large ones only) and this solution turned to be the one giving the highest boost. In my tests yesterday, TCP jumped from ~4.3Gbps to ~7.3Gbps after applying this patch, which is the same throughput I am getting over UDP! > > [...] >> +static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb) >> +{ >> + struct ovpn_peer *peer = container_of(strp, struct ovpn_peer, tcp.strp); >> + struct strp_msg *msg = strp_msg(skb); >> + int pkt_len = msg->full_len - 2; >> + u8 opcode; >> + >> + /* we need at least 4 bytes of data in the packet >> * to extract the opcode and the key ID later on >> */ >> - if (!pskb_may_pull(skb, OVPN_OPCODE_SIZE)) { >> + if (unlikely(pkt_len < OVPN_OPCODE_SIZE)) { >> net_warn_ratelimited("%s: packet too small to fetch opcode for peer %u\n", >> netdev_name(peer->ovpn->dev), peer->id); >> goto err; >> } >> >> + /* extract the packet into a new skb */ >> + skb = ovpn_tcp_skb_packet(peer, skb, pkt_len, msg->offset + 2); >> + if (unlikely(!skb)) >> + goto err; > > > err: > /* take reference for deferred peer deletion. should never fail */ > if (WARN_ON(!ovpn_peer_hold(peer))) > goto err_nopeer; > schedule_work(&peer->tcp.defer_del_work); > dev_dstats_rx_dropped(peer->ovpn->dev); > > I'm thinking that we may not need to abort the connection if we failed > to allocate the new skb or copy the message, since we have a message > boundary so we can still parse the following messages out of the > stream? But we won't be able to validate that boundary since we can't > try to decrypt the packet, so maybe it's better to still abort. > (if the "don't abort" idea is wanted, it can be done at a later time, > doesn't have to be part of this patch) > >> + >> /* DATA_V2 packets are handled in kernel, the rest goes to user space */ >> opcode = ovpn_opcode_from_skb(skb, 0); >> if (unlikely(opcode != OVPN_DATA_V2)) { >> @@ -113,7 +132,7 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb) >> /* The packet size header must be there when sending the packet >> * to userspace, therefore we put it back >> */ >> - skb_push(skb, 2); >> + *((__force __be16 *)__skb_push(skb, 2)) = cpu_to_be16(pkt_len); > > Why switch to __skb_push here? The skb_under_panic() would be nice in > the (unexpected) case we have an invalid skb. > We just created the skb, so it should be safe to assume that the skb is valid, no? > Here we rely on the extra room that netdev_alloc_skb reserves > (NET_SKB_PAD) in case we have to re-push the packet length, right? The comment at https://elixir.bootlin.com/linux/v6.19-rc5/source/include/linux/skbuff.h#L3282 about NET_SKB_PAD seems to suggest that this is actual headroom that networking drivers can assume to have, no? And it should never be less than 32 bytes. Regards, > I'm a bit concerned about the silent assumptions that could lead to > writing to arbitrary addresses in memory. > >> ovpn_tcp_to_userspace(peer, strp->sk, skb); >> return; >> } >> -- >> 2.52.0 >> >
2026-02-04, 23:42:31 +0100, Antonio Quartulli wrote: > Hi Sabrina! > > On 04/02/2026 20:46, Sabrina Dubroca wrote: > > > this resulted in TCP throughput improvements of up to 74%. > > > > Wow. > > I was also astonished by this result! > > Actually Ralf tested various options (i.e. netdev_alloc_skb vs pskb_extract, > on all skbs vs on large ones only) and this solution turned to be the one > giving the highest boost. > > In my tests yesterday, TCP jumped from ~4.3Gbps to ~7.3Gbps after applying > this patch, which is the same throughput I am getting over UDP! Very nice :) > > > @@ -113,7 +132,7 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb) > > > /* The packet size header must be there when sending the packet > > > * to userspace, therefore we put it back > > > */ > > > - skb_push(skb, 2); > > > + *((__force __be16 *)__skb_push(skb, 2)) = cpu_to_be16(pkt_len); > > > > Why switch to __skb_push here? The skb_under_panic() would be nice in > > the (unexpected) case we have an invalid skb. > > > > We just created the skb, so it should be safe to assume that the skb is > valid, no? I meant invalid in the sense of "not having the expected room to push the header". > > Here we rely on the extra room that netdev_alloc_skb reserves > > (NET_SKB_PAD) in case we have to re-push the packet length, right? > > The comment at https://elixir.bootlin.com/linux/v6.19-rc5/source/include/linux/skbuff.h#L3282 > about NET_SKB_PAD seems to suggest that this is actual headroom that > networking drivers can assume to have, no? I guess so. But I'd feel a bit safer if we had something enforcing that at least this push can't fail, more as a guarantee against an accidental code change in ovpn. But maybe we'd have bigger problems through the rest of the stack if ovpn skbs get bridged/forwarded and we don't have all that headroom. > And it should never be less than 32 bytes. > > > Regards,
On 05/02/2026 11:42, Sabrina Dubroca wrote: > 2026-02-04, 23:42:31 +0100, Antonio Quartulli wrote: >>>> @@ -113,7 +132,7 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb) >>>> /* The packet size header must be there when sending the packet >>>> * to userspace, therefore we put it back >>>> */ >>>> - skb_push(skb, 2); >>>> + *((__force __be16 *)__skb_push(skb, 2)) = cpu_to_be16(pkt_len); >>> >>> Why switch to __skb_push here? The skb_under_panic() would be nice in >>> the (unexpected) case we have an invalid skb. >>> >> >> We just created the skb, so it should be safe to assume that the skb is >> valid, no? > > I meant invalid in the sense of "not having the expected room to push > the header". > >>> Here we rely on the extra room that netdev_alloc_skb reserves >>> (NET_SKB_PAD) in case we have to re-push the packet length, right? >> >> The comment at https://elixir.bootlin.com/linux/v6.19-rc5/source/include/linux/skbuff.h#L3282 >> about NET_SKB_PAD seems to suggest that this is actual headroom that >> networking drivers can assume to have, no? > > I guess so. But I'd feel a bit safer if we had something enforcing > that at least this push can't fail, more as a guarantee against an > accidental code change in ovpn. But maybe we'd have bigger problems > through the rest of the stack if ovpn skbs get bridged/forwarded and > we don't have all that headroom. Exactly my thought. If this assumption doesn't hold anymore, more things are going to break. (I expect also other mechanisms outside ovpn to be affected) On top of that, we ovpn_tcp_send_skb() basically relying on the same assumption already. Therefore, I'd just stick with the current version. However, I have a little nitpick: Ralf, please use the same style as the assignment in ovpn_tcp_send_skb(), for consistency: 584 *(__be16 *)__skb_push(skb, sizeof(u16)) = htons(len); Regards, > >> And it should never be less than 32 bytes. >> >> >> Regards, >
On Wed, 2026-02-04 at 20:46 +0100, Sabrina Dubroca wrote: > Sorry Ralf, December and January flew by and I didn't get a chance to > dive deeper into your previous RFC patch. No problem at all. We had the opportunity to investigate this further and run some tests, as Antonio mentioned. > 2026-02-04, 15:14:41 +0100, Ralf Lici wrote: > > When processing TCP stream data in ovpn_tcp_recv, we receive large > > cloned skbs from __strp_rcv that may contain multiple coalesced > > packets. > > The current implementation has two bugs: > > > > 1. Header offset overflow: Using pskb_pull with large offsets on > > coalesced skbs causes skb->data - skb->head to exceed the u16 > > storage > > of skb->network_header. This causes skb_reset_network_header to > > fail > > on the inner decapsulated packet, resulting in packet drops. > > > > 2. Unaligned protocol headers: Extracting packets from arbitrary > > positions within the coalesced TCP stream provides no alignment > > guarantees for the packet data causing performance penalties on > > architectures without efficient unaligned access. Additionally, > > openvpn's 2-byte length prefix on TCP packets causes the > > subsequent > > 4-byte opcode and packet ID fields to be inherently misaligned. > > > > Fix both issues by allocating a new skb for each openvpn packet and > > using skb_copy_bits to extract only the packet content into the new > > buffer, skipping the 2-byte length prefix. Also, check the length > > before > > invoking the function that performs the allocation to avoid creating > > an > > invalid skb. > > > > If the packet has to be forwarded to userspace the 2-byte prefix can > > be > > pushed to the head safely, without misalignment. > > > > As a side effect, this approach also avoids the expensive > > linearization > > that pskb_pull triggers on cloned skbs with page fragments. In > > testing, > > We don't really avoid the linearization (because > netdev_alloc_skb+skb_copy_bits is pretty much doing that) but we're > only linearizing pkt_len instead of offset + pkt_len? Exactly, the main issue was the first pskb_pull in ovpn_tcp_rcv which would linearize large amounts of data for every openvpn packet inside a coalesced skb (strp keeps cloning the original one). In fact your suggestion of using pskb_extract does resolve the skb_reset_network_header issue and improves throughput but netdev_alloc_skb performs better. I suppose that's because while pskb_extract avoids initial data copying through frag manipulation, skb_cow_data in ovpn_aead_decrypt still linearizes the packet for crypto, resulting in two passes over the data (carve + linearize) versus one direct copy with netdev_alloc_skb. Also pskb_extract requires atomic refcount operations which are not needed with the alloc + copy approach. > > > this resulted in TCP throughput improvements of up to 74%. > > Wow. > > [...] > > +static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff > > *skb) > > +{ > > + struct ovpn_peer *peer = container_of(strp, struct > > ovpn_peer, tcp.strp); > > + struct strp_msg *msg = strp_msg(skb); > > + int pkt_len = msg->full_len - 2; > > + u8 opcode; > > + > > + /* we need at least 4 bytes of data in the packet > > * to extract the opcode and the key ID later on > > */ > > - if (!pskb_may_pull(skb, OVPN_OPCODE_SIZE)) { > > + if (unlikely(pkt_len < OVPN_OPCODE_SIZE)) { > > net_warn_ratelimited("%s: packet too small to fetch > > opcode for peer %u\n", > > netdev_name(peer->ovpn->dev), > > peer->id); > > goto err; > > } > > > > + /* extract the packet into a new skb */ > > + skb = ovpn_tcp_skb_packet(peer, skb, pkt_len, msg->offset + > > 2); > > + if (unlikely(!skb)) > > + goto err; > > > err: > /* take reference for deferred peer deletion. should never > fail */ > if (WARN_ON(!ovpn_peer_hold(peer))) > goto err_nopeer; > schedule_work(&peer->tcp.defer_del_work); > dev_dstats_rx_dropped(peer->ovpn->dev); > > I'm thinking that we may not need to abort the connection if we failed > to allocate the new skb or copy the message, since we have a message > boundary so we can still parse the following messages out of the > stream? But we won't be able to validate that boundary since we can't > try to decrypt the packet, so maybe it's better to still abort. > (if the "don't abort" idea is wanted, it can be done at a later time, > doesn't have to be part of this patch) I agree. While an allocation failure here doesn't strictly require aborting the connection, subsequent operations are unlikely to succeed anyway. I can address this in a follow-up patch to keep this fix focused. > > + > > /* DATA_V2 packets are handled in kernel, the rest goes to > > user space */ > > opcode = ovpn_opcode_from_skb(skb, 0); > > if (unlikely(opcode != OVPN_DATA_V2)) { > > @@ -113,7 +132,7 @@ static void ovpn_tcp_rcv(struct strparser *strp, > > struct sk_buff *skb) > > /* The packet size header must be there when > > sending the packet > > * to userspace, therefore we put it back > > */ > > - skb_push(skb, 2); > > + *((__force __be16 *)__skb_push(skb, 2)) = > > cpu_to_be16(pkt_len); > > Why switch to __skb_push here? The skb_under_panic() would be nice in > the (unexpected) case we have an invalid skb. > > Here we rely on the extra room that netdev_alloc_skb reserves > (NET_SKB_PAD) in case we have to re-push the packet length, right? > I'm a bit concerned about the silent assumptions that could lead to > writing to arbitrary addresses in memory. > > > ovpn_tcp_to_userspace(peer, strp->sk, skb); > > return; > > } > > -- > > 2.52.0 > >
On Thu, 2026-02-05 at 14:42 +0100, Antonio Quartulli wrote: > On 05/02/2026 11:42, Sabrina Dubroca wrote: > > 2026-02-04, 23:42:31 +0100, Antonio Quartulli wrote: > > > > > @@ -113,7 +132,7 @@ static void ovpn_tcp_rcv(struct strparser > > > > > *strp, struct sk_buff *skb) > > > > > /* The packet size header must be there when > > > > > sending the packet > > > > > * to userspace, therefore we put it back > > > > > */ > > > > > - skb_push(skb, 2); > > > > > + *((__force __be16 *)__skb_push(skb, 2)) = > > > > > cpu_to_be16(pkt_len); > > > > > > > > Why switch to __skb_push here? The skb_under_panic() would be > > > > nice in > > > > the (unexpected) case we have an invalid skb. > > > > > > > > > > We just created the skb, so it should be safe to assume that the > > > skb is > > > valid, no? > > > > I meant invalid in the sense of "not having the expected room to > > push > > the header". > > > > > > Here we rely on the extra room that netdev_alloc_skb reserves > > > > (NET_SKB_PAD) in case we have to re-push the packet length, > > > > right? > > > > > > The comment at > > > https://elixir.bootlin.com/linux/v6.19-rc5/source/include/linux/skbuff.h#L3282 > > > about NET_SKB_PAD seems to suggest that this is actual headroom > > > that > > > networking drivers can assume to have, no? > > > > I guess so. But I'd feel a bit safer if we had something enforcing > > that at least this push can't fail, more as a guarantee against an > > accidental code change in ovpn. But maybe we'd have bigger problems > > through the rest of the stack if ovpn skbs get bridged/forwarded and > > we don't have all that headroom. > > Exactly my thought. If this assumption doesn't hold anymore, more > things > are going to break. > (I expect also other mechanisms outside ovpn to be affected) > > On top of that, we ovpn_tcp_send_skb() basically relying on the same > assumption already. > Therefore, I'd just stick with the current version. > > However, I have a little nitpick: Ralf, please use the same style as > the > assignment in ovpn_tcp_send_skb(), for consistency: > > 584 *(__be16 *)__skb_push(skb, sizeof(u16)) = htons(len); ACK. > Regards, > > > > > > And it should never be less than 32 bytes. > > > > > > > > > Regards, > >
diff --git a/drivers/net/ovpn/tcp.c b/drivers/net/ovpn/tcp.c index b7348da9b040..ffe8db69d76d 100644 --- a/drivers/net/ovpn/tcp.c +++ b/drivers/net/ovpn/tcp.c @@ -70,37 +70,56 @@ static void ovpn_tcp_to_userspace(struct ovpn_peer *peer, struct sock *sk, peer->tcp.sk_cb.sk_data_ready(sk); } -static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb) +static struct sk_buff *ovpn_tcp_skb_packet(const struct ovpn_peer *peer, + struct sk_buff *orig_skb, + const int pkt_len, const int pkt_off) { - struct ovpn_peer *peer = container_of(strp, struct ovpn_peer, tcp.strp); - struct strp_msg *msg = strp_msg(skb); - size_t pkt_len = msg->full_len - 2; - size_t off = msg->offset + 2; - u8 opcode; + struct sk_buff *ovpn_skb; + int err; - /* ensure skb->data points to the beginning of the openvpn packet */ - if (!pskb_pull(skb, off)) { - net_warn_ratelimited("%s: packet too small for peer %u\n", - netdev_name(peer->ovpn->dev), peer->id); + /* create a new skb with only the content of the current packet */ + ovpn_skb = netdev_alloc_skb(peer->ovpn->dev, pkt_len); + if (unlikely(!ovpn_skb)) goto err; - } - /* strparser does not trim the skb for us, therefore we do it now */ - if (pskb_trim(skb, pkt_len) != 0) { - net_warn_ratelimited("%s: trimming skb failed for peer %u\n", + skb_copy_header(ovpn_skb, orig_skb); + err = skb_copy_bits(orig_skb, pkt_off, skb_put(ovpn_skb, pkt_len), + pkt_len); + if (unlikely(err)) { + net_warn_ratelimited("%s: skb_copy_bits failed for peer %u\n", netdev_name(peer->ovpn->dev), peer->id); + kfree_skb(ovpn_skb); goto err; } - /* we need the first 4 bytes of data to be accessible + consume_skb(orig_skb); + return ovpn_skb; +err: + kfree_skb(orig_skb); + return NULL; +} + +static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb) +{ + struct ovpn_peer *peer = container_of(strp, struct ovpn_peer, tcp.strp); + struct strp_msg *msg = strp_msg(skb); + int pkt_len = msg->full_len - 2; + u8 opcode; + + /* we need at least 4 bytes of data in the packet * to extract the opcode and the key ID later on */ - if (!pskb_may_pull(skb, OVPN_OPCODE_SIZE)) { + if (unlikely(pkt_len < OVPN_OPCODE_SIZE)) { net_warn_ratelimited("%s: packet too small to fetch opcode for peer %u\n", netdev_name(peer->ovpn->dev), peer->id); goto err; } + /* extract the packet into a new skb */ + skb = ovpn_tcp_skb_packet(peer, skb, pkt_len, msg->offset + 2); + if (unlikely(!skb)) + goto err; + /* DATA_V2 packets are handled in kernel, the rest goes to user space */ opcode = ovpn_opcode_from_skb(skb, 0); if (unlikely(opcode != OVPN_DATA_V2)) { @@ -113,7 +132,7 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb) /* The packet size header must be there when sending the packet * to userspace, therefore we put it back */ - skb_push(skb, 2); + *((__force __be16 *)__skb_push(skb, 2)) = cpu_to_be16(pkt_len); ovpn_tcp_to_userspace(peer, strp->sk, skb); return; }