lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20260204-psp-v1-5-5f034e2dfa36@gmail.com>
Date: Wed, 04 Feb 2026 07:20:09 -0800
From: Daniel Zahka <daniel.zahka@...il.com>
To: "David S. Miller" <davem@...emloft.net>, 
 Eric Dumazet <edumazet@...gle.com>, Jakub Kicinski <kuba@...nel.org>, 
 Paolo Abeni <pabeni@...hat.com>, Simon Horman <horms@...nel.org>, 
 Donald Hunter <donald.hunter@...il.com>, Boris Pismenny <borisp@...dia.com>, 
 Saeed Mahameed <saeedm@...dia.com>, Leon Romanovsky <leon@...nel.org>, 
 Tariq Toukan <tariqt@...dia.com>, Mark Bloch <mbloch@...dia.com>, 
 Andrew Lunn <andrew+netdev@...n.ch>, Shuah Khan <shuah@...nel.org>, 
 Willem de Bruijn <willemdebruijn.kernel@...il.com>
Cc: netdev@...r.kernel.org, linux-kselftest@...r.kernel.org, 
 Daniel Zahka <daniel.zahka@...il.com>
Subject: [PATCH net-next 5/9] psp: add driver api for deferred tx key
 deletion

There is a race condition during tx key deletion on devices that use
key identifiers in tx metadata, as opposed to inlining keys
directly. When a key is requested to be deleted, there may be skb's in
the tx ring, whose metadata descriptors contain unaccounted references
to a tx key. Under these conditions, the skb sitting in the tx ring
can race against the request to fw to delete the tx key handle.

The solution implemented here is to provide an api for core to defer
tx key deletion operations until after the driver signals that it is
safe to do so.

Core informs the driver that a key deletion grace period is starting
via psp_dev::tx_grace_begin(). While a grace period is active, core
will queue keys to be deleted to the psp_dev::tx_del_next queue.

Core will then periodically query the driver with
psp_dev::tx_grace_end() to determine if it is safe to delete the
keys it has queued. If it is, core will then move the queued keys into
a new list and begin deleting them, allowing the psp_dev::tx_del_next
queue to begin filling for the next grace period.

Signed-off-by: Daniel Zahka <daniel.zahka@...il.com>
---
 include/net/psp/types.h | 32 +++++++++++++++++
 net/psp/psp.h           |  1 +
 net/psp/psp_main.c      | 93 +++++++++++++++++++++++++++++++++++++++++++++++++
 net/psp/psp_sock.c      | 13 ++++++-
 4 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/include/net/psp/types.h b/include/net/psp/types.h
index 52844ac6f870..280c7fdc713c 100644
--- a/include/net/psp/types.h
+++ b/include/net/psp/types.h
@@ -5,6 +5,7 @@
 
 #include <linux/mutex.h>
 #include <linux/refcount.h>
+#include <linux/workqueue.h>
 
 struct netlink_ext_ack;
 
@@ -58,6 +59,10 @@ struct psp_dev_config {
  * @prev_assocs:	associations which use old (but still usable)
  *			device key
  * @stale_assocs:	associations which use a rotated out key
+ * @tx_del_active:	TX keys to be deleted after the current grace period
+ * @tx_del_next:	TX keys queued for deletion during current grace period
+ * @tx_del_work:	workqueue for periodic grace period checking
+ * @tx_grace_active:	true if a grace period is in progress
  *
  * @stats:	statistics maintained by the core
  * @stats.rotations:	See stats attr key-rotations
@@ -85,6 +90,11 @@ struct psp_dev {
 	struct list_head prev_assocs;
 	struct list_head stale_assocs;
 
+	struct list_head tx_del_active;
+	struct list_head tx_del_next;
+	struct delayed_work tx_del_work;
+	bool tx_grace_active;
+
 	struct {
 		unsigned long rotations;
 		unsigned long stales;
@@ -208,6 +218,28 @@ struct psp_dev_ops {
 	 */
 	void (*tx_key_del)(struct psp_dev *psd, struct psp_assoc *pas);
 
+	/**
+	 * @tx_grace_begin: begin TX grace period tracking
+	 * Begin a new TX grace period. Core will queue tx keys for deletion
+	 * and not delete them until the grace period has elapsed.
+	 *
+	 * Return: 0 on success, error code otherwise. If the operation fails,
+	 * core will try again later and a grace period is not activated.
+	 */
+	int (*tx_grace_begin)(struct psp_dev *psd);
+
+	/**
+	 * @tx_grace_end: check if TX grace period has ended
+	 * Check if the current TX grace period has ended.
+	 *
+	 * Return:
+	 *   0: grace period has ended, core will delete queued tx keys
+	 *   -EAGAIN: grace period has not ended, core will requery later
+	 *   other error: internal error (e.g., device reconfigured), core
+	 *                should return to the tx_grace_begin() phase
+	 */
+	int (*tx_grace_end)(struct psp_dev *psd);
+
 	/**
 	 * @get_stats: get statistics from the device
 	 * Stats required by the spec must be maintained and filled in.
diff --git a/net/psp/psp.h b/net/psp/psp.h
index b86539d5137a..d09fdd956fcb 100644
--- a/net/psp/psp.h
+++ b/net/psp/psp.h
@@ -15,6 +15,7 @@ extern struct mutex psp_devs_lock;
 
 void psp_dev_free(struct psp_dev *psd);
 int psp_dev_check_access(struct psp_dev *psd, struct net *net);
+void psp_tx_key_queue_del(struct psp_dev *psd, struct psp_assoc *pas);
 
 void psp_nl_notify_dev(struct psp_dev *psd, u32 cmd);
 
diff --git a/net/psp/psp_main.c b/net/psp/psp_main.c
index 982c96f74ae3..2fb886edc384 100644
--- a/net/psp/psp_main.c
+++ b/net/psp/psp_main.c
@@ -14,6 +14,10 @@
 DEFINE_XARRAY_ALLOC1(psp_devs);
 struct mutex psp_devs_lock;
 
+#define PSP_TX_DEL_INTERVAL_MS  100
+
+static void psp_tx_del_work_fn(struct work_struct *work);
+
 /**
  * DOC: PSP locking
  *
@@ -64,6 +68,9 @@ psp_dev_create(struct net_device *netdev,
 		    !psd_ops->get_stats))
 		return ERR_PTR(-EINVAL);
 
+	if (WARN_ON(!!psd_ops->tx_grace_begin != !!psd_ops->tx_grace_end))
+		return ERR_PTR(-EINVAL);
+
 	psd = kzalloc(sizeof(*psd), GFP_KERNEL);
 	if (!psd)
 		return ERR_PTR(-ENOMEM);
@@ -77,6 +84,9 @@ psp_dev_create(struct net_device *netdev,
 	INIT_LIST_HEAD(&psd->active_assocs);
 	INIT_LIST_HEAD(&psd->prev_assocs);
 	INIT_LIST_HEAD(&psd->stale_assocs);
+	INIT_LIST_HEAD(&psd->tx_del_active);
+	INIT_LIST_HEAD(&psd->tx_del_next);
+	INIT_DELAYED_WORK(&psd->tx_del_work, psp_tx_del_work_fn);
 	refcount_set(&psd->refcnt, 1);
 
 	mutex_lock(&psp_devs_lock);
@@ -118,6 +128,8 @@ void psp_dev_unregister(struct psp_dev *psd)
 {
 	struct psp_assoc *pas, *next;
 
+	cancel_delayed_work_sync(&psd->tx_del_work);
+
 	mutex_lock(&psp_devs_lock);
 	mutex_lock(&psd->lock);
 
@@ -130,6 +142,15 @@ void psp_dev_unregister(struct psp_dev *psd)
 	xa_store(&psp_devs, psd->id, NULL, GFP_KERNEL);
 	mutex_unlock(&psp_devs_lock);
 
+	list_splice_init(&psd->tx_del_active, &psd->tx_del_next);
+	list_for_each_entry_safe(pas, next, &psd->tx_del_next, assocs_list) {
+		list_del(&pas->assocs_list);
+		psp_dev_tx_key_del(psd, pas);
+		psp_assoc_put(pas->prev);
+		psp_dev_put(psd);
+		kfree(pas);
+	}
+
 	list_splice_init(&psd->active_assocs, &psd->prev_assocs);
 	list_splice_init(&psd->prev_assocs, &psd->stale_assocs);
 	list_for_each_entry_safe(pas, next, &psd->stale_assocs, assocs_list) {
@@ -149,6 +170,78 @@ void psp_dev_unregister(struct psp_dev *psd)
 }
 EXPORT_SYMBOL(psp_dev_unregister);
 
+void psp_tx_key_queue_del(struct psp_dev *psd, struct psp_assoc *pas)
+{
+	lockdep_assert_held(&psd->lock);
+
+	list_add_tail(&pas->assocs_list, &psd->tx_del_next);
+	if (!delayed_work_pending(&psd->tx_del_work))
+		schedule_delayed_work(&psd->tx_del_work,
+				      msecs_to_jiffies(PSP_TX_DEL_INTERVAL_MS));
+}
+
+static void psp_tx_del_work_fn(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct psp_dev *psd = container_of(dwork, struct psp_dev, tx_del_work);
+	struct psp_assoc *pas, *tmp;
+	bool need_reschedule = false;
+	LIST_HEAD(to_free);
+	int err;
+
+	mutex_lock(&psd->lock);
+
+	if (!psp_dev_is_registered(psd))
+		goto out_unlock;
+
+	if (psd->tx_grace_active) {
+		err = psd->ops->tx_grace_end(psd);
+		if (err == -EAGAIN) {
+			need_reschedule = true;
+			goto out_unlock;
+		}
+		if (err) {
+			/* Driver error, restart grace period */
+			psd->tx_grace_active = false;
+			list_splice_init(&psd->tx_del_active, &psd->tx_del_next);
+			goto start_grace;
+		}
+
+		list_for_each_entry_safe(pas, tmp, &psd->tx_del_active,
+					 assocs_list) {
+			list_del(&pas->assocs_list);
+			psp_dev_tx_key_del(psd, pas);
+			list_add_tail(&pas->assocs_list, &to_free);
+		}
+
+		psd->tx_grace_active = false;
+	}
+
+start_grace:
+	if (!list_empty(&psd->tx_del_next)) {
+		err = psd->ops->tx_grace_begin(psd);
+		if (!err) {
+			list_splice_init(&psd->tx_del_next, &psd->tx_del_active);
+			psd->tx_grace_active = true;
+		}
+		need_reschedule = true;
+	}
+
+out_unlock:
+	mutex_unlock(&psd->lock);
+
+	list_for_each_entry_safe(pas, tmp, &to_free, assocs_list) {
+		list_del(&pas->assocs_list);
+		psp_assoc_put(pas->prev);
+		psp_dev_put(psd);
+		kfree(pas);
+	}
+
+	if (need_reschedule)
+		schedule_delayed_work(&psd->tx_del_work,
+				      msecs_to_jiffies(PSP_TX_DEL_INTERVAL_MS));
+}
+
 unsigned int psp_key_size(u32 version)
 {
 	switch (version) {
diff --git a/net/psp/psp_sock.c b/net/psp/psp_sock.c
index 1a97609564e7..d038da122ebb 100644
--- a/net/psp/psp_sock.c
+++ b/net/psp/psp_sock.c
@@ -88,6 +88,11 @@ void psp_dev_tx_key_del(struct psp_dev *psd, struct psp_assoc *pas)
 	psd->ops->tx_key_del(psd, pas);
 }
 
+static bool psp_dev_needs_defer(struct psp_dev *psd)
+{
+	return !!psd->ops->tx_grace_begin;
+}
+
 static void psp_assoc_free(struct work_struct *work)
 {
 	struct psp_assoc *pas = container_of(work, struct psp_assoc, work);
@@ -96,8 +101,14 @@ static void psp_assoc_free(struct work_struct *work)
 	mutex_lock(&psd->lock);
 	if (psd->ops) {
 		list_del(&pas->assocs_list);
-		if (pas->tx.spi && !pas->tx_moved)
+		if (pas->tx.spi && !pas->tx_moved) {
+			if (psp_dev_needs_defer(psd)) {
+				psp_tx_key_queue_del(psd, pas);
+				mutex_unlock(&psd->lock);
+				return;
+			}
 			psp_dev_tx_key_del(psd, pas);
+		}
 	}
 	mutex_unlock(&psd->lock);
 	psp_assoc_put(pas->prev);

-- 
2.47.3


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ