From nobody Tue Nov 26 22:24:37 2024 Received: from mail-wm1-f51.google.com (mail-wm1-f51.google.com [209.85.128.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3BC711D1E9C for ; Wed, 16 Oct 2024 01:04:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729040667; cv=none; b=CPXk8NdDkawpUChQz3+8s2Cmync/k36t1WUmpcpL6HAqiA53HImy/yxQPzqb2BA+Z9KPBwK7eWgl9W3wz1IwwR+MFkEVCMnRY/AhLVbX8qgeQKXYcVk9GZmwg9Ly9ZQUehq0QRqY4FQo3PSP1rnDbBI6M6WrYZj3Olvz7gfsHzY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729040667; c=relaxed/simple; bh=D9XOuq5NLdXjEhB+gziaUN9VEXaSfc+cmeGM+FY4CmY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hTCIqNnGbqJC6WRaP/VDl/5jR21L9DypTMfNJ5OE+1LB1SMCkWLac6Py5mnYjTHAjZSQHcemk4/M+huWy1Vq6sqYOQrvDA0FExkOXYADXWwiLsb8kfAdDPpjctVuhBkMN1sRRTustD55jwmRLwSyqM4O+PiE/3bGPQKeujOTdvs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=openvpn.net; spf=pass smtp.mailfrom=openvpn.com; dkim=pass (2048-bit key) header.d=openvpn.net header.i=@openvpn.net header.b=VOuZ7Mzd; arc=none smtp.client-ip=209.85.128.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=openvpn.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=openvpn.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=openvpn.net header.i=@openvpn.net header.b="VOuZ7Mzd" Received: by mail-wm1-f51.google.com with SMTP id 5b1f17b1804b1-42f6bec84b5so57638235e9.1 for ; Tue, 15 Oct 2024 18:04:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1729040663; x=1729645463; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=rMD7l+FSF3xKMSQaJEdYL4+0Pf5IdciRVFCya7TYwek=; b=VOuZ7MzdF8uODgIL+Y1UYc+lrykA72PARhGSHYjihkH62+sMdPLUdIEK6IGB0Q6Suf 9l4wnTLm08Q2X0F2L8r1q4iUXaNscZR5POFauBd3Klba4l1Dg3WfkSimmgKLO864avVN GCj14gDWYyutpVElR1mh5GhJe7HXUCCIcmaLZc0EHz5dMFgF1hThK19V7mZlIEMk7oFA Qn4PQ+Z/CjYz7MDOOmRhW4NZPeoG1eb2hi1fN3h5rk1D6y7PCSEYnvzJtlsFMUB1zmh5 dlyEsyFQW7ELZyEwUwbGtVVMcHPOCHMqiUIIIJRiTcXkWkSEChuDA0xtdsgCtqOkU/yH VmlQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1729040663; x=1729645463; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=rMD7l+FSF3xKMSQaJEdYL4+0Pf5IdciRVFCya7TYwek=; b=TH58n8iEecUKV0pweQ1RHU6gkMMjIeGHIz54YUSloeteoZhgkaeADyZVGPKdJWpqBl VRZehhd3PITW1Mr/jyInycazywVFBO+Euow9q82nPf0KlAhNvIvQOoQam0U7J5xi9QUE QBe8kCVLTZsyzoafCWASZfMs9AZk9QLYH7b8UPwIFj1LUKBroP8i3HohkY2ga5mmmDmj JZxRV2v+RhvbEqncyX6yxhINYJgN+UtZ+uZe5ToDss7opwyTHjWaVpyGaQp94CZGVltR xXcplgHrnxlTrBdiQEojdkAastFAIubY0TD55VGb101l8/hNGaBieEB/oeDvw/hL3L90 KFlQ== X-Forwarded-Encrypted: i=1; AJvYcCVxexjdfBj9EXMKM3Ef/CSAS72ljnS4y7Z7QQ+68MwL4A1PKRFFO2ifYS6dADTAY3/YmUeq3PeWy30YGnQ=@vger.kernel.org X-Gm-Message-State: AOJu0Yz3lL8n+iY4NNdLVAZ5nAjHL6fcVT+72/qQHgXyWa1m0JyhqryS aeBel/Tu4HzfxjqrAxF22DPsvAVDKJ0MaeRiyKw2IXsWXv+PZojJSrlC5rMLc+c= X-Google-Smtp-Source: AGHT+IEsXHjvZSLYefO3htqwaxwzORWf8B0OT6ATZfvFpi1yhCfCetRyT7L5kxe4wZAe75IokFMrDg== X-Received: by 2002:a05:600c:1906:b0:42c:b45d:4a7b with SMTP id 5b1f17b1804b1-4314a37bb99mr19466285e9.25.1729040663627; Tue, 15 Oct 2024 18:04:23 -0700 (PDT) Received: from serenity.mandelbit.com ([2001:67c:2fbc:1:4c1a:a7c8:72f5:4282]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-37d7fa8778csm2886765f8f.25.2024.10.15.18.04.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 15 Oct 2024 18:04:22 -0700 (PDT) From: Antonio Quartulli Date: Wed, 16 Oct 2024 03:03:20 +0200 Subject: [PATCH net-next v9 20/23] ovpn: kill key and notify userspace in case of IV exhaustion Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20241016-b4-ovpn-v9-20-aabe9d225ad5@openvpn.net> References: <20241016-b4-ovpn-v9-0-aabe9d225ad5@openvpn.net> In-Reply-To: <20241016-b4-ovpn-v9-0-aabe9d225ad5@openvpn.net> To: Eric Dumazet , Jakub Kicinski , Paolo Abeni , Donald Hunter , Antonio Quartulli , Shuah Khan , donald.hunter@gmail.com, sd@queasysnail.net, ryazanov.s.a@gmail.com, Andrew Lunn Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, openvpn-devel@lists.sourceforge.net, linux-kselftest@vger.kernel.org X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=6543; i=antonio@openvpn.net; h=from:subject:message-id; bh=D9XOuq5NLdXjEhB+gziaUN9VEXaSfc+cmeGM+FY4CmY=; b=owEBbQGS/pANAwAIAQtw5TqgONWHAcsmYgBnDxDxD98nCNTe5ud76sPiUO1YuG5F/Zi1VEblA D3GUuO3E42JATMEAAEIAB0WIQSZq9xs+NQS5N5fwPwLcOU6oDjVhwUCZw8Q8QAKCRALcOU6oDjV h6TZB/9EiC73lma2rR+/IWSXjb+n3h1zfkbNg8sSZZeolW3efmCuf69tdyBmvrVZioFJ2spZXCT YHg46IGSCJvSqne+Lb4IbfO/oao/EjvpOPrFyr6JoyAtdxVnSWkhlyebNuYq/Jq5j9RaSEjBwTU HpsNa/6/9GyaXntUF3ki4Jo9cQ/t8TWbHyMlosrJsCOwzHgmcbkSNJ2Q82HZWxmpN7YWq0c+uuu BxSjOCb8qTiMkwwegrDWnXx2v2Wr/es9Nj9uDzTd9Jo8n/vxnCQgsLOb/qVoqiZqI0ysGUa+913 OP8urs2N/JO9y6BVRTYavxNq4aapB944jH9ju+pL2s0T38Ts X-Developer-Key: i=antonio@openvpn.net; a=openpgp; fpr=CABDA1282017C267219885C748F0CCB68F59D14C 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 --- drivers/net/ovpn/crypto.c | 19 ++++++++++++++++ drivers/net/ovpn/crypto.h | 2 ++ drivers/net/ovpn/io.c | 18 ++++++++++++++- drivers/net/ovpn/netlink.c | 55 ++++++++++++++++++++++++++++++++++++++++++= ++++ drivers/net/ovpn/netlink.h | 2 ++ 5 files changed, 95 insertions(+), 1 deletion(-) diff --git a/drivers/net/ovpn/crypto.c b/drivers/net/ovpn/crypto.c index f1f7510e2f735e367f96eb4982ba82c9af3c8bfc..56ae2f5e5c33e13933f26acd91c= 7786f7c02011a 100644 --- a/drivers/net/ovpn/crypto.c +++ b/drivers/net/ovpn/crypto.c @@ -55,6 +55,25 @@ void ovpn_crypto_state_release(struct ovpn_crypto_state = *cs) } } =20 +/* 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 =3D NULL; + + spin_lock_bh(&cs->lock); + if (rcu_access_pointer(cs->slots[0])->key_id =3D=3D key_id) { + ks =3D rcu_replace_pointer(cs->slots[0], NULL, + lockdep_is_held(&cs->lock)); + } else if (rcu_access_pointer(cs->slots[1])->key_id =3D=3D key_id) { + ks =3D 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 3b437d26b531c3034cca5343c755ef9c7ef57276..53a965ec0fad3402317c1ac580a= a6faad579a09b 100644 --- a/drivers/net/ovpn/crypto.h +++ b/drivers/net/ovpn/crypto.h @@ -136,4 +136,6 @@ void ovpn_crypto_state_release(struct ovpn_crypto_state= *cs); =20 void ovpn_crypto_key_slots_swap(struct ovpn_crypto_state *cs); =20 +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 c857ac9015b75530cf3ae40f8db0d4db4c08e2fa..dc6479d5f3008c4e851bee8d406= 1e4e85bed40f2 100644 --- a/drivers/net/ovpn/io.c +++ b/drivers/net/ovpn/io.c @@ -225,6 +225,7 @@ void ovpn_recv(struct ovpn_peer *peer, struct sk_buff *= skb) =20 void ovpn_encrypt_post(void *data, int ret) { + struct ovpn_crypto_key_slot *ks =3D NULL; struct ovpn_peer *peer =3D NULL; struct sk_buff *skb =3D data; unsigned int orig_len =3D 0; @@ -237,15 +238,28 @@ void ovpn_encrypt_post(void *data, int ret) =20 /* crypto is done, cleanup skb CB and its members */ if (likely(ovpn_skb_cb(skb)->ctx)) { + ks =3D ovpn_skb_cb(skb)->ctx->ks; peer =3D ovpn_skb_cb(skb)->ctx->peer; orig_len =3D ovpn_skb_cb(skb)->ctx->orig_len; =20 - ovpn_crypto_key_slot_put(ovpn_skb_cb(skb)->ctx->ks); aead_request_free(ovpn_skb_cb(skb)->ctx->req); kfree(ovpn_skb_cb(skb)->ctx); ovpn_skb_cb(skb)->ctx =3D NULL; } =20 + if (unlikely(ret =3D=3D -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; =20 @@ -275,6 +289,8 @@ void ovpn_encrypt_post(void *data, int ret) dev_core_stats_tx_dropped_inc(peer->ovpn->dev); if (likely(peer)) ovpn_peer_put(peer); + if (likely(ks)) + ovpn_crypto_key_slot_put(ks); kfree_skb(skb); } =20 diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c index bb96645205b6704f7066b7de9a003e01e63c10f7..09c7df2b1c76c812a3bece6e63c= 9fac13c96c327 100644 --- a/drivers/net/ovpn/netlink.c +++ b/drivers/net/ovpn/netlink.c @@ -903,6 +903,61 @@ int ovpn_nl_key_del_doit(struct sk_buff *skb, struct g= enl_info *info) return 0; } =20 +/** + * 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 nlattr *k_attr; + struct sk_buff *msg; + int ret =3D -EMSGSIZE; + void *hdr; + + netdev_info(peer->ovpn->dev, "peer with id %u must rekey - primary key un= usable.\n", + peer->id); + + msg =3D nlmsg_new(100, GFP_ATOMIC); + if (!msg) + return -ENOMEM; + + hdr =3D genlmsg_put(msg, 0, 0, &ovpn_nl_family, 0, OVPN_CMD_KEY_SWAP_NTF); + if (!hdr) { + ret =3D -ENOBUFS; + goto err_free_msg; + } + + if (nla_put_u32(msg, OVPN_A_IFINDEX, peer->ovpn->dev->ifindex)) + goto err_cancel_msg; + + k_attr =3D 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); + + genlmsg_multicast_netns(&ovpn_nl_family, dev_net(peer->ovpn->dev), msg, + 0, OVPN_NLGRP_PEERS, GFP_ATOMIC); + + return 0; + +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 9e87cf11d1e9813b7a75ddf3705ab7d5fabe899f..33390b13c8904d40b629662005a= 9eb92ff617c3b 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); =20 +int ovpn_nl_key_swap_notify(struct ovpn_peer *peer, u8 key_id); + #endif /* _NET_OVPN_NETLINK_H_ */ --=20 2.45.2