All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next net] netdev: Hide the netdev_priv() origin from GCC in netdev_from_priv()
@ 2026-10-15 17:00 Kees Cook
  2026-10-15 17:07 ` Kees Cook
  0 siblings, 1 reply; 4+ messages in thread
From: Kees Cook @ 2026-10-15 17:00 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Kees Cook, Andrew Lunn, David S. Miller, Eric Dumazet,
	Paolo Abeni, Simon Horman, Gustavo A. R. Silva, Qingfang Deng,
	Jiri Pirko, Brad Spengler, PaX Team, Bill Wendling, Justin Stitt,
	netdev, linuxppc-dev, linux-hardening, Yeswanth Krishna Tellakula,
	stable, linux-kernel

GCC 15.1 and later can compute an object size of 0 for a pointer that
container_of() derives from a pointer into a __counted_by flexible array
member[1]; Clang gets it right. netdev_from_priv() does this with struct
net_device's "priv" array, so when GCC can see that its argument came
from netdev_priv(), FORTIFY_SOURCE sees a zero-sized net_device. Since
commit 9027497a25e3c ("team: use netdev_from_priv()"), adding a port of
another type to a team device can then fail the memcpy() to
"dev->broadcast" in team_setup_by_port(), which GCC sees through after
inlining team_port_add() into team_add_slave():

  memcpy: detected buffer overflow: 4 byte write of buffer size 0
  ...
  kernel BUG at lib/string_helpers.c:1044!
  ...
  Call Trace:
   <TASK>
   team_add_slave.cold+0x88/0x201
   do_set_master+0x11c/0x180
   do_setlink.isra.0+0x3a4/0x1410

Whether GCC inlines that far depends on the architecture and the
configuration. It does on ppc64le, where this was reported, and on
x86_64 with defconfig plus hardening.config or with Debian's
configuration, but not with allmodconfig.

Hide where "priv" came from with OPTIMIZER_HIDE_VAR(), so GCC sees a
net_device of unknown size whose members have their declared sizes. (An
"unknown" size is considered uncheckable by FORTIFY.)  FORTIFY still
bounds writes to members; only the whole-object size becomes unknown,
as it already is for any net_device pointer GCC can't trace to its
allocation. In an extracted PoC, the __builtin_dynamic_object_size()
of "dev->broadcast" for the two types FORTIFY sees, before and after
this patch:

                                   GCC 16.2.0      Clang 22 and 24
                                 before   after
  plain pointer, whole object   unknown  unknown        44
  container_of(), whole object        0  unknown        44
  container_of(), member              0       32        32

In addition to getting the bogus "0" fixed in GCC, I'll be following up
to solve the whole-object visiblity disparity as well.

Build tested with GCC 16.2.0: ARCH=x86_64 defconfig with hardening.config,
CONFIG_NET_TEAM=y, and CONFIG_NET_IPGRE=y; ARCH=arm64 defconfig with
hardening.config, CONFIG_NET_TEAM=y, CONFIG_PPP=y, and CONFIG_NET_AIROHA=m;
and drivers/net/team/, drivers/net/ppp/, and drivers/net/ethernet/airoha/
in ARCH=x86_64 allmodconfig. Under QEMU, the x86_64 kernel hits the BUG
above when adding the GRE fallback device "gre0" as a port of a new team
device without this patch, and adds it with the patch.

Reported-by: Yeswanth Krishna Tellakula <yeswanth@linux.ibm.com>
Closes: https://lore.kernel.org/all/3ad19e86-234c-408f-896e-0d6c774fea49@linux.ibm.com/
Fixes: 9027497a25e3c ("team: use netdev_from_priv()")
Cc: stable@vger.kernel.org
Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127875 [1]
Signed-off-by: Kees Cook <kees@kernel.org>
---
 include/linux/netdevice.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 87cafc932e9e..e1dedecd796a 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2838,6 +2838,13 @@ static inline void *netdev_priv(const struct net_device *dev)
  */
 static inline struct net_device *netdev_from_priv(const void *priv)
 {
+	/*
+	 * When GCC can see that @priv came from netdev_priv(), it can
+	 * compute an object size of 0 for the net_device and its members,
+	 * which makes FORTIFY_SOURCE fail valid accesses through the result:
+	 * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127875
+	 */
+	OPTIMIZER_HIDE_VAR(priv);
 	return container_of(priv, struct net_device, priv);
 }
 
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-10-15 17:58 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-15 17:00 [PATCH net-next net] netdev: Hide the netdev_priv() origin from GCC in netdev_from_priv() Kees Cook
2026-10-15 17:07 ` Kees Cook
2026-10-15 17:34   ` Jakub Kicinski
2026-10-15 17:58     ` Kees Cook

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.