From: Antonio Quartulli <antonio@openvpn.net>
To: netdev@vger.kernel.org, Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>,
Paolo Abeni <pabeni@redhat.com>,
Donald Hunter <donald.hunter@gmail.com>,
Antonio Quartulli <antonio@openvpn.net>,
Shuah Khan <shuah@kernel.org>,
sd@queasysnail.net, ryazanov.s.a@gmail.com,
Andrew Lunn <andrew+netdev@lunn.ch>
Cc: Simon Horman <horms@kernel.org>,
linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
Xiao Liang <shaw.leon@gmail.com>
Subject: [PATCH v21 21/24] ovpn: kill key and notify userspace in case of IV exhaustion
Date: Tue, 04 Mar 2025 01:33:51 +0100 [thread overview]
Message-ID: <20250304-b4-ovpn-tmp-v21-21-d3cbb74bb581@openvpn.net> (raw)
In-Reply-To: <20250304-b4-ovpn-tmp-v21-0-d3cbb74bb581@openvpn.net>
IV wrap-around is cryptographically dangerous for a number of ciphers,
therefore kill the key and inform userspace (via netlink) should the
IV space go exhausted.
Userspace has two ways of deciding when the key has to be renewed before
exhausting the IV space:
1) time based approach:
after X seconds/minutes userspace generates a new key and sends it
to the kernel. This is based on guestimate and normally default
timer value works well.
2) packet count based approach:
after X packets/bytes userspace generates a new key and sends it to
the kernel. Userspace keeps track of the amount of traffic by
periodically polling GET_PEER and fetching the VPN/LINK stats.
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
drivers/net/ovpn/crypto.c | 19 ++++++++++++++
drivers/net/ovpn/crypto.h | 2 ++
drivers/net/ovpn/io.c | 13 ++++++++++
drivers/net/ovpn/netlink.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/ovpn/netlink.h | 2 ++
5 files changed, 100 insertions(+)
diff --git a/drivers/net/ovpn/crypto.c b/drivers/net/ovpn/crypto.c
index f30c59c1193a167d7f420d89b665e2e61c57d81c..b86340e51e0cafe2931221ce91a0f7a977e5a047 100644
--- a/drivers/net/ovpn/crypto.c
+++ b/drivers/net/ovpn/crypto.c
@@ -54,6 +54,25 @@ void ovpn_crypto_state_release(struct ovpn_crypto_state *cs)
}
}
+/* removes the key matching the specified id from the crypto context */
+void ovpn_crypto_kill_key(struct ovpn_crypto_state *cs, u8 key_id)
+{
+ struct ovpn_crypto_key_slot *ks = NULL;
+
+ spin_lock_bh(&cs->lock);
+ if (rcu_access_pointer(cs->slots[0])->key_id == key_id) {
+ ks = rcu_replace_pointer(cs->slots[0], NULL,
+ lockdep_is_held(&cs->lock));
+ } else if (rcu_access_pointer(cs->slots[1])->key_id == key_id) {
+ ks = rcu_replace_pointer(cs->slots[1], NULL,
+ lockdep_is_held(&cs->lock));
+ }
+ spin_unlock_bh(&cs->lock);
+
+ if (ks)
+ ovpn_crypto_key_slot_put(ks);
+}
+
/* Reset the ovpn_crypto_state object in a way that is atomic
* to RCU readers.
*/
diff --git a/drivers/net/ovpn/crypto.h b/drivers/net/ovpn/crypto.h
index d6e888381c82d208c7ff619381858302ea6fbbc7..7c88927830020482ca4d357ac44d3b4916db0891 100644
--- a/drivers/net/ovpn/crypto.h
+++ b/drivers/net/ovpn/crypto.h
@@ -140,4 +140,6 @@ int ovpn_crypto_config_get(struct ovpn_crypto_state *cs,
enum ovpn_key_slot slot,
struct ovpn_key_config *keyconf);
+void ovpn_crypto_kill_key(struct ovpn_crypto_state *cs, u8 key_id);
+
#endif /* _NET_OVPN_OVPNCRYPTO_H_ */
diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c
index 5b673eae255033b9d7d6e7890a46686403d7c222..d81c1a2a958c73e22e548d8e63fc78821b5eb881 100644
--- a/drivers/net/ovpn/io.c
+++ b/drivers/net/ovpn/io.c
@@ -255,6 +255,19 @@ void ovpn_encrypt_post(void *data, int ret)
if (likely(ovpn_skb_cb(skb)->req))
aead_request_free(ovpn_skb_cb(skb)->req);
+ if (unlikely(ret == -ERANGE)) {
+ /* we ran out of IVs and we must kill the key as it can't be
+ * use anymore
+ */
+ netdev_warn(peer->ovpn->dev,
+ "killing key %u for peer %u\n", ks->key_id,
+ peer->id);
+ ovpn_crypto_kill_key(&peer->crypto, ks->key_id);
+ /* let userspace know so that a new key must be negotiated */
+ ovpn_nl_key_swap_notify(peer, ks->key_id);
+ goto err;
+ }
+
if (unlikely(ret < 0))
goto err;
diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c
index 3d8b5e02e103e4177f3abacecfc4b52eb7226b87..d1845c1b446c82111ae349092e779fd46824c83a 100644
--- a/drivers/net/ovpn/netlink.c
+++ b/drivers/net/ovpn/netlink.c
@@ -1094,6 +1094,70 @@ int ovpn_nl_key_del_doit(struct sk_buff *skb, struct genl_info *info)
return 0;
}
+/**
+ * ovpn_nl_key_swap_notify - notify userspace peer's key must be renewed
+ * @peer: the peer whose key needs to be renewed
+ * @key_id: the ID of the key that needs to be renewed
+ *
+ * Return: 0 on success or a negative error code otherwise
+ */
+int ovpn_nl_key_swap_notify(struct ovpn_peer *peer, u8 key_id)
+{
+ struct ovpn_socket *sock;
+ struct nlattr *k_attr;
+ struct sk_buff *msg;
+ int ret = -EMSGSIZE;
+ void *hdr;
+
+ netdev_info(peer->ovpn->dev, "peer with id %u must rekey - primary key unusable.\n",
+ peer->id);
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+ if (!msg)
+ return -ENOMEM;
+
+ hdr = genlmsg_put(msg, 0, 0, &ovpn_nl_family, 0, OVPN_CMD_KEY_SWAP_NTF);
+ if (!hdr) {
+ ret = -ENOBUFS;
+ goto err_free_msg;
+ }
+
+ if (nla_put_u32(msg, OVPN_A_IFINDEX, peer->ovpn->dev->ifindex))
+ goto err_cancel_msg;
+
+ k_attr = nla_nest_start(msg, OVPN_A_KEYCONF);
+ if (!k_attr)
+ goto err_cancel_msg;
+
+ if (nla_put_u32(msg, OVPN_A_KEYCONF_PEER_ID, peer->id))
+ goto err_cancel_msg;
+
+ if (nla_put_u16(msg, OVPN_A_KEYCONF_KEY_ID, key_id))
+ goto err_cancel_msg;
+
+ nla_nest_end(msg, k_attr);
+ genlmsg_end(msg, hdr);
+
+ rcu_read_lock();
+ sock = rcu_dereference(peer->sock);
+ if (!sock) {
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+ genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sock->sk),
+ msg, 0, OVPN_NLGRP_PEERS, GFP_ATOMIC);
+ rcu_read_unlock();
+
+ return 0;
+err_unlock:
+ rcu_read_unlock();
+err_cancel_msg:
+ genlmsg_cancel(msg, hdr);
+err_free_msg:
+ nlmsg_free(msg);
+ return ret;
+}
+
/**
* ovpn_nl_register - perform any needed registration in the NL subsustem
*
diff --git a/drivers/net/ovpn/netlink.h b/drivers/net/ovpn/netlink.h
index 0d6c34e17082cc7c52dd9c5d5ed1e964925b3f4b..5dc84c8e5e803014053faa0d892fc3a7259d40e5 100644
--- a/drivers/net/ovpn/netlink.h
+++ b/drivers/net/ovpn/netlink.h
@@ -12,4 +12,6 @@
int ovpn_nl_register(void);
void ovpn_nl_unregister(void);
+int ovpn_nl_key_swap_notify(struct ovpn_peer *peer, u8 key_id);
+
#endif /* _NET_OVPN_NETLINK_H_ */
--
2.45.3
next prev parent reply other threads:[~2025-03-04 0:34 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-03-04 0:33 [PATCH v21 00/24] Introducing OpenVPN Data Channel Offload Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 01/24] net: introduce OpenVPN Data Channel Offload (ovpn) Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 02/24] ovpn: add basic netlink support Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 03/24] ovpn: add basic interface creation/destruction/management routines Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 04/24] ovpn: keep carrier always on for MP interfaces Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 05/24] ovpn: introduce the ovpn_peer object Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 06/24] ovpn: introduce the ovpn_socket object Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 07/24] ovpn: implement basic TX path (UDP) Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 08/24] ovpn: implement basic RX " Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 09/24] ovpn: implement packet processing Antonio Quartulli
2025-03-04 19:02 ` Sabrina Dubroca
2025-03-04 23:35 ` Antonio Quartulli
2025-03-05 10:06 ` Sabrina Dubroca
2025-03-04 0:33 ` [PATCH v21 10/24] ovpn: store tunnel and transport statistics Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 11/24] ovpn: implement TCP transport Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 12/24] skb: implement skb_send_sock_locked_with_flags() Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 13/24] ovpn: add support for MSG_NOSIGNAL in tcp_sendmsg Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 14/24] ovpn: implement multi-peer support Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 15/24] ovpn: implement peer lookup logic Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 16/24] ovpn: implement keepalive mechanism Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 17/24] ovpn: add support for updating local UDP endpoint Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 18/24] ovpn: add support for peer floating Antonio Quartulli
2025-03-04 18:37 ` Sabrina Dubroca
2025-03-04 23:19 ` Antonio Quartulli
2025-03-05 0:19 ` Antonio Quartulli
2025-03-05 11:20 ` Sabrina Dubroca
2025-03-05 13:14 ` Antonio Quartulli
2025-03-05 16:56 ` Sabrina Dubroca
2025-03-06 10:02 ` Antonio Quartulli
2025-03-07 10:12 ` Sabrina Dubroca
2025-03-10 12:57 ` Antonio Quartulli
2025-03-10 22:32 ` Sabrina Dubroca
2025-03-04 0:33 ` [PATCH v21 19/24] ovpn: implement peer add/get/dump/delete via netlink Antonio Quartulli
2025-03-04 14:35 ` Sabrina Dubroca
2025-03-04 21:42 ` Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 20/24] ovpn: implement key add/get/del/swap " Antonio Quartulli
2025-03-04 12:00 ` Sabrina Dubroca
2025-03-04 12:11 ` Antonio Quartulli
2025-03-04 23:09 ` Sabrina Dubroca
2025-03-05 1:00 ` Antonio Quartulli
2025-03-05 10:11 ` Sabrina Dubroca
2025-03-05 13:17 ` Antonio Quartulli
2025-03-04 0:33 ` Antonio Quartulli [this message]
2025-03-04 0:33 ` [PATCH v21 22/24] ovpn: notify userspace when a peer is deleted Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 23/24] ovpn: add basic ethtool support Antonio Quartulli
2025-03-04 0:33 ` [PATCH v21 24/24] testing/selftests: add test tool and scripts for ovpn module Antonio Quartulli
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250304-b4-ovpn-tmp-v21-21-d3cbb74bb581@openvpn.net \
--to=antonio@openvpn.net \
--cc=andrew+netdev@lunn.ch \
--cc=donald.hunter@gmail.com \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=ryazanov.s.a@gmail.com \
--cc=sd@queasysnail.net \
--cc=shaw.leon@gmail.com \
--cc=shuah@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox