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-next>] [day] [month] [year] [list]
Message-ID: <20250918084823.372000-1-dtatulea@nvidia.com>
Date: Thu, 18 Sep 2025 11:48:21 +0300
From: Dragos Tatulea <dtatulea@...dia.com>
To: Jesper Dangaard Brouer <hawk@...nel.org>, "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>, Ilias Apalodimas <ilias.apalodimas@...aro.org>,
	"Sebastian Andrzej Siewior" <bigeasy@...utronix.de>, Clark Williams
	<clrkwllms@...nel.org>, Steven Rostedt <rostedt@...dmis.org>
CC: Dragos Tatulea <dtatulea@...dia.com>, <netdev@...r.kernel.org>, "Tariq
 Toukan" <tariqt@...dia.com>, <linux-kernel@...r.kernel.org>,
	<linux-rt-devel@...ts.linux.dev>
Subject: [PATCH net-next] page_pool: add debug for release to cache from wrong CPU

Direct page releases to cache must be done on the same CPU as where NAPI
is running. Not doing so results in races that are quite difficult to
debug.

This change adds a debug configuration which issues a warning when
such buggy behaviour is encountered.

Signed-off-by: Dragos Tatulea <dtatulea@...dia.com>
Reviewed-by: Tariq Toukan <tariqt@...dia.com>
---
 net/Kconfig.debug    | 10 +++++++
 net/core/page_pool.c | 66 ++++++++++++++++++++++++++------------------
 2 files changed, 49 insertions(+), 27 deletions(-)

diff --git a/net/Kconfig.debug b/net/Kconfig.debug
index 277fab8c4d77..7cd417fabbdc 100644
--- a/net/Kconfig.debug
+++ b/net/Kconfig.debug
@@ -39,3 +39,13 @@ config DEBUG_NET_SMALL_RTNL
 
 	  Once the conversion completes, rtnl_lock() will be removed
 	  and rtnetlink will gain per-netns scalability.
+
+config DEBUG_PAGE_POOL_CACHE_RELEASE
+	bool "Debug page releases into page_pool cache"
+	depends on DEBUG_KERNEL && NET && PAGE_POOL
+	help
+	  Enable debugging feature to track page releases to the
+	  page_pool cache from incorrect CPUs.
+
+	  This makes it easier to track races related to this incorrect
+	  usage of the page_pool API.
diff --git a/net/core/page_pool.c b/net/core/page_pool.c
index ba70569bd4b0..404064d893d6 100644
--- a/net/core/page_pool.c
+++ b/net/core/page_pool.c
@@ -755,6 +755,33 @@ static bool page_pool_recycle_in_ring(struct page_pool *pool, netmem_ref netmem)
 	return ret;
 }
 
+static bool page_pool_napi_local(const struct page_pool *pool)
+{
+	const struct napi_struct *napi;
+	u32 cpuid;
+
+	/* On PREEMPT_RT the softirq can be preempted by the consumer */
+	if (IS_ENABLED(CONFIG_PREEMPT_RT))
+		return false;
+
+	if (unlikely(!in_softirq()))
+		return false;
+
+	/* Allow direct recycle if we have reasons to believe that we are
+	 * in the same context as the consumer would run, so there's
+	 * no possible race.
+	 * __page_pool_put_page() makes sure we're not in hardirq context
+	 * and interrupts are enabled prior to accessing the cache.
+	 */
+	cpuid = smp_processor_id();
+	if (READ_ONCE(pool->cpuid) == cpuid)
+		return true;
+
+	napi = READ_ONCE(pool->p.napi);
+
+	return napi && READ_ONCE(napi->list_owner) == cpuid;
+}
+
 /* Only allow direct recycling in special circumstances, into the
  * alloc side cache.  E.g. during RX-NAPI processing for XDP_DROP use-case.
  *
@@ -768,6 +795,18 @@ static bool page_pool_recycle_in_cache(netmem_ref netmem,
 		return false;
 	}
 
+#ifdef CONFIG_DEBUG_PAGE_POOL_CACHE_RELEASE
+	if (unlikely(!page_pool_napi_local(pool))) {
+		u32 pp_cpuid = READ_ONCE(pool->cpuid);
+		u32 cpuid = smp_processor_id();
+
+		WARN_RATELIMIT(1, "page_pool %d: direct page release from wrong CPU %d, expected CPU %d",
+			       pool->user.id, cpuid, pp_cpuid);
+
+		return false;
+	}
+#endif
+
 	/* Caller MUST have verified/know (page_ref_count(page) == 1) */
 	pool->alloc.cache[pool->alloc.count++] = netmem;
 	recycle_stat_inc(pool, cached);
@@ -833,33 +872,6 @@ __page_pool_put_page(struct page_pool *pool, netmem_ref netmem,
 	return 0;
 }
 
-static bool page_pool_napi_local(const struct page_pool *pool)
-{
-	const struct napi_struct *napi;
-	u32 cpuid;
-
-	/* On PREEMPT_RT the softirq can be preempted by the consumer */
-	if (IS_ENABLED(CONFIG_PREEMPT_RT))
-		return false;
-
-	if (unlikely(!in_softirq()))
-		return false;
-
-	/* Allow direct recycle if we have reasons to believe that we are
-	 * in the same context as the consumer would run, so there's
-	 * no possible race.
-	 * __page_pool_put_page() makes sure we're not in hardirq context
-	 * and interrupts are enabled prior to accessing the cache.
-	 */
-	cpuid = smp_processor_id();
-	if (READ_ONCE(pool->cpuid) == cpuid)
-		return true;
-
-	napi = READ_ONCE(pool->p.napi);
-
-	return napi && READ_ONCE(napi->list_owner) == cpuid;
-}
-
 void page_pool_put_unrefed_netmem(struct page_pool *pool, netmem_ref netmem,
 				  unsigned int dma_sync_size, bool allow_direct)
 {
-- 
2.48.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ