* [PATCH net 00/10] pull request: fixes for ovpn 2026-07-30
@ 2026-07-30 9:46 Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 01/10] ovpn: add missing rtnl_link_ops->get_size callback Antonio Quartulli
` (9 more replies)
0 siblings, 10 replies; 11+ messages in thread
From: Antonio Quartulli @ 2026-07-30 9:46 UTC (permalink / raw)
To: netdev
Cc: Antonio Quartulli, Sabrina Dubroca, Ralf Lici, Jakub Kicinski,
Paolo Abeni, Andrew Lunn, David S. Miller, Eric Dumazet
Hi all!
Here is a batch of ovpn fixes for net, collected and reviewed over the
past weeks (they went through a few rounds of sashiko pre-review on
openvpn-devel).
There are still larger fixes in our queue, so please ignore any
"previous issue" Sashiko may report on these.
Please pull or let me know of any issue!
Thanks a lot,
Antonio
The following changes since commit 51b093a7ba27476e1f639455f005e8d2e75390e4:
net: sxgbe: check descriptor ring allocation failures (2026-07-29 09:33:10 +0100)
are available in the Git repository at:
https://github.com/OpenVPN/ovpn-net-next.git ovpn-net-20260730
for you to fetch changes up to 26ba17d845193dac4921ae1ab280d28d1938052e:
ovpn: fix incorrect use of rcu_access_pointer() (2026-07-30 11:28:30 +0200)
----------------------------------------------------------------
Included fixes:
* use rcu_dereference_bh() instead of rcu_access_pointer() where the
pointer is actually dereferenced
* ensure TCP global variables are initialized before they can be
accessed via netlink (e.g. when attaching a TCP socket)
* actually disable IPv4 redirects on multipeer interfaces (the
previous attempt was a no-op and did not survive netns moves)
* hash a floated peer by its transport identity only, consistently
with the add and lookup paths
* zero the sockaddr padding before learning a floated endpoint so it
does not leak into the by_transp_addr hash key
* ensure the socket is owned by ovpn before dereferencing
sk_user_data
* rehash a peer in the by_transp_addr table when its remote endpoint
is updated via CMD_PEER_SET
* avoid re-adding to the hashtables a peer that was concurrently
removed (use-after-free)
* limit keepalive values to one day to avoid overflowing the
delayed-work delay on 32-bit systems
* add the missing rtnl_link_ops->get_size callback so link messages
account for the nested mode attribute
----------------------------------------------------------------
Antonio Quartulli (7):
ovpn: skip rehash for peers already removed from by_id
ovpn: rehash peer in by_transp_addr table on CMD_PEER_SET
ovpn: ensure socket is owned by ovpn before deref sk_user_data
ovpn: zero-initialize sockaddr before learning a floated endpoint
ovpn: hash floated peer by transport identity only
ovpn: disable IPv4 redirects on MP interfaces
ovpn: ensure TCP vars are initialized first
Marco Baffo (1):
ovpn: limit keepalive values to one day
Qingfang Deng (1):
ovpn: fix incorrect use of rcu_access_pointer()
Ralf Lici (1):
ovpn: add missing rtnl_link_ops->get_size callback
Documentation/netlink/specs/ovpn.yaml | 4 +
drivers/net/ovpn/main.c | 64 +++++++++----
drivers/net/ovpn/netlink-gen.c | 20 ++--
drivers/net/ovpn/netlink.c | 6 ++
drivers/net/ovpn/peer.c | 172 +++++++++++++++++++++++++---------
drivers/net/ovpn/peer.h | 1 +
drivers/net/ovpn/socket.c | 9 ++
7 files changed, 208 insertions(+), 68 deletions(-)
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH net 01/10] ovpn: add missing rtnl_link_ops->get_size callback
2026-07-30 9:46 [PATCH net 00/10] pull request: fixes for ovpn 2026-07-30 Antonio Quartulli
@ 2026-07-30 9:46 ` Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 02/10] ovpn: limit keepalive values to one day Antonio Quartulli
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Antonio Quartulli @ 2026-07-30 9:46 UTC (permalink / raw)
To: netdev
Cc: Ralf Lici, Sabrina Dubroca, Jakub Kicinski, Paolo Abeni,
Andrew Lunn, David S. Miller, Eric Dumazet, Antonio Quartulli
From: Ralf Lici <ralf@mandelbit.com>
ovpn_fill_info emits IFLA_OVPN_MODE inside IFLA_INFO_DATA, but
ovpn_link_ops does not provide a get_size callback. Consequently,
rtnetlink's size estimate for ovpn link messages does not include the
nested mode attribute.
Available skb tailroom may hide this mismatch. When the remaining space
is insufficient, however, ovpn_fill_info returns -EMSGSIZE and message
construction fails.
Add the callback and account for IFLA_OVPN_MODE.
Fixes: c2d950c4672a ("ovpn: add basic interface creation/destruction/management routines")
Signed-off-by: Ralf Lici <ralf@mandelbit.com>
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
drivers/net/ovpn/main.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
index 9993c1dfe471..9d9a0ff690d6 100644
--- a/drivers/net/ovpn/main.c
+++ b/drivers/net/ovpn/main.c
@@ -210,6 +210,12 @@ static int ovpn_newlink(struct net_device *dev,
return register_netdevice(dev);
}
+static size_t ovpn_get_size(const struct net_device *dev)
+{
+ /* IFLA_OVPN_MODE */
+ return nla_total_size(sizeof(u8));
+}
+
static int ovpn_fill_info(struct sk_buff *skb, const struct net_device *dev)
{
struct ovpn_priv *ovpn = netdev_priv(dev);
@@ -228,6 +234,7 @@ static struct rtnl_link_ops ovpn_link_ops = {
.policy = ovpn_policy,
.maxtype = IFLA_OVPN_MAX,
.newlink = ovpn_newlink,
+ .get_size = ovpn_get_size,
.fill_info = ovpn_fill_info,
};
--
2.54.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH net 02/10] ovpn: limit keepalive values to one day
2026-07-30 9:46 [PATCH net 00/10] pull request: fixes for ovpn 2026-07-30 Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 01/10] ovpn: add missing rtnl_link_ops->get_size callback Antonio Quartulli
@ 2026-07-30 9:46 ` Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 03/10] ovpn: skip rehash for peers already removed from by_id Antonio Quartulli
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Antonio Quartulli @ 2026-07-30 9:46 UTC (permalink / raw)
To: netdev
Cc: Marco Baffo, Sabrina Dubroca, Ralf Lici, Jakub Kicinski,
Paolo Abeni, Andrew Lunn, David S. Miller, Eric Dumazet,
Antonio Quartulli
From: Marco Baffo <marco@mandelbit.com>
Large keepalive values can overflow the delayed-work delay on 32-bit
systems, causing the keepalive worker to be repeatedly scheduled.
A correct configuration should not require such large keepalive values,
and an upper limit of one day is already generous and unnecessary in
practice. Limit both the keepalive interval and timeout to 86400 seconds.
Signed-off-by: Marco Baffo <marco@mandelbit.com>
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
Documentation/netlink/specs/ovpn.yaml | 4 ++++
drivers/net/ovpn/netlink-gen.c | 20 ++++++++++++++------
2 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/Documentation/netlink/specs/ovpn.yaml b/Documentation/netlink/specs/ovpn.yaml
index b0c782e59a32..ac50d1d7c00a 100644
--- a/Documentation/netlink/specs/ovpn.yaml
+++ b/Documentation/netlink/specs/ovpn.yaml
@@ -118,12 +118,16 @@ attribute-sets:
doc: >-
The number of seconds after which a keep alive message is sent to the
peer
+ checks:
+ max: 86400
-
name: keepalive-timeout
type: u32
doc: >-
The number of seconds from the last activity after which the peer is
assumed dead
+ checks:
+ max: 86400
-
name: del-reason
type: u32
diff --git a/drivers/net/ovpn/netlink-gen.c b/drivers/net/ovpn/netlink-gen.c
index 2147cec7c2c5..92d2fdc17c2e 100644
--- a/drivers/net/ovpn/netlink-gen.c
+++ b/drivers/net/ovpn/netlink-gen.c
@@ -16,6 +16,14 @@ static const struct netlink_range_validation ovpn_a_peer_id_range = {
.max = 16777215ULL,
};
+static const struct netlink_range_validation ovpn_a_peer_keepalive_interval_range = {
+ .max = 86400ULL,
+};
+
+static const struct netlink_range_validation ovpn_a_peer_keepalive_timeout_range = {
+ .max = 86400ULL,
+};
+
static const struct netlink_range_validation ovpn_a_peer_tx_id_range = {
.max = 16777215ULL,
};
@@ -68,8 +76,8 @@ const struct nla_policy ovpn_peer_nl_policy[OVPN_A_PEER_TX_ID + 1] = {
[OVPN_A_PEER_LOCAL_IPV4] = { .type = NLA_BE32, },
[OVPN_A_PEER_LOCAL_IPV6] = NLA_POLICY_EXACT_LEN(16),
[OVPN_A_PEER_LOCAL_PORT] = NLA_POLICY_MIN(NLA_BE16, 1),
- [OVPN_A_PEER_KEEPALIVE_INTERVAL] = { .type = NLA_U32, },
- [OVPN_A_PEER_KEEPALIVE_TIMEOUT] = { .type = NLA_U32, },
+ [OVPN_A_PEER_KEEPALIVE_INTERVAL] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_keepalive_interval_range),
+ [OVPN_A_PEER_KEEPALIVE_TIMEOUT] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_keepalive_timeout_range),
[OVPN_A_PEER_DEL_REASON] = NLA_POLICY_MAX(NLA_U32, 4),
[OVPN_A_PEER_VPN_RX_BYTES] = { .type = NLA_UINT, },
[OVPN_A_PEER_VPN_TX_BYTES] = { .type = NLA_UINT, },
@@ -97,8 +105,8 @@ const struct nla_policy ovpn_peer_new_input_nl_policy[OVPN_A_PEER_TX_ID + 1] = {
[OVPN_A_PEER_VPN_IPV6] = NLA_POLICY_EXACT_LEN(16),
[OVPN_A_PEER_LOCAL_IPV4] = { .type = NLA_BE32, },
[OVPN_A_PEER_LOCAL_IPV6] = NLA_POLICY_EXACT_LEN(16),
- [OVPN_A_PEER_KEEPALIVE_INTERVAL] = { .type = NLA_U32, },
- [OVPN_A_PEER_KEEPALIVE_TIMEOUT] = { .type = NLA_U32, },
+ [OVPN_A_PEER_KEEPALIVE_INTERVAL] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_keepalive_interval_range),
+ [OVPN_A_PEER_KEEPALIVE_TIMEOUT] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_keepalive_timeout_range),
[OVPN_A_PEER_TX_ID] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_tx_id_range),
};
@@ -112,8 +120,8 @@ const struct nla_policy ovpn_peer_set_input_nl_policy[OVPN_A_PEER_TX_ID + 1] = {
[OVPN_A_PEER_VPN_IPV6] = NLA_POLICY_EXACT_LEN(16),
[OVPN_A_PEER_LOCAL_IPV4] = { .type = NLA_BE32, },
[OVPN_A_PEER_LOCAL_IPV6] = NLA_POLICY_EXACT_LEN(16),
- [OVPN_A_PEER_KEEPALIVE_INTERVAL] = { .type = NLA_U32, },
- [OVPN_A_PEER_KEEPALIVE_TIMEOUT] = { .type = NLA_U32, },
+ [OVPN_A_PEER_KEEPALIVE_INTERVAL] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_keepalive_interval_range),
+ [OVPN_A_PEER_KEEPALIVE_TIMEOUT] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_keepalive_timeout_range),
[OVPN_A_PEER_TX_ID] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_tx_id_range),
};
--
2.54.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH net 03/10] ovpn: skip rehash for peers already removed from by_id
2026-07-30 9:46 [PATCH net 00/10] pull request: fixes for ovpn 2026-07-30 Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 01/10] ovpn: add missing rtnl_link_ops->get_size callback Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 02/10] ovpn: limit keepalive values to one day Antonio Quartulli
@ 2026-07-30 9:46 ` Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 04/10] ovpn: rehash peer in by_transp_addr table on CMD_PEER_SET Antonio Quartulli
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Antonio Quartulli @ 2026-07-30 9:46 UTC (permalink / raw)
To: netdev
Cc: Antonio Quartulli, Sabrina Dubroca, Ralf Lici, Jakub Kicinski,
Paolo Abeni, Andrew Lunn, David S. Miller, Eric Dumazet
ovpn_nl_peer_set_doit() resolves the target peer via
ovpn_peer_get_by_id() before taking ovpn->lock. In the window between
the lookup (which only takes a refcount) and the subsequent
spin_lock_bh(&ovpn->lock), a concurrent OVPN_CMD_PEER_DEL, keepalive
expiry, or socket teardown can take ovpn->lock first, run
ovpn_peer_remove() to unhash the peer from all four tables (by_id,
by_vpn_addr4/6, by_transp_addr) and release the lock. set_doit then
acquires ovpn->lock and calls ovpn_peer_hash_vpn_ip(), which
re-inserts the now-removed peer back into the rehashing tables.
The same race affects the float path: ovpn_peer_endpoints_update()
holds only a refcount and acquires ovpn->lock very late (after async
AEAD decrypt and a netlink notification), then rehashes the peer
in the by_transp_addr table.
The resurrected peer becomes reachable again from the RX lookup
(ovpn_peer_get_by_transp_addr) and the TX VPN-IP lookup, even though
userspace believes it is gone. Once the data-path refcount drops the
peer is freed via call_rcu while the hash entries embedded in it
remain linked, opening a UAF window.
Bail out of the rehash when hash_entry_id is unhashed, mirroring
the sentinel already used by ovpn_peer_remove() to detect the
already-removed state. The check is safe under ovpn->lock, which
serializes every mutation of hash_entry_id, and is a no-op for the
add path because ovpn_peer_add_mp() inserts hash_entry_id before
calling ovpn_peer_hash_vpn_ip().
Fixes: 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
drivers/net/ovpn/peer.c | 73 ++++++++++++++++++++++++-----------------
1 file changed, 43 insertions(+), 30 deletions(-)
diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
index a21d02ac715e..68021c0c1783 100644
--- a/drivers/net/ovpn/peer.c
+++ b/drivers/net/ovpn/peer.c
@@ -297,40 +297,46 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
/* rehashing is required only in MP mode as P2P has one peer
* only and thus there is no hashtable
*/
- if (peer->ovpn->mode == OVPN_MODE_MP) {
- spin_lock_bh(&peer->ovpn->lock);
- spin_lock_bh(&peer->lock);
- bind = rcu_dereference_protected(peer->bind,
- lockdep_is_held(&peer->lock));
- if (unlikely(!bind)) {
- spin_unlock_bh(&peer->lock);
- spin_unlock_bh(&peer->ovpn->lock);
- return;
- }
+ if (peer->ovpn->mode != OVPN_MODE_MP)
+ return;
- /* This function may be invoked concurrently, therefore another
- * float may have happened in parallel: perform rehashing
- * using the peer->bind->remote directly as key
- */
+ spin_lock_bh(&peer->ovpn->lock);
+ spin_lock_bh(&peer->lock);
+ bind = rcu_dereference_protected(peer->bind,
+ lockdep_is_held(&peer->lock));
+ if (unlikely(!bind))
+ goto unlock2;
- switch (bind->remote.in4.sin_family) {
- case AF_INET:
- salen = sizeof(*sa);
- break;
- case AF_INET6:
- salen = sizeof(*sa6);
- break;
- }
+ /* peer may have been concurrently removed between the caller's
+ * initial lookup and our acquisition of ovpn->lock; skip the
+ * rehash so we don't re-insert a removed peer
+ */
+ if (unlikely(hlist_unhashed(&peer->hash_entry_id)))
+ goto unlock2;
- /* remove old hashing */
- hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
- /* re-add with new transport address */
- nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
- &bind->remote, salen);
- hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
- spin_unlock_bh(&peer->lock);
- spin_unlock_bh(&peer->ovpn->lock);
+ /* This function may be invoked concurrently, therefore another
+ * float may have happened in parallel: perform rehashing
+ * using the peer->bind->remote directly as key
+ */
+
+ switch (bind->remote.in4.sin_family) {
+ case AF_INET:
+ salen = sizeof(*sa);
+ break;
+ case AF_INET6:
+ salen = sizeof(*sa6);
+ break;
}
+
+ /* remove old hashing */
+ hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
+ /* re-add with new transport address */
+ nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
+ &bind->remote, salen);
+ hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
+unlock2:
+ spin_unlock_bh(&peer->lock);
+ spin_unlock_bh(&peer->ovpn->lock);
return;
unlock:
spin_unlock_bh(&peer->lock);
@@ -906,6 +912,13 @@ void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer)
if (peer->ovpn->mode != OVPN_MODE_MP)
return;
+ /* peer may have been concurrently removed between the caller's
+ * initial lookup and our acquisition of ovpn->lock; skip the
+ * rehash so we don't re-insert a removed peer
+ */
+ if (hlist_unhashed(&peer->hash_entry_id))
+ return;
+
if (peer->vpn_addrs.ipv4.s_addr != htonl(INADDR_ANY)) {
/* remove potential old hashing */
hlist_nulls_del_init_rcu(&peer->hash_entry_addr4);
--
2.54.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH net 04/10] ovpn: rehash peer in by_transp_addr table on CMD_PEER_SET
2026-07-30 9:46 [PATCH net 00/10] pull request: fixes for ovpn 2026-07-30 Antonio Quartulli
` (2 preceding siblings ...)
2026-07-30 9:46 ` [PATCH net 03/10] ovpn: skip rehash for peers already removed from by_id Antonio Quartulli
@ 2026-07-30 9:46 ` Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 05/10] ovpn: ensure socket is owned by ovpn before deref sk_user_data Antonio Quartulli
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Antonio Quartulli @ 2026-07-30 9:46 UTC (permalink / raw)
To: netdev
Cc: Antonio Quartulli, Sabrina Dubroca, Ralf Lici, Jakub Kicinski,
Paolo Abeni, Andrew Lunn, David S. Miller, Eric Dumazet
When userspace updates a peer's remote endpoint via OVPN_CMD_PEER_SET,
ovpn_nl_peer_modify() installs a new ovpn_bind through
ovpn_peer_reset_sockaddr(), but ovpn_nl_peer_set_doit() only calls
ovpn_peer_hash_vpn_ip() to refresh the VPN-IP hashtables. The peer is
left in the bucket of peers->by_transp_addr corresponding to its old
remote address.
As a consequence, datagrams arriving at the UDP RX path from the newly
configured remote hash to a different slot and the lockless lookup in
ovpn_peer_get_by_transp_addr() (called from ovpn_udp_encap_recv()) does
not find the peer, until either a float event or a peer re-add fixes
the bucket.
Introduce ovpn_peer_hash_transp_addr() (modeled after
ovpn_peer_hash_vpn_ip()) and invoke it from ovpn_nl_peer_set_doit()
whenever the request carried a new remote address. The helper bails
out in P2P mode and on peers without a bind (TCP), and relies on
hlist_nulls_del_init_rcu()'s pprev==NULL short-circuit to handle the
case of an entry not currently linked in the table.
Fixes: 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
drivers/net/ovpn/netlink.c | 6 +++
drivers/net/ovpn/peer.c | 105 +++++++++++++++++++++++++------------
drivers/net/ovpn/peer.h | 1 +
3 files changed, 79 insertions(+), 33 deletions(-)
diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c
index 4c66c1ec497e..4dad85294198 100644
--- a/drivers/net/ovpn/netlink.c
+++ b/drivers/net/ovpn/netlink.c
@@ -534,6 +534,12 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
*/
if (ret > 0)
ovpn_peer_hash_vpn_ip(peer);
+ /* if the remote endpoint was updated, the by_transp_addr hash bucket
+ * also needs to be refreshed, otherwise incoming packets from the new
+ * remote address would fail the lockless lookup
+ */
+ if (attrs[OVPN_A_PEER_REMOTE_IPV4] || attrs[OVPN_A_PEER_REMOTE_IPV6])
+ ovpn_peer_hash_transp_addr(peer);
spin_unlock_bh(&ovpn->lock);
ovpn_peer_put(peer);
diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
index 68021c0c1783..a330892e82bf 100644
--- a/drivers/net/ovpn/peer.c
+++ b/drivers/net/ovpn/peer.c
@@ -189,6 +189,9 @@ int ovpn_peer_reset_sockaddr(struct ovpn_peer *peer,
&(*__tbl1)[ovpn_get_hash_slot(*__tbl1, _key, _key_len)];\
})
+static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
+ const struct ovpn_bind *bind);
+
/**
* ovpn_peer_endpoints_update - update remote or local endpoint for peer
* @peer: peer to update the remote endpoint for
@@ -196,7 +199,6 @@ int ovpn_peer_reset_sockaddr(struct ovpn_peer *peer,
*/
void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
{
- struct hlist_nulls_head *nhead;
struct sockaddr_storage ss;
struct sockaddr_in6 *sa6;
bool reset_cache = false;
@@ -295,46 +297,23 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
ovpn_nl_peer_float_notify(peer, &ss);
/* rehashing is required only in MP mode as P2P has one peer
- * only and thus there is no hashtable
+ * only and thus there is no hashtable.
+ *
+ * This function may be invoked concurrently, so re-read peer->bind
+ * under the proper locks and rehash against its current value.
*/
if (peer->ovpn->mode != OVPN_MODE_MP)
return;
+ /* This function may be invoked concurrently, therefore another
+ * float may have happened in parallel: re-acquire the locks and
+ * rehash using the peer->bind->remote directly as key
+ */
spin_lock_bh(&peer->ovpn->lock);
spin_lock_bh(&peer->lock);
bind = rcu_dereference_protected(peer->bind,
lockdep_is_held(&peer->lock));
- if (unlikely(!bind))
- goto unlock2;
-
- /* peer may have been concurrently removed between the caller's
- * initial lookup and our acquisition of ovpn->lock; skip the
- * rehash so we don't re-insert a removed peer
- */
- if (unlikely(hlist_unhashed(&peer->hash_entry_id)))
- goto unlock2;
-
- /* This function may be invoked concurrently, therefore another
- * float may have happened in parallel: perform rehashing
- * using the peer->bind->remote directly as key
- */
-
- switch (bind->remote.in4.sin_family) {
- case AF_INET:
- salen = sizeof(*sa);
- break;
- case AF_INET6:
- salen = sizeof(*sa6);
- break;
- }
-
- /* remove old hashing */
- hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
- /* re-add with new transport address */
- nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
- &bind->remote, salen);
- hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
-unlock2:
+ __ovpn_peer_hash_transp_addr(peer, bind);
spin_unlock_bh(&peer->lock);
spin_unlock_bh(&peer->ovpn->lock);
return;
@@ -902,6 +881,66 @@ bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,
return match;
}
+/* Move @peer to the by_transp_addr bucket matching its current bind.
+ *
+ * Caller must hold both peer->ovpn->lock and peer->lock, and must have
+ * already dereferenced a valid (non-NULL) peer->bind, passed in as @bind.
+ */
+static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
+ const struct ovpn_bind *bind)
+{
+ struct hlist_nulls_head *nhead;
+ size_t salen;
+
+ lockdep_assert_held(&peer->ovpn->lock);
+ lockdep_assert_held(&peer->lock);
+
+ if (WARN_ON_ONCE(!bind))
+ return;
+
+ /* peer may have been concurrently removed between the caller's
+ * initial lookup and our acquisition of ovpn->lock; skip the
+ * rehash so we don't re-insert a removed peer
+ */
+ if (unlikely(hlist_unhashed(&peer->hash_entry_id)))
+ return;
+
+ switch (bind->remote.in4.sin_family) {
+ case AF_INET:
+ salen = sizeof(struct sockaddr_in);
+ break;
+ case AF_INET6:
+ salen = sizeof(struct sockaddr_in6);
+ break;
+ default:
+ return;
+ }
+
+ /* remove old hashing (no-op if entry is not currently linked) */
+ hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
+ /* re-add with current transport address */
+ nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
+ &bind->remote, salen);
+ hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
+}
+
+void ovpn_peer_hash_transp_addr(struct ovpn_peer *peer)
+{
+ struct ovpn_bind *bind;
+
+ lockdep_assert_held(&peer->ovpn->lock);
+
+ /* rehashing makes sense only in multipeer mode */
+ if (peer->ovpn->mode != OVPN_MODE_MP)
+ return;
+
+ spin_lock_bh(&peer->lock);
+ bind = rcu_dereference_protected(peer->bind,
+ lockdep_is_held(&peer->lock));
+ __ovpn_peer_hash_transp_addr(peer, bind);
+ spin_unlock_bh(&peer->lock);
+}
+
void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer)
{
struct hlist_nulls_head *nhead;
diff --git a/drivers/net/ovpn/peer.h b/drivers/net/ovpn/peer.h
index 86c8cffada6d..dfa5c0037e02 100644
--- a/drivers/net/ovpn/peer.h
+++ b/drivers/net/ovpn/peer.h
@@ -150,6 +150,7 @@ struct ovpn_peer *ovpn_peer_get_by_id(struct ovpn_priv *ovpn, u32 peer_id);
struct ovpn_peer *ovpn_peer_get_by_dst(struct ovpn_priv *ovpn,
struct sk_buff *skb);
void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer);
+void ovpn_peer_hash_transp_addr(struct ovpn_peer *peer);
bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,
struct ovpn_peer *peer);
--
2.54.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH net 05/10] ovpn: ensure socket is owned by ovpn before deref sk_user_data
2026-07-30 9:46 [PATCH net 00/10] pull request: fixes for ovpn 2026-07-30 Antonio Quartulli
` (3 preceding siblings ...)
2026-07-30 9:46 ` [PATCH net 04/10] ovpn: rehash peer in by_transp_addr table on CMD_PEER_SET Antonio Quartulli
@ 2026-07-30 9:46 ` Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 06/10] ovpn: zero-initialize sockaddr before learning a floated endpoint Antonio Quartulli
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Antonio Quartulli @ 2026-07-30 9:46 UTC (permalink / raw)
To: netdev
Cc: Antonio Quartulli, Sabrina Dubroca, Ralf Lici, Jakub Kicinski,
Paolo Abeni, Andrew Lunn, David S. Miller, Eric Dumazet
Some subsystems, like BPF SOCKMAP, set sk_user_data without
actually setting the encap_type.
For this reason, we must make sure that the type is the
one ovpn expects before dereferencing sk_user_data.
Failing to do so may lead to out-of-bounds reads.
Fixes: f6226ae7a0cd ("ovpn: introduce the ovpn_socket object")
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
drivers/net/ovpn/socket.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/net/ovpn/socket.c b/drivers/net/ovpn/socket.c
index 517caa64a4fe..6cbeb2caaeec 100644
--- a/drivers/net/ovpn/socket.c
+++ b/drivers/net/ovpn/socket.c
@@ -162,6 +162,15 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
rcu_read_lock();
ovpn_sock = rcu_dereference_sk_user_data(sk);
if (ovpn_sock) {
+ /* something else filled the sk_user_data without
+ * setting the encap_type. Reject the socket.
+ */
+ if (!type) {
+ ovpn_sock = ERR_PTR(-EBUSY);
+ rcu_read_unlock();
+ goto sock_release;
+ }
+
/* socket owned by another ovpn instance, we can't use it */
if (ovpn_sock->ovpn != peer->ovpn) {
ovpn_sock = ERR_PTR(-EBUSY);
--
2.54.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH net 06/10] ovpn: zero-initialize sockaddr before learning a floated endpoint
2026-07-30 9:46 [PATCH net 00/10] pull request: fixes for ovpn 2026-07-30 Antonio Quartulli
` (4 preceding siblings ...)
2026-07-30 9:46 ` [PATCH net 05/10] ovpn: ensure socket is owned by ovpn before deref sk_user_data Antonio Quartulli
@ 2026-07-30 9:46 ` Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 07/10] ovpn: hash floated peer by transport identity only Antonio Quartulli
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Antonio Quartulli @ 2026-07-30 9:46 UTC (permalink / raw)
To: netdev
Cc: Antonio Quartulli, Sabrina Dubroca, Ralf Lici, Jakub Kicinski,
Paolo Abeni, Andrew Lunn, David S. Miller, Eric Dumazet
ovpn_peer_endpoints_update() builds the new remote endpoint in an
on-stack struct sockaddr_storage that is left uninitialized. For IPv4
only sin_family/sin_addr/sin_port are written, leaving the 8-byte
sin_zero padding as stack garbage (for IPv6, sin6_flowinfo is left
uninitialized likewise).
ovpn_peer_reset_sockaddr() -> ovpn_bind_from_sockaddr() then memcpy()s
sizeof(struct sockaddr_in)/sizeof(struct sockaddr_in6) bytes - padding
included - into bind->remote. That buffer is later hashed with jhash()
over the same length to place the peer in the by_transp_addr table, so
the garbage padding lands the floated peer in an essentially random
bucket. Lockless lookups in ovpn_peer_get_by_transp_addr() build their
key from a zero-initialized sockaddr_storage, compute a different bucket
and fail to find the peer.
This is also a plain use of uninitialized stack memory in jhash().
Build the floated endpoint with a designated initializer so the
padding (sin_zero for IPv4, sin6_flowinfo for IPv6) is zeroed as part
of the assignment. This keeps the padding out of the by_transp_addr
hash key without memset-ing the whole sockaddr_storage on every
received packet.
Fixes: f0281c1d3732 ("ovpn: add support for updating local or remote UDP endpoint")
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
drivers/net/ovpn/peer.c | 31 +++++++++++++++++++++++--------
1 file changed, 23 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
index a330892e82bf..33fb0a75e600 100644
--- a/drivers/net/ovpn/peer.c
+++ b/drivers/net/ovpn/peer.c
@@ -222,9 +222,16 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
*/
local_ip = &ip_hdr(skb)->daddr;
sa = (struct sockaddr_in *)&ss;
- sa->sin_family = AF_INET;
- sa->sin_addr.s_addr = ip_hdr(skb)->saddr;
- sa->sin_port = udp_hdr(skb)->source;
+ /* use a designated initializer so the sin_zero padding
+ * is zeroed (it ends up in the by_transp_addr hash key)
+ * without memset-ing the whole sockaddr_storage on the
+ * RX fast path
+ */
+ *sa = (struct sockaddr_in) {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = ip_hdr(skb)->saddr,
+ .sin_port = udp_hdr(skb)->source,
+ };
salen = sizeof(*sa);
reset_cache = true;
break;
@@ -250,11 +257,19 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
*/
local_ip = &ipv6_hdr(skb)->daddr;
sa6 = (struct sockaddr_in6 *)&ss;
- sa6->sin6_family = AF_INET6;
- sa6->sin6_addr = ipv6_hdr(skb)->saddr;
- sa6->sin6_port = udp_hdr(skb)->source;
- sa6->sin6_scope_id = ipv6_iface_scope_id(&ipv6_hdr(skb)->saddr,
- skb->skb_iif);
+ /* use a designated initializer so the sin6_flowinfo
+ * padding is zeroed (it ends up in the by_transp_addr
+ * hash key) without memset-ing the whole
+ * sockaddr_storage on the RX fast path
+ */
+ *sa6 = (struct sockaddr_in6) {
+ .sin6_family = AF_INET6,
+ .sin6_addr = ipv6_hdr(skb)->saddr,
+ .sin6_port = udp_hdr(skb)->source,
+ .sin6_scope_id =
+ ipv6_iface_scope_id(&ipv6_hdr(skb)->saddr,
+ skb->skb_iif),
+ };
salen = sizeof(*sa6);
reset_cache = true;
break;
--
2.54.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH net 07/10] ovpn: hash floated peer by transport identity only
2026-07-30 9:46 [PATCH net 00/10] pull request: fixes for ovpn 2026-07-30 Antonio Quartulli
` (5 preceding siblings ...)
2026-07-30 9:46 ` [PATCH net 06/10] ovpn: zero-initialize sockaddr before learning a floated endpoint Antonio Quartulli
@ 2026-07-30 9:46 ` Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 08/10] ovpn: disable IPv4 redirects on MP interfaces Antonio Quartulli
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Antonio Quartulli @ 2026-07-30 9:46 UTC (permalink / raw)
To: netdev
Cc: Antonio Quartulli, Sabrina Dubroca, Ralf Lici, Jakub Kicinski,
Paolo Abeni, Andrew Lunn, David S. Miller, Eric Dumazet
The by_transp_addr table is keyed on the peer's remote transport
address, but the float rehash hashed bind->remote directly, while the
two other sites that touch the table build a clean key first:
ovpn_peer_add_mp() and the lookup in ovpn_peer_get_by_transp_addr()
both hash a sockaddr holding only family/address/port.
For a link-local IPv6 peer, bind->remote carries sin6_scope_id (set
from ipv6_iface_scope_id() when the endpoint is learned), and that
field is folded into the jhash() over sizeof(struct sockaddr_in6).
The lookup never sets sin6_scope_id, so after such a peer floats it is
rehashed into a scope_id-dependent bucket that lookups (scope_id 0)
never visit, making the peer unreachable through the by_transp_addr
fallback. ovpn_peer_transp_match() only compares address and port, so
the hash was keying on a field the match ignores.
sin6_scope_id must stay in bind->remote because the TX path uses it as
flowi6_oif, so it cannot just be cleared there. Instead build the hash
key from family/address/port only, exactly like ovpn_peer_add_mp() and
the lookup, so all three sites agree on the bucket.
Fixes: f0281c1d3732 ("ovpn: add support for updating local or remote UDP endpoint")
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
drivers/net/ovpn/peer.c | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
index 33fb0a75e600..eada414a9d92 100644
--- a/drivers/net/ovpn/peer.c
+++ b/drivers/net/ovpn/peer.c
@@ -904,7 +904,10 @@ bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,
static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
const struct ovpn_bind *bind)
{
+ struct sockaddr_storage sa = {};
struct hlist_nulls_head *nhead;
+ struct sockaddr_in6 *sa6;
+ struct sockaddr_in *sa4;
size_t salen;
lockdep_assert_held(&peer->ovpn->lock);
@@ -920,12 +923,26 @@ static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
if (unlikely(hlist_unhashed(&peer->hash_entry_id)))
return;
+ /* Build the hash key from the transport identity only
+ * (family/address/port), matching ovpn_peer_add_mp() and the lookup
+ * in ovpn_peer_get_by_transp_addr(). Hashing bind->remote directly
+ * would fold in sin6_scope_id (set on the float path but never by the
+ * lookup), scattering the peer into a bucket lookups cannot reach.
+ */
switch (bind->remote.in4.sin_family) {
case AF_INET:
- salen = sizeof(struct sockaddr_in);
+ sa4 = (struct sockaddr_in *)&sa;
+ sa4->sin_family = AF_INET;
+ sa4->sin_addr.s_addr = bind->remote.in4.sin_addr.s_addr;
+ sa4->sin_port = bind->remote.in4.sin_port;
+ salen = sizeof(*sa4);
break;
case AF_INET6:
- salen = sizeof(struct sockaddr_in6);
+ sa6 = (struct sockaddr_in6 *)&sa;
+ sa6->sin6_family = AF_INET6;
+ sa6->sin6_addr = bind->remote.in6.sin6_addr;
+ sa6->sin6_port = bind->remote.in6.sin6_port;
+ salen = sizeof(*sa6);
break;
default:
return;
@@ -934,8 +951,8 @@ static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
/* remove old hashing (no-op if entry is not currently linked) */
hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
/* re-add with current transport address */
- nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
- &bind->remote, salen);
+ nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr, &sa,
+ salen);
hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH net 08/10] ovpn: disable IPv4 redirects on MP interfaces
2026-07-30 9:46 [PATCH net 00/10] pull request: fixes for ovpn 2026-07-30 Antonio Quartulli
` (6 preceding siblings ...)
2026-07-30 9:46 ` [PATCH net 07/10] ovpn: hash floated peer by transport identity only Antonio Quartulli
@ 2026-07-30 9:46 ` Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 09/10] ovpn: ensure TCP vars are initialized first Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 10/10] ovpn: fix incorrect use of rcu_access_pointer() Antonio Quartulli
9 siblings, 0 replies; 11+ messages in thread
From: Antonio Quartulli @ 2026-07-30 9:46 UTC (permalink / raw)
To: netdev
Cc: Antonio Quartulli, Sabrina Dubroca, Ralf Lici, Jakub Kicinski,
Paolo Abeni, Andrew Lunn, David S. Miller, Eric Dumazet
ovpn_mp_alloc() tried to disable SEND_REDIRECTS on a multipeer
interface, but it runs from ovpn_net_init() (->ndo_init), which
register_netdevice() invokes before the NETDEV_REGISTER notifier
chain. The IPv4 in_device is only created when that notifier reaches
inetdev_event() -> inetdev_init(), so __in_dev_get_rtnl() always
returned NULL at ndo_init time and the whole redirect-disabling block
(both the per-device and the per-netns IPV4_DEVCONF_ALL write) was
dead. MP interfaces therefore kept emitting ICMP redirects.
Disabling redirects only once is not enough either: the IPv4
in_device is destroyed and recreated when the interface is moved to a
different network namespace (NETDEV_UNREGISTER/NETDEV_REGISTER), and
the newly created in_device inherits the destination namespace
defaults, silently re-enabling SEND_REDIRECTS.
Disable redirects from ovpn_net_open() (->ndo_open) instead: it runs
every time the interface is brought up, including after the in_device
has been recreated, so the setting is always re-applied. This mirrors
what wireguard does in wg_open(). RTNL is held on the ndo_open() path,
so __in_dev_get_rtnl() is safe.
Fixes: 05003b408c20 ("ovpn: implement multi-peer support")
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
drivers/net/ovpn/main.c | 50 ++++++++++++++++++++++++++++-------------
1 file changed, 35 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
index 9d9a0ff690d6..3a04757d5c31 100644
--- a/drivers/net/ovpn/main.c
+++ b/drivers/net/ovpn/main.c
@@ -35,25 +35,11 @@ static void ovpn_priv_free(struct net_device *net)
static int ovpn_mp_alloc(struct ovpn_priv *ovpn)
{
- struct in_device *dev_v4;
int i;
if (ovpn->mode != OVPN_MODE_MP)
return 0;
- dev_v4 = __in_dev_get_rtnl(ovpn->dev);
- if (dev_v4) {
- /* disable redirects as Linux gets confused by ovpn
- * handling same-LAN routing.
- * This happens because a multipeer interface is used as
- * relay point between hosts in the same subnet, while
- * in a classic LAN this would not be needed because the
- * two hosts would be able to talk directly.
- */
- IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false);
- IPV4_DEVCONF_ALL(dev_net(ovpn->dev), SEND_REDIRECTS) = false;
- }
-
/* the peer container is fairly large, therefore we allocate it only in
* MP mode
*/
@@ -97,9 +83,38 @@ static void ovpn_net_uninit(struct net_device *dev)
gro_cells_destroy(&ovpn->gro_cells);
}
+static int ovpn_net_open(struct net_device *dev)
+{
+ struct ovpn_priv *ovpn = netdev_priv(dev);
+ struct in_device *dev_v4;
+
+ /* the IPv4 in_device (and thus its config) is recreated whenever the
+ * interface is moved to a new netns, so redirects must be disabled on
+ * every bring-up rather than once at creation time, otherwise the
+ * setting is silently lost after such a move
+ */
+ if (ovpn->mode == OVPN_MODE_MP) {
+ dev_v4 = __in_dev_get_rtnl(dev);
+ if (dev_v4) {
+ /* disable redirects as Linux gets confused by ovpn
+ * handling same-LAN routing.
+ * This happens because a multipeer interface is used as
+ * relay point between hosts in the same subnet, while
+ * in a classic LAN this would not be needed because the
+ * two hosts would be able to talk directly.
+ */
+ IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false);
+ IPV4_DEVCONF_ALL(dev_net(dev), SEND_REDIRECTS) = false;
+ }
+ }
+
+ return 0;
+}
+
static const struct net_device_ops ovpn_netdev_ops = {
.ndo_init = ovpn_net_init,
.ndo_uninit = ovpn_net_uninit,
+ .ndo_open = ovpn_net_open,
.ndo_start_xmit = ovpn_net_xmit,
};
@@ -183,6 +198,7 @@ static int ovpn_newlink(struct net_device *dev,
struct ovpn_priv *ovpn = netdev_priv(dev);
struct nlattr **data = params->data;
enum ovpn_mode mode = OVPN_MODE_P2P;
+ int ret;
if (data && data[IFLA_OVPN_MODE]) {
mode = nla_get_u8(data[IFLA_OVPN_MODE]);
@@ -207,7 +223,11 @@ static int ovpn_newlink(struct net_device *dev,
else
netif_carrier_off(dev);
- return register_netdevice(dev);
+ ret = register_netdevice(dev);
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
static size_t ovpn_get_size(const struct net_device *dev)
--
2.54.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH net 09/10] ovpn: ensure TCP vars are initialized first
2026-07-30 9:46 [PATCH net 00/10] pull request: fixes for ovpn 2026-07-30 Antonio Quartulli
` (7 preceding siblings ...)
2026-07-30 9:46 ` [PATCH net 08/10] ovpn: disable IPv4 redirects on MP interfaces Antonio Quartulli
@ 2026-07-30 9:46 ` Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 10/10] ovpn: fix incorrect use of rcu_access_pointer() Antonio Quartulli
9 siblings, 0 replies; 11+ messages in thread
From: Antonio Quartulli @ 2026-07-30 9:46 UTC (permalink / raw)
To: netdev
Cc: Antonio Quartulli, Sabrina Dubroca, Ralf Lici, Jakub Kicinski,
Paolo Abeni, Andrew Lunn, David S. Miller, Eric Dumazet
Netlink calls may access TCP global vars (i.e. when attaching
a TCP socket), therefore we need to make sure the
latters are initialized beforehand.
For this reason move the global TCP initialization at the top
of the module init function.
Fixes: 11851cbd60ea ("ovpn: implement TCP transport")
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
drivers/net/ovpn/main.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
index 3a04757d5c31..168cfe9b59a9 100644
--- a/drivers/net/ovpn/main.c
+++ b/drivers/net/ovpn/main.c
@@ -260,8 +260,11 @@ static struct rtnl_link_ops ovpn_link_ops = {
static int __init ovpn_init(void)
{
- int err = rtnl_link_register(&ovpn_link_ops);
+ int err;
+ ovpn_tcp_init();
+
+ err = rtnl_link_register(&ovpn_link_ops);
if (err) {
pr_err("ovpn: can't register rtnl link ops: %d\n", err);
return err;
@@ -273,8 +276,6 @@ static int __init ovpn_init(void)
goto unreg_rtnl;
}
- ovpn_tcp_init();
-
return 0;
unreg_rtnl:
--
2.54.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH net 10/10] ovpn: fix incorrect use of rcu_access_pointer()
2026-07-30 9:46 [PATCH net 00/10] pull request: fixes for ovpn 2026-07-30 Antonio Quartulli
` (8 preceding siblings ...)
2026-07-30 9:46 ` [PATCH net 09/10] ovpn: ensure TCP vars are initialized first Antonio Quartulli
@ 2026-07-30 9:46 ` Antonio Quartulli
9 siblings, 0 replies; 11+ messages in thread
From: Antonio Quartulli @ 2026-07-30 9:46 UTC (permalink / raw)
To: netdev
Cc: Qingfang Deng, Sabrina Dubroca, Ralf Lici, Jakub Kicinski,
Paolo Abeni, Andrew Lunn, David S. Miller, Eric Dumazet,
Antonio Quartulli
From: Qingfang Deng <qingfang.deng@linux.dev>
rcu_access_pointer() should only be used to test the value of a pointer,
not to dereference it. As it's in a spin_lock_bh() critical section, use
rcu_dereference_bh() instead, avoiding an extra rcu_read_lock().
Fixes: f6226ae7a0cd ("ovpn: introduce the ovpn_socket object")
Signed-off-by: Qingfang Deng <qingfang.deng@linux.dev>
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
drivers/net/ovpn/peer.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
index eada414a9d92..b0519f9840d8 100644
--- a/drivers/net/ovpn/peer.c
+++ b/drivers/net/ovpn/peer.c
@@ -1249,7 +1249,7 @@ static void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, struct sock *sk,
}
if (sk) {
- ovpn_sock = rcu_access_pointer(peer->sock);
+ ovpn_sock = rcu_dereference_bh(peer->sock);
if (!ovpn_sock || ovpn_sock->sk != sk) {
spin_unlock_bh(&ovpn->lock);
return;
--
2.54.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-07-30 9:46 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-30 9:46 [PATCH net 00/10] pull request: fixes for ovpn 2026-07-30 Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 01/10] ovpn: add missing rtnl_link_ops->get_size callback Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 02/10] ovpn: limit keepalive values to one day Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 03/10] ovpn: skip rehash for peers already removed from by_id Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 04/10] ovpn: rehash peer in by_transp_addr table on CMD_PEER_SET Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 05/10] ovpn: ensure socket is owned by ovpn before deref sk_user_data Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 06/10] ovpn: zero-initialize sockaddr before learning a floated endpoint Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 07/10] ovpn: hash floated peer by transport identity only Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 08/10] ovpn: disable IPv4 redirects on MP interfaces Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 09/10] ovpn: ensure TCP vars are initialized first Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 10/10] ovpn: fix incorrect use of rcu_access_pointer() Antonio Quartulli
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox