* Re: [PATCH] qede: fix out-of-bounds check for cqe->len_list[]
From: patchwork-bot+netdevbpf @ 2026-06-27 2:00 UTC (permalink / raw)
To: Matvey Kovalev
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, Pavel.Zhigulin,
netdev, linux-kernel, lvc-project
In-Reply-To: <20260623144602.3521-1-matvey.kovalev@ispras.ru>
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Tue, 23 Jun 2026 17:45:54 +0300 you wrote:
> Move index check before element access.
>
> Fixes: 896f1a2493b5 ("net: qlogic/qede: fix potential out-of-bounds read in qede_tpa_cont() and qede_tpa_end()")
> Found by Linux Verification Center (linuxtesting.org) with SVACE.
>
> Signed-off-by: Matvey Kovalev <matvey.kovalev@ispras.ru>
>
> [...]
Here is the summary with links:
- qede: fix out-of-bounds check for cqe->len_list[]
https://git.kernel.org/netdev/net/c/f9ba47fce593
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH 0/2] net/sched: finish the qdisc_dequeue_peeked conversion (taprio, multiq)
From: patchwork-bot+netdevbpf @ 2026-06-27 2:00 UTC (permalink / raw)
To: Bryam Vargas
Cc: vinicius.gomes, pabeni, jhs, jiri, kuba, davem, edumazet, horms,
netdev, jarkao2, vladimir.oltean, linux-kernel
In-Reply-To: <20260625-b4-disp-31bcb279-v1-0-85c40b83c529@proton.me>
Hello:
This series was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Thu, 25 Jun 2026 04:51:18 -0500 you wrote:
> Commit 77be155cba4e added peek emulation: a non-work-conserving qdisc's
> ->peek dequeues one skb and stashes it in the child's gso_skb. A parent
> that peeks such a child must then take the packet with
> qdisc_dequeue_peeked(), not a direct ->dequeue(), or the stashed skb is
> bypassed and the child's qlen/backlog desync. sch_red and sch_sfb were
> just fixed for this; taprio and multiq still take the direct path.
>
> [...]
Here is the summary with links:
- [1/2] net/sched: sch_taprio: Replace direct dequeue call with peek and qdisc_dequeue_peeked
https://git.kernel.org/netdev/net/c/e056e1dfcddc
- [2/2] net/sched: sch_multiq: Replace direct dequeue call with peek and qdisc_dequeue_peeked
https://git.kernel.org/netdev/net/c/54f6b0c843e2
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH net v2] seg6: validate SRH length before reading fixed fields
From: patchwork-bot+netdevbpf @ 2026-06-27 2:00 UTC (permalink / raw)
To: Nuoqi Gui
Cc: davem, edumazet, kuba, pabeni, horms, andrea.mayer, netdev, bpf,
linux-kernel, m.xhonneux, daniel, dlebrun
In-Reply-To: <20260623-f01-17-seg6-srh-len-v2-1-2edc40e9e3e1@mails.tsinghua.edu.cn>
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Tue, 23 Jun 2026 18:32:31 +0800 you wrote:
> seg6_validate_srh() reads fixed SRH fields such as srh->type and
> srh->hdrlen before checking that the supplied length covers the fixed
> struct ipv6_sr_hdr fields.
>
> The BPF SEG6 encap path reaches this with a BPF program-supplied pointer
> and length: bpf_lwt_push_encap() and the SEG6 local BPF END_B6 and
> END_B6_ENCAP actions call bpf_push_seg6_encap(), which forwards the
> length to seg6_validate_srh() with no minimum-size guard. A 2-byte SEG6
> encap header can therefore make the validator read srh->type at offset 2
> beyond the caller-supplied buffer.
>
> [...]
Here is the summary with links:
- [net,v2] seg6: validate SRH length before reading fixed fields
https://git.kernel.org/netdev/net/c/a75d99f46bf2
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [PATCH ipsec] xfrm: fix sk_dst_cache double-free in xfrm_user_policy()
From: Xiang Mei (Microsoft) @ 2026-06-27 2:40 UTC (permalink / raw)
To: steffen.klassert, herbert, davem, netdev
Cc: edumazet, kuba, pabeni, linux-kernel, AutonomousCodeSecurity,
tgopinath, kys, Xiang Mei (Microsoft)
From: "Xiang Mei (Microsoft)" <xmei5@asu.edu>
xfrm_user_policy() clears the socket dst cache with __sk_dst_reset(),
i.e. the non-atomic __sk_dst_set(sk, NULL): it reads sk_dst_cache with
rcu_dereference_protected(), stores NULL and dst_release()s the old dst.
That is only safe if no other thread modifies sk_dst_cache concurrently.
For a connected UDP socket that does not hold: the transmit fast path
(udp_sendmsg -> sk_dst_check -> sk_dst_reset) resets the cache locklessly
with an atomic xchg(). A per-socket policy change racing a send can make
both sides observe the same old dst and each dst_release() it, dropping
the socket's single reference twice and freeing the xfrm_dst bundle while
it is still referenced:
BUG: KASAN: slab-use-after-free in dst_release
Write of size 4 at addr ffff88801897b6c0 by task exploit/155
Call Trace:
...
dst_release (... ./include/linux/rcuref.h:109)
xfrm_user_policy (./include/net/sock.h:2239 ./include/net/sock.h:2256 net/xfrm/xfrm_state.c:3053)
do_ip_setsockopt (net/ipv4/ip_sockglue.c:1347)
ip_setsockopt (net/ipv4/ip_sockglue.c:1417)
do_sock_setsockopt (net/socket.c:2368)
__sys_setsockopt (net/socket.c:2393)
__x64_sys_setsockopt (net/socket.c:2396)
do_syscall_64 (arch/x86/entry/syscall_64.c:94)
entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
Reachable by an unprivileged user via a user+network namespace.
Use the atomic sk_dst_reset() so the cache is cleared and released with a
single xchg(): whichever side wins releases the dst once, the other sees
NULL and does nothing. Behaviour is otherwise unchanged.
Fixes: 2b06cdf3e688 ("xfrm: Clear sk_dst_cache when applying per-socket policy.")
Fixes: be8f8284cd89 ("net: xfrm: allow clearing socket xfrm policies.")
Reported-by: AutonomousCodeSecurity@microsoft.com
Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
---
net/xfrm/xfrm_state.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index c58cd024e3c6..08ba6805ddb3 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -3010,7 +3010,7 @@ int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen)
if (sockptr_is_null(optval) && !optlen) {
xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL);
xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL);
- __sk_dst_reset(sk);
+ sk_dst_reset(sk);
return 0;
}
@@ -3050,7 +3050,7 @@ int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen)
if (err >= 0) {
xfrm_sk_policy_insert(sk, err, pol);
xfrm_pol_put(pol);
- __sk_dst_reset(sk);
+ sk_dst_reset(sk);
err = 0;
}
--
2.43.0
^ permalink raw reply related
* [PATCH] xfrm: cache the offload ifindex for netlink dumps
From: Cen Zhang @ 2026-06-27 3:00 UTC (permalink / raw)
To: Steffen Klassert, Herbert Xu, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman
Cc: netdev, linux-kernel, baijiaju1990, zzzccc427
Validation reproduced this kernel report:
Oops: general protection fault
Call Trace:
<TASK>
copy_to_user_state_extra+0xb8d/0x1370 [xfrm_user]
? __pfx_copy_to_user_state_extra+0x10/0x10 [xfrm_user]
? __asan_memset+0x23/0x50
? srso_alias_return_thunk+0x5/0xfbef5
? __alloc_skb+0x342/0x960
? srso_alias_return_thunk+0x5/0xfbef5
? __asan_memset+0x23/0x50
? srso_alias_return_thunk+0x5/0xfbef5
? __nlmsg_put+0x147/0x1b0
dump_one_state+0x1c7/0x3e0 [xfrm_user]
xfrm_state_netlink+0xcb/0x130 [xfrm_user]
? __pfx_xfrm_state_netlink+0x10/0x10 [xfrm_user]
? srso_alias_return_thunk+0x5/0xfbef5
? xfrm_user_state_lookup.constprop.0+0x230/0x310 [xfrm_user]
xfrm_get_sa+0x102/0x250 [xfrm_user]
? __pfx_xfrm_get_sa+0x10/0x10 [xfrm_user]
xfrm_user_rcv_msg+0x504/0xaa0 [xfrm_user]
? __pfx_xfrm_user_rcv_msg+0x10/0x10 [xfrm_user]
? srso_alias_return_thunk+0x5/0xfbef5
? stack_trace_save+0x8e/0xc0
? __pfx_stack_trace_save+0x10/0x10
netlink_rcv_skb+0x11f/0x350
? __pfx_xfrm_user_rcv_msg+0x10/0x10 [xfrm_user]
? __pfx_netlink_rcv_skb+0x10/0x10
? __pfx_mutex_lock+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
xfrm_netlink_rcv+0x65/0x80 [xfrm_user]
netlink_unicast+0x600/0x870
? __pfx_netlink_unicast+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? __pfx_stack_trace_save+0x10/0x10
netlink_sendmsg+0x75d/0xc10
? __pfx_netlink_sendmsg+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
____sys_sendmsg+0x77a/0x900
? srso_alias_return_thunk+0x5/0xfbef5
? __pfx_____sys_sendmsg+0x10/0x10
? __pfx_copy_msghdr_from_user+0x10/0x10
? release_sock+0x1a/0x1d0
? srso_alias_return_thunk+0x5/0xfbef5
? netlink_insert+0x143/0xec0
___sys_sendmsg+0xff/0x180
? __pfx____sys_sendmsg+0x10/0x10
? _raw_spin_lock_irqsave+0x85/0xe0
? do_getsockname+0xf9/0x170
? srso_alias_return_thunk+0x5/0xfbef5
? fdget+0x53/0x3b0
__sys_sendmsg+0x111/0x1a0
? __pfx___sys_sendmsg+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? __sys_getsockname+0x8c/0x100
do_syscall_64+0x102/0x5a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
copy_to_user_state_extra() only holds a reference to the outer xfrm_state.
That does not pin x->xso.dev. NETDEV_DOWN and NETDEV_UNREGISTER can race
through xfrm_dev_state_flush(), xfrm_state_delete(), and
xfrm_dev_state_free(), which clears xso->dev and drops the netdev
reference before the GETSA dump reaches xso_to_xuo() and reads
xso->dev->ifindex.
The buggy scenario involves two paths, with each column showing the order
within that path:
XFRM_MSG_GETSA dump path: NETDEV teardown path:
1. xfrm_get_sa() gets xfrm_state 1. xfrm_dev_state_flush() finds x
2. copy_to_user_state_extra() sees 2. xfrm_state_delete() removes x
x->xso.dev from the SAD
3. copy_user_offload() calls 3. xfrm_dev_state_free() clears
xso_to_xuo() xso->dev
4. xso->dev->ifindex dereferences 4. netdev_put() drops the device
a detached net_device reference
Avoid following the live net_device from the dump paths. Cache the
attached ifindex in xfrm_dev_offload when state or policy offload is bound
to a device, and serialize that snapshot instead. This preserves the
user-visible XFRMA_OFFLOAD_DEV value without depending on the embedded
net_device lifetime.
Fixes: 07b87f9eea0c ("xfrm: Fix unregister netdevice hang on hardware offload.")
Assisted-by: Codex:gpt-5.5
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
include/net/xfrm.h | 2 ++
net/xfrm/xfrm_device.c | 1 +
net/xfrm/xfrm_state.c | 1 +
net/xfrm/xfrm_user.c | 38 +++++++++++++++++++++++++++++---------
4 files changed, 33 insertions(+), 9 deletions(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 519a0156a05c..a6d69aaa6cd2 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -162,6 +162,8 @@ struct xfrm_dev_offload {
*/
struct net_device *real_dev;
unsigned long offload_handle;
+ /* Snapshot the attached device index for dump paths. */
+ int ifindex;
u8 dir : 2;
u8 type : 2;
u8 flags : 2;
diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c
index 630f3dd31cc5..44bfaa04e621 100644
--- a/net/xfrm/xfrm_device.c
+++ b/net/xfrm/xfrm_device.c
@@ -313,6 +313,7 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
}
xso->dev = dev;
+ xso->ifindex = dev->ifindex;
netdev_tracker_alloc(dev, &xso->dev_tracker, GFP_ATOMIC);
if (xuo->flags & XFRM_OFFLOAD_INBOUND)
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index c58cd024e3c6..707e29c82020 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1547,6 +1547,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
xso->type = XFRM_DEV_OFFLOAD_PACKET;
xso->dir = xdo->dir;
xso->dev = dev;
+ xso->ifindex = dev->ifindex;
xso->flags = XFRM_DEV_OFFLOAD_FLAG_ACQ;
netdev_hold(dev, &xso->dev_tracker, GFP_ATOMIC);
error = dev->xfrmdev_ops->xdo_dev_state_add(dev, x,
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 6384795ee6b2..0eb87fc998d1 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1201,17 +1201,26 @@ static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb)
return 0;
}
-static void xso_to_xuo(const struct xfrm_dev_offload *xso,
- struct xfrm_user_offload *xuo)
+static void xso_to_xuo_ifindex(const struct xfrm_dev_offload *xso, int ifindex,
+ struct xfrm_user_offload *xuo)
{
- xuo->ifindex = xso->dev->ifindex;
+ xuo->ifindex = ifindex;
if (xso->dir == XFRM_DEV_OFFLOAD_IN)
xuo->flags = XFRM_OFFLOAD_INBOUND;
if (xso->type == XFRM_DEV_OFFLOAD_PACKET)
xuo->flags |= XFRM_OFFLOAD_PACKET;
}
-static int copy_user_offload(struct xfrm_dev_offload *xso, struct sk_buff *skb)
+#ifdef CONFIG_XFRM_MIGRATE
+static void xso_to_xuo(const struct xfrm_dev_offload *xso,
+ struct xfrm_user_offload *xuo)
+{
+ xso_to_xuo_ifindex(xso, xso->dev->ifindex, xuo);
+}
+#endif
+
+static int copy_user_offload_ifindex(const struct xfrm_dev_offload *xso,
+ int ifindex, struct sk_buff *skb)
{
struct xfrm_user_offload *xuo;
struct nlattr *attr;
@@ -1222,11 +1231,22 @@ static int copy_user_offload(struct xfrm_dev_offload *xso, struct sk_buff *skb)
xuo = nla_data(attr);
memset(xuo, 0, sizeof(*xuo));
- xso_to_xuo(xso, xuo);
+ xso_to_xuo_ifindex(xso, ifindex, xuo);
return 0;
}
+static int copy_user_offload(struct xfrm_dev_offload *xso, struct sk_buff *skb)
+{
+ return copy_user_offload_ifindex(xso, xso->dev->ifindex, skb);
+}
+
+static int copy_user_state_offload(const struct xfrm_dev_offload *xso,
+ struct sk_buff *skb)
+{
+ return copy_user_offload_ifindex(xso, READ_ONCE(xso->ifindex), skb);
+}
+
static bool xfrm_redact(void)
{
return IS_ENABLED(CONFIG_SECURITY) &&
@@ -1433,8 +1453,8 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
&x->replay);
if (ret)
goto out;
- if(x->xso.dev)
- ret = copy_user_offload(&x->xso, skb);
+ if (READ_ONCE(x->xso.dev))
+ ret = copy_user_state_offload(&x->xso, skb);
if (ret)
goto out;
if (x->if_id) {
@@ -4046,8 +4066,8 @@ static inline unsigned int xfrm_sa_len(struct xfrm_state *x)
l += nla_total_size(sizeof(*x->coaddr));
if (x->props.extra_flags)
l += nla_total_size(sizeof(x->props.extra_flags));
- if (x->xso.dev)
- l += nla_total_size(sizeof(struct xfrm_user_offload));
+ if (READ_ONCE(x->xso.dev))
+ l += nla_total_size(sizeof(struct xfrm_user_offload));
if (x->props.smark.v | x->props.smark.m) {
l += nla_total_size(sizeof(x->props.smark.v));
l += nla_total_size(sizeof(x->props.smark.m));
--
2.43.0
^ permalink raw reply related
* [PATCH] xfrm: clear mode callbacks after failed mode setup
From: Cen Zhang @ 2026-06-27 3:01 UTC (permalink / raw)
To: Steffen Klassert, Herbert Xu, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Christian Hopps
Cc: netdev, linux-kernel, baijiaju1990, zzzccc427
xfrm_state_gc_task can run long after a failed IPTFS state setup. In the
reproduced case, __xfrm_init_state() cached x->mode_cbs, IPTFS setup
returned -ENOMEM before publishing mode_data, and the temporary module
reference from xfrm_get_mode_cbs() was dropped immediately. The dead state
then kept x->mode_cbs until deferred GC ran after xfrm_iptfs had been
unloaded.
Clear x->mode_cbs when mode init or clone fails before publishing
mode_data. Those states never installed mode-specific state or the
long-term IPTFS module pin, so deferred GC has nothing mode-specific to
destroy and must not retain a callback table pointer past the temporary
lookup reference.
The buggy scenario involves two paths, with each column showing the order
within that path:
failed setup path:
1. cache x->mode_cbs
2. mode setup fails before mode_data
3. drop the temporary module ref
4. dead state keeps x->mode_cbs cached
GC/unload path:
1. xfrm_state_put() queues GC work
2. xfrm_iptfs unloads later
3. xfrm_state_gc_task runs
4. GC dereferences stale x->mode_cbs
This also covers the failed clone path where clone_state() returns before
publishing mode_data.
Validation reproduced this kernel report:
Kernel panic - not syncing: Fatal exception
CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
failslab_stacktrace_filter matched xfrm_iptfs frames
ack_error=-12
FAULT_INJECTION: forcing a failure
BUG: unable to handle page fault
Workqueue: events xfrm_state_gc_task
RIP: xfrm_state_gc_task+0x142/0x650
Modules linked in: esp4_offload xfrm_user [last unloaded: xfrm_iptfs]
Kernel panic - not syncing: Fatal exception
Fixes: 4b3faf610cc6 ("xfrm: iptfs: add new iptfs xfrm mode impl")
Assisted-by: Codex:gpt-5.5
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
net/xfrm/xfrm_state.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index c58cd024e3c6..4d95b2720894 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -2071,8 +2071,11 @@ static struct xfrm_state *xfrm_state_clone_and_setup(struct xfrm_state *orig,
x->mode_cbs = orig->mode_cbs;
if (x->mode_cbs && x->mode_cbs->clone_state) {
- if (x->mode_cbs->clone_state(x, orig))
+ if (x->mode_cbs->clone_state(x, orig)) {
+ if (!x->mode_data)
+ x->mode_cbs = NULL;
goto error;
+ }
}
x->props.reqid = m->new_reqid;
@@ -3291,6 +3294,8 @@ int __xfrm_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
if (x->mode_cbs->init_state)
err = x->mode_cbs->init_state(x);
module_put(x->mode_cbs->owner);
+ if (err && !x->mode_data)
+ x->mode_cbs = NULL;
}
error:
return err;
--
2.43.0
^ permalink raw reply related
* [PATCH] fix: net/batman-adv: batadv_interface_kill_vid: extra batadv_meshif_vlan_put after destroy
From: WenTao Liang @ 2026-06-27 3:46 UTC (permalink / raw)
To: marek.lindner, sw, antonio, sven, davem, edumazet, kuba, pabeni
Cc: horms, b.a.t.m.a.n, netdev, linux-kernel, WenTao Liang, stable
In batadv_interface_kill_vid(), batadv_meshif_vlan_get() acquires a
reference on the vlan object. batadv_meshif_destroy_vlan() internally
calls batadv_meshif_vlan_put() which balances that reference. However, an
additional batadv_meshif_vlan_put(vlan) is called after
batadv_meshif_destroy_vlan(), causing a refcount underflow and potential
use-after-free of the vlan object.
Remove the extra batadv_meshif_vlan_put(vlan) call.
Cc: stable@vger.kernel.org
Fixes: 5d2c05b21337 ("batman-adv: add per VLAN interface attribute framework")
Signed-off-by: WenTao Liang <vulab@iscas.ac.cn>
---
net/batman-adv/mesh-interface.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c
index e7aa45bc6b7a..cc974f243200 100644
--- a/net/batman-adv/mesh-interface.c
+++ b/net/batman-adv/mesh-interface.c
@@ -691,9 +691,6 @@ static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto,
batadv_meshif_destroy_vlan(bat_priv, vlan);
- /* finally free the vlan object */
- batadv_meshif_vlan_put(vlan);
-
return 0;
}
--
2.39.5 (Apple Git-154)
^ permalink raw reply related
* [PATCH v2] xfrm: cache the offload ifindex for netlink dumps
From: Cen Zhang @ 2026-06-27 3:50 UTC (permalink / raw)
To: Steffen Klassert, Herbert Xu, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman
Cc: netdev, linux-kernel, baijiaju1990, zzzccc427
copy_to_user_state_extra() only holds a reference to the outer xfrm_state.
That does not pin x->xso.dev. NETDEV_DOWN and NETDEV_UNREGISTER can race
through xfrm_dev_state_flush(), xfrm_state_delete(), and
xfrm_dev_state_free(), which clears xso->dev and drops the netdev
reference before the GETSA dump reaches xso_to_xuo() and reads
xso->dev->ifindex.
The buggy scenario involves two paths, with each column showing the order
within that path:
XFRM_MSG_GETSA dump path: NETDEV teardown path:
1. xfrm_get_sa() gets xfrm_state 1. xfrm_dev_state_flush() finds x
2. copy_to_user_state_extra() sees 2. xfrm_state_delete() removes x
x->xso.dev from the SAD
3. copy_user_offload() calls 3. xfrm_dev_state_free() clears
xso_to_xuo() xso->dev
4. xso->dev->ifindex dereferences 4. netdev_put() drops the device
a detached net_device reference
Avoid following the live net_device from the dump paths. Cache the
attached ifindex in xfrm_dev_offload when state or policy offload is bound
to a device, and serialize that snapshot instead. This preserves the
user-visible XFRMA_OFFLOAD_DEV value without depending on the embedded
net_device lifetime.
Validation reproduced this kernel report:
Oops: general protection fault
Call Trace:
<TASK>
copy_to_user_state_extra+0xb8d/0x1370 [xfrm_user]
? __pfx_copy_to_user_state_extra+0x10/0x10 [xfrm_user]
? __asan_memset+0x23/0x50
? srso_alias_return_thunk+0x5/0xfbef5
? __alloc_skb+0x342/0x960
? srso_alias_return_thunk+0x5/0xfbef5
? __asan_memset+0x23/0x50
? srso_alias_return_thunk+0x5/0xfbef5
? __nlmsg_put+0x147/0x1b0
dump_one_state+0x1c7/0x3e0 [xfrm_user]
xfrm_state_netlink+0xcb/0x130 [xfrm_user]
? __pfx_xfrm_state_netlink+0x10/0x10 [xfrm_user]
? srso_alias_return_thunk+0x5/0xfbef5
? xfrm_user_state_lookup.constprop.0+0x230/0x310 [xfrm_user]
xfrm_get_sa+0x102/0x250 [xfrm_user]
? __pfx_xfrm_get_sa+0x10/0x10 [xfrm_user]
xfrm_user_rcv_msg+0x504/0xaa0 [xfrm_user]
? __pfx_xfrm_user_rcv_msg+0x10/0x10 [xfrm_user]
? srso_alias_return_thunk+0x5/0xfbef5
? stack_trace_save+0x8e/0xc0
? __pfx_stack_trace_save+0x10/0x10
netlink_rcv_skb+0x11f/0x350
? __pfx_xfrm_user_rcv_msg+0x10/0x10 [xfrm_user]
? __pfx_netlink_rcv_skb+0x10/0x10
? __pfx_mutex_lock+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
xfrm_netlink_rcv+0x65/0x80 [xfrm_user]
netlink_unicast+0x600/0x870
? __pfx_netlink_unicast+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? __pfx_stack_trace_save+0x10/0x10
netlink_sendmsg+0x75d/0xc10
? __pfx_netlink_sendmsg+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
____sys_sendmsg+0x77a/0x900
? srso_alias_return_thunk+0x5/0xfbef5
? __pfx_____sys_sendmsg+0x10/0x10
? __pfx_copy_msghdr_from_user+0x10/0x10
? release_sock+0x1a/0x1d0
? srso_alias_return_thunk+0x5/0xfbef5
? netlink_insert+0x143/0xec0
___sys_sendmsg+0xff/0x180
? __pfx____sys_sendmsg+0x10/0x10
? _raw_spin_lock_irqsave+0x85/0xe0
? do_getsockname+0xf9/0x170
? srso_alias_return_thunk+0x5/0xfbef5
? fdget+0x53/0x3b0
__sys_sendmsg+0x111/0x1a0
? __pfx___sys_sendmsg+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? __sys_getsockname+0x8c/0x100
do_syscall_64+0x102/0x5a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Fixes: 07b87f9eea0c ("xfrm: Fix unregister netdevice hang on hardware offload.")
Assisted-by: Codex:gpt-5.5
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
include/net/xfrm.h | 2 ++
net/xfrm/xfrm_device.c | 1 +
net/xfrm/xfrm_state.c | 1 +
net/xfrm/xfrm_user.c | 38 +++++++++++++++++++++++++++++---------
4 files changed, 33 insertions(+), 9 deletions(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 519a0156a05c..a6d69aaa6cd2 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -162,6 +162,8 @@ struct xfrm_dev_offload {
*/
struct net_device *real_dev;
unsigned long offload_handle;
+ /* Snapshot the attached device index for dump paths. */
+ int ifindex;
u8 dir : 2;
u8 type : 2;
u8 flags : 2;
diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c
index 630f3dd31cc5..44bfaa04e621 100644
--- a/net/xfrm/xfrm_device.c
+++ b/net/xfrm/xfrm_device.c
@@ -313,6 +313,7 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
}
xso->dev = dev;
+ xso->ifindex = dev->ifindex;
netdev_tracker_alloc(dev, &xso->dev_tracker, GFP_ATOMIC);
if (xuo->flags & XFRM_OFFLOAD_INBOUND)
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index c58cd024e3c6..707e29c82020 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1547,6 +1547,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
xso->type = XFRM_DEV_OFFLOAD_PACKET;
xso->dir = xdo->dir;
xso->dev = dev;
+ xso->ifindex = dev->ifindex;
xso->flags = XFRM_DEV_OFFLOAD_FLAG_ACQ;
netdev_hold(dev, &xso->dev_tracker, GFP_ATOMIC);
error = dev->xfrmdev_ops->xdo_dev_state_add(dev, x,
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 6384795ee6b2..0eb87fc998d1 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1201,17 +1201,26 @@ static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb)
return 0;
}
-static void xso_to_xuo(const struct xfrm_dev_offload *xso,
- struct xfrm_user_offload *xuo)
+static void xso_to_xuo_ifindex(const struct xfrm_dev_offload *xso, int ifindex,
+ struct xfrm_user_offload *xuo)
{
- xuo->ifindex = xso->dev->ifindex;
+ xuo->ifindex = ifindex;
if (xso->dir == XFRM_DEV_OFFLOAD_IN)
xuo->flags = XFRM_OFFLOAD_INBOUND;
if (xso->type == XFRM_DEV_OFFLOAD_PACKET)
xuo->flags |= XFRM_OFFLOAD_PACKET;
}
-static int copy_user_offload(struct xfrm_dev_offload *xso, struct sk_buff *skb)
+#ifdef CONFIG_XFRM_MIGRATE
+static void xso_to_xuo(const struct xfrm_dev_offload *xso,
+ struct xfrm_user_offload *xuo)
+{
+ xso_to_xuo_ifindex(xso, xso->dev->ifindex, xuo);
+}
+#endif
+
+static int copy_user_offload_ifindex(const struct xfrm_dev_offload *xso,
+ int ifindex, struct sk_buff *skb)
{
struct xfrm_user_offload *xuo;
struct nlattr *attr;
@@ -1222,11 +1231,22 @@ static int copy_user_offload(struct xfrm_dev_offload *xso, struct sk_buff *skb)
xuo = nla_data(attr);
memset(xuo, 0, sizeof(*xuo));
- xso_to_xuo(xso, xuo);
+ xso_to_xuo_ifindex(xso, ifindex, xuo);
return 0;
}
+static int copy_user_offload(struct xfrm_dev_offload *xso, struct sk_buff *skb)
+{
+ return copy_user_offload_ifindex(xso, xso->dev->ifindex, skb);
+}
+
+static int copy_user_state_offload(const struct xfrm_dev_offload *xso,
+ struct sk_buff *skb)
+{
+ return copy_user_offload_ifindex(xso, READ_ONCE(xso->ifindex), skb);
+}
+
static bool xfrm_redact(void)
{
return IS_ENABLED(CONFIG_SECURITY) &&
@@ -1433,8 +1453,8 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
&x->replay);
if (ret)
goto out;
- if(x->xso.dev)
- ret = copy_user_offload(&x->xso, skb);
+ if (READ_ONCE(x->xso.dev))
+ ret = copy_user_state_offload(&x->xso, skb);
if (ret)
goto out;
if (x->if_id) {
@@ -4046,8 +4066,8 @@ static inline unsigned int xfrm_sa_len(struct xfrm_state *x)
l += nla_total_size(sizeof(*x->coaddr));
if (x->props.extra_flags)
l += nla_total_size(sizeof(x->props.extra_flags));
- if (x->xso.dev)
- l += nla_total_size(sizeof(struct xfrm_user_offload));
+ if (READ_ONCE(x->xso.dev))
+ l += nla_total_size(sizeof(struct xfrm_user_offload));
if (x->props.smark.v | x->props.smark.m) {
l += nla_total_size(sizeof(x->props.smark.v));
l += nla_total_size(sizeof(x->props.smark.m));
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v2] r8169: migrate Rx path to page_pool
From: atharva-potdar @ 2026-06-27 3:52 UTC (permalink / raw)
To: Heiner Kallweit, nic_swsd, Andrew Lunn, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni
Cc: Francois Romieu, netdev, atharvapotdar07
Migrate the Rx path to use the page_pool API, replacing the legacy
alloc_pages() + skb_copy() model with napi_build_skb() for zero-copy
delivery. This prepares the driver for future XDP support.
To prevent MTU regressions and DMA overflows on older MACs
(CVE-2009-1389), the pool allocates higher-order pages using
get_order(SZ_16K), matching the legacy driver behavior.
DMA mapping and cache syncing are delegated to the page_pool core via
PP_FLAG_DMA_MAP and PP_FLAG_DMA_SYNC_DEV to ensure safe operation across
all architectures.
Signed-off-by: atharva-potdar <atharvapotdar07@gmail.com>
---
v2:
- Reverted buffer size to SZ_16K and utilized get_order(SZ_16K) to
prevent MTU regression and mitigate CVE-2009-1389.
- Use napi_build_skb() instead of skb_add_rx_frag() to keep ethernet
headers in the linear data area.
drivers/net/ethernet/realtek/r8169_main.c | 77 ++++++++++++++++-------
1 file changed, 54 insertions(+), 23 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index ec4fc21fa..a9bedf93b 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -31,6 +31,7 @@
#include <linux/unaligned.h>
#include <net/ip6_checksum.h>
#include <net/netdev_queues.h>
+#include <net/page_pool/helpers.h>
#include <net/phy/realtek_phy.h>
#include "r8169.h"
@@ -729,6 +730,7 @@ enum rtl_dash_type {
};
struct rtl8169_private {
+ struct page_pool *rx_pool;
void __iomem *mmio_addr; /* memory map physical address */
struct pci_dev *pci_dev;
struct net_device *dev;
@@ -4161,21 +4163,14 @@ static void rtl8169_mark_to_asic(struct RxDesc *desc)
static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
struct RxDesc *desc)
{
- struct device *d = tp_to_dev(tp);
- int node = dev_to_node(d);
dma_addr_t mapping;
struct page *data;
- data = alloc_pages_node(node, GFP_KERNEL, get_order(R8169_RX_BUF_SIZE));
+ data = page_pool_dev_alloc_pages(tp->rx_pool);
if (!data)
return NULL;
- mapping = dma_map_page(d, data, 0, R8169_RX_BUF_SIZE, DMA_FROM_DEVICE);
- if (unlikely(dma_mapping_error(d, mapping))) {
- netdev_err(tp->dev, "Failed to map RX DMA!\n");
- __free_pages(data, get_order(R8169_RX_BUF_SIZE));
- return NULL;
- }
+ mapping = page_pool_get_dma_addr(data);
desc->addr = cpu_to_le64(mapping);
rtl8169_mark_to_asic(desc);
@@ -4188,14 +4183,16 @@ static void rtl8169_rx_clear(struct rtl8169_private *tp)
int i;
for (i = 0; i < NUM_RX_DESC && tp->Rx_databuff[i]; i++) {
- dma_unmap_page(tp_to_dev(tp),
- le64_to_cpu(tp->RxDescArray[i].addr),
- R8169_RX_BUF_SIZE, DMA_FROM_DEVICE);
- __free_pages(tp->Rx_databuff[i], get_order(R8169_RX_BUF_SIZE));
+ page_pool_put_full_page(tp->rx_pool, tp->Rx_databuff[i], false);
tp->Rx_databuff[i] = NULL;
tp->RxDescArray[i].addr = 0;
tp->RxDescArray[i].opts1 = 0;
}
+
+ if (tp->rx_pool) {
+ page_pool_destroy(tp->rx_pool);
+ tp->rx_pool = NULL;
+ }
}
static int rtl8169_rx_fill(struct rtl8169_private *tp)
@@ -4221,8 +4218,26 @@ static int rtl8169_rx_fill(struct rtl8169_private *tp)
static int rtl8169_init_ring(struct rtl8169_private *tp)
{
+ struct page_pool_params params = {0};
+
rtl8169_init_ring_indexes(tp);
+ params.order = get_order(SZ_16K);
+ params.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
+ params.pool_size = NUM_RX_DESC;
+ params.dev = tp_to_dev(tp);
+ params.nid = dev_to_node(tp_to_dev(tp));
+ params.dma_dir = DMA_FROM_DEVICE;
+ params.offset = 0;
+ params.max_len = SZ_16K;
+ tp->rx_pool = page_pool_create(¶ms);
+ if (IS_ERR(tp->rx_pool)) {
+ int err = PTR_ERR(tp->rx_pool);
+
+ tp->rx_pool = NULL;
+ return err;
+ }
+
memset(tp->tx_skb, 0, sizeof(tp->tx_skb));
memset(tp->Rx_databuff, 0, sizeof(tp->Rx_databuff));
@@ -4777,6 +4792,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget
unsigned int pkt_size, entry = tp->cur_rx % NUM_RX_DESC;
struct RxDesc *desc = tp->RxDescArray + entry;
struct sk_buff *skb;
+ struct page *new_page;
const void *rx_buf;
dma_addr_t addr;
u32 status;
@@ -4820,21 +4836,36 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget
goto release_descriptor;
}
- skb = napi_alloc_skb(&tp->napi, pkt_size);
- if (unlikely(!skb)) {
- dev->stats.rx_dropped++;
- goto release_descriptor;
- }
-
addr = le64_to_cpu(desc->addr);
rx_buf = page_address(tp->Rx_databuff[entry]);
dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE);
prefetch(rx_buf);
- skb_copy_to_linear_data(skb, rx_buf, pkt_size);
- skb->tail += pkt_size;
- skb->len = pkt_size;
- dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
+
+ new_page = page_pool_dev_alloc_pages(tp->rx_pool);
+ if (unlikely(!new_page)) {
+ skb = napi_alloc_skb(&tp->napi, pkt_size);
+ if (unlikely(!skb)) {
+ dev->stats.rx_dropped++;
+ goto release_descriptor;
+ }
+ skb_copy_to_linear_data(skb, rx_buf, pkt_size);
+ skb_put(skb, pkt_size);
+ dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
+ } else {
+ skb = napi_build_skb(page_address(tp->Rx_databuff[entry]), SZ_16K);
+ if (unlikely(!skb)) {
+ page_pool_recycle_direct(tp->rx_pool, new_page);
+ dev->stats.rx_dropped++;
+ goto release_descriptor;
+ }
+
+ skb_put(skb, pkt_size);
+ skb_mark_for_recycle(skb);
+
+ tp->Rx_databuff[entry] = new_page;
+ desc->addr = cpu_to_le64(page_pool_get_dma_addr(new_page));
+ }
rtl8169_rx_csum(skb, status);
skb->protocol = eth_type_trans(skb, dev);
--
2.54.0
^ permalink raw reply related
* Re: [PATCH] tomoyo: Enforce connect policy in TCP Fast Open
From: Tetsuo Handa @ 2026-06-27 5:28 UTC (permalink / raw)
To: Matthieu Buffet
Cc: Bryam Vargas, Mickaël Salaün, Günther Noack,
linux-security-module, Mikhail Ivanov, Paul Moore, Yuchung Cheng,
Eric Dumazet, netdev, Kentaro Takeda
In-Reply-To: <20260619002207.61104-1-matthieu@buffet.re>
On 2026/06/19 9:22, Matthieu Buffet wrote:
> Tomoyo restricted TCP connections in 2011 in commit
> 059d84dbb389 ("TOMOYO: Add socket operation restriction support.")
> using the socket_connect() LSM hook.
>
> However, the MSG_FASTOPEN sendmsg() flag was added in 2012 to allow
> combining connect() and the first sendmsg(). Tomoyo was not updated to
> take this into account in its send hook.
>
> This resulted in a TCP connect policy bypass similar to that reported in
> Landlock in 2024 (see Link below), with the difference that Tomoyo was
> fine when originally merged, and the problem got introduced when adding
> fastopen support, possibly due to lack of synchronization between lsm
> and netdev worlds.
>
> Add MSG_FASTOPEN handling in Tomoyo's existing send hook.
>
> Link: https://github.com/landlock-lsm/linux/issues/41
> Link: https://lore.kernel.org/all/20260616201615.275032-1-hexlabsecurity@proton.me/
> Fixes: cf60af03ca4e ("net-tcp: Fast Open client - sendmsg(MSG_FASTOPEN)")
> Cc: stable@kernel.org
> Signed-off-by: Matthieu Buffet <matthieu@buffet.re>
> ---
> security/tomoyo/network.c | 16 +++++++++++++++-
> 1 file changed, 15 insertions(+), 1 deletion(-)
>
Thank you for finding this problem and making a patch.
I updated your patch like below in order to exclude kernel threads from this check.
If we are OK to go with modifying individual LSM, I'll apply this change.
security/tomoyo/network.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/security/tomoyo/network.c b/security/tomoyo/network.c
index cfc2a019de1e..50d27c773b10 100644
--- a/security/tomoyo/network.c
+++ b/security/tomoyo/network.c
@@ -765,6 +765,15 @@ int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *msg,
const u8 family = tomoyo_sock_family(sock->sk);
const unsigned int type = sock->type;
+ if ((msg->msg_flags & MSG_FASTOPEN) && msg->msg_name && type == SOCK_STREAM &&
+ (family == PF_INET || family == PF_INET6) &&
+ (sock->sk->sk_protocol == IPPROTO_TCP || sock->sk->sk_protocol == IPPROTO_MPTCP)) {
+ address.protocol = SOCK_STREAM;
+ address.operation = TOMOYO_NETWORK_CONNECT;
+ return tomoyo_check_inet_address((struct sockaddr *)msg->msg_name,
+ msg->msg_namelen, 0, &address);
+ }
+
if (!msg->msg_name || !family ||
(type != SOCK_DGRAM && type != SOCK_RAW))
return 0;
--
2.54.0
^ permalink raw reply related
* Re: [PATCH net-next] Documentation: networking: Add a test plan for ethtool pause validation
From: Maxime Chevallier @ 2026-06-27 5:34 UTC (permalink / raw)
To: Jakub Kicinski, Andrew Lunn
Cc: davem, Eric Dumazet, Paolo Abeni, Simon Horman, Russell King,
Heiner Kallweit, Jonathan Corbet, Shuah Khan, Oleksij Rempel,
Vladimir Oltean, Florian Fainelli, thomas.petazzoni, netdev,
linux-kernel, linux-doc
In-Reply-To: <20260626173352.7dc8f106@kernel.org>
Hi Jakub,
On 6/27/26 02:33, Jakub Kicinski wrote:
> On Fri, 26 Jun 2026 14:39:57 +0200 Andrew Lunn wrote:
>> On Fri, Jun 26, 2026 at 10:33:50AM +0200, Maxime Chevallier wrote:
>>>
>>>> Sphinx follows pythons object orientate structure. So you could have a
>>>> class test_ethtool_pause_advertising, with class documentation. And
>>>> then methods within the class which are individual tests. The
>>>> commented out section would then be method documentation.
>>>
>>> Good point, so maybe something along these lines :
>>>
>>> - A class for the test
>>> - methods for indivitual tests
>>> - For readability, I've written what the internal test helper would look
>>> like (_adv_test), and how a test would look like without the helper in
>>> adv_rx_on_tx_on().
>>>
>>> I'm already diving into coding, but it helps me a bit in the definition of the
>>> "description" format :)
>>>
>>> this is what the class would look like :
>>
>> I like this :-)
>
> This is very far from what existing python tests do in netdev.
We can probably drop the class, as it is with this discussion, it's merely a way
to regroup doc common to similar tests. The rest really is the usual set of
ksft funcs you can feed to the run function, with a set of ksft_ethtool_*
annotators for generic checks.
>
> I would prefer to stick to the "bash on steroids" use of Python.
Maxime
^ permalink raw reply
* [PATCH net] octeontx2-pf: fix SQ resource leaks on init failure
From: Dawei Feng @ 2026-06-27 6:03 UTC (permalink / raw)
To: sgoutham
Cc: gakula, sbhatta, hkelam, bbhushan2, andrew+netdev, davem,
edumazet, kuba, pabeni, jbrandeb, richardcochran, amakarov,
netdev, linux-kernel, stable, jianhao.xu, zilin, Dawei Feng
otx2_init_hw_resources() initializes SQ aura and pool resources
before several later setup steps. On failure, err_free_sq_ptrs only
frees SQB pages, leaving the per-SQ sqb_ptrs arrays behind. If
otx2_config_nix_queues() has initialized some SQs before failing, their
qmem-backed resources can be left behind too.
Use otx2_free_sq_res() for the SQ unwind path and let it free sqb_ptrs
even when sq->sqe has not been allocated yet. Also free the PTP
timestamp qmem from the same helper.
The bug was first flagged by an experimental analysis tool we are
developing for kernel memory-management bugs while analyzing
v6.13-rc1. The tool is still under development and is not yet publicly
available. Manual inspection confirms that the bug is still
present in v7.1.1.
An x86_64 allyesconfig build showed no new warnings. As we do not have an
OcteonTX2 PF device and the corresponding AF mailbox setup to test with,
no runtime testing was able to be performed.
Fixes: caa2da34fd25 ("octeontx2-pf: Initialize and config queues")
Fixes: c9c12d339d93 ("octeontx2-pf: Add support for PTP clock")
Cc: stable@vger.kernel.org
Signed-off-by: Dawei Feng <dawei.feng@seu.edu.cn>
---
.../ethernet/marvell/octeontx2/nic/otx2_pf.c | 20 +++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
index 41a0ebdf201e..88ac85354445 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
@@ -1568,14 +1568,15 @@ static void otx2_free_sq_res(struct otx2_nic *pf)
otx2_sq_free_sqbs(pf);
for (qidx = 0; qidx < otx2_get_total_tx_queues(pf); qidx++) {
sq = &qset->sq[qidx];
- /* Skip freeing Qos queues if they are not initialized */
- if (!sq->sqe)
- continue;
- qmem_free(pf->dev, sq->sqe);
- qmem_free(pf->dev, sq->sqe_ring);
- qmem_free(pf->dev, sq->cpt_resp);
- qmem_free(pf->dev, sq->tso_hdrs);
- kfree(sq->sg);
+ /* sq->sqe is not initialized for unused QoS queues */
+ if (sq->sqe) {
+ qmem_free(pf->dev, sq->sqe);
+ qmem_free(pf->dev, sq->sqe_ring);
+ qmem_free(pf->dev, sq->cpt_resp);
+ qmem_free(pf->dev, sq->tso_hdrs);
+ qmem_free(pf->dev, sq->timestamps);
+ kfree(sq->sg);
+ }
kfree(sq->sqb_ptrs);
}
}
@@ -1710,13 +1711,12 @@ int otx2_init_hw_resources(struct otx2_nic *pf)
return err;
err_free_nix_queues:
- otx2_free_sq_res(pf);
otx2_free_cq_res(pf);
otx2_ctx_disable(mbox, NIX_AQ_CTYPE_RQ, false);
err_free_txsch:
otx2_txschq_stop(pf);
err_free_sq_ptrs:
- otx2_sq_free_sqbs(pf);
+ otx2_free_sq_res(pf);
err_free_rq_ptrs:
otx2_free_aura_ptr(pf, AURA_NIX_RQ);
otx2_ctx_disable(mbox, NPA_AQ_CTYPE_POOL, true);
--
2.34.1
^ permalink raw reply related
* Re: [PATCH] fix: net/batman-adv: batadv_interface_kill_vid: extra batadv_meshif_vlan_put after destroy
From: Sven Eckelmann @ 2026-06-27 6:15 UTC (permalink / raw)
To: WenTao Liang
Cc: marek.lindner, sw, antonio, sven, davem, edumazet, kuba, pabeni,
horms, b.a.t.m.a.n, netdev, linux-kernel, stable
In-Reply-To: <20260627034636.59693-1-vulab@iscas.ac.cn>
On Sat, 27 Jun 2026 11:46:36 +0800, WenTao Liang <vulab@iscas.ac.cn> wrote:
Hi,
not-acked
1. please don't send patches to netdev directly. See (from any recent
batadv.git, netdev/net.git netdev/net-next.git or torvalds/linux.git):
$ ./scripts/get_maintainer.pl 20260627034636.59693-1-vulab@iscas.ac.cn.mbx
Marek Lindner <marek.lindner@mailbox.org> (maintainer:BATMAN ADVANCED,blamed_fixes:1/1=100%)
Simon Wunderlich <sw@simonwunderlich.de> (maintainer:BATMAN ADVANCED)
Antonio Quartulli <antonio@mandelbit.com> (maintainer:BATMAN ADVANCED,blamed_fixes:1/1=100%)
Sven Eckelmann <sven@narfation.org> (maintainer:BATMAN ADVANCED)
b.a.t.m.a.n@lists.open-mesh.org (moderated list:BATMAN ADVANCED)
linux-kernel@vger.kernel.org (open list)
2. please add after the "PATCH" the tree which it should enter (in this case
"[PATCH batadv]". See:
./scripts/get_maintainer.pl --scm 20260627034636.59693-1-vulab@iscas.ac.cn.mbx|grep '^git'
git https://git.open-mesh.org/batadv.git
git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
3. Please use a subject line which follows the kernel style. See
https://docs.kernel.org/process/submitting-patches.html#the-canonical-patch-formatA
- no "fix: "
- "batman-adv: " instead of "net/batman-adv: "
- most likely no "batadv_interface_kill_vid: "
- an actual summary of your change (because right now it says it adds(?) an extra put)
> In batadv_interface_kill_vid(), batadv_meshif_vlan_get() acquires a
> reference on the vlan object. batadv_meshif_destroy_vlan() internally
> calls batadv_meshif_vlan_put() which balances that reference. However, an
No, this doesn't balance the reference. The reference put in this function is
for the reference acquired by this function. The batadv_meshif_destroy_vlan()
put is for the reference for its "from .ndo_vlan_rx_add_vid till
.ndo_vlan_rx_kill_vid" lifetime.
You can see exactly the same approach also in batadv_meshif_destroy_netlink()
for its "untagged" vlan. A function which you didn't touch.
> additional batadv_meshif_vlan_put(vlan) is called after
> batadv_meshif_destroy_vlan(), causing a refcount underflow and potential
> use-after-free of the vlan object.
No, doesn't cause an underflow in my setup. Please explain exactly how you
tested this and came the conclusion that this would cause a use-after-free.
Because I can't reproduce this and the patch in this form is causing a memory
leak for me.
>
> Remove the extra batadv_meshif_vlan_put(vlan) call.
No, this can't be the correct solution.
>
>
> diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c
> index e5a55d24..7a1aeeca 100644
> --- a/net/batman-adv/mesh-interface.c
> +++ b/net/batman-adv/mesh-interface.c
> @@ -693,9 +693,6 @@ static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto,
>
> batadv_meshif_destroy_vlan(bat_priv, vlan);
>
> - /* finally free the vlan object */
> - batadv_meshif_vlan_put(vlan);
> -
This looks wrong to me. Now it leaks the VLAN which was acquired at the
beginning of the function. When I add a kref_get-printk right before the
batadv_meshif_destroy_vlan() and in batadv_tt_local_entry_release() before the
puts:
refcnt before batadv_meshif_destroy_vlan: 3
refcnt after batadv_meshif_destroy_vlan: 2
refcnt before batadv_tt_local_entry_release: 2
refcnt after batadv_tt_local_entry_release: 1
As you can see, now the VLAN never reaches the 0 and thus isn't free'd. You can
also directly see the memory leak (which didn't happen before):
root@node01:~# ip l del dev bat0.10
[ 18.127153][ T368] refcnt before batadv_meshif_destroy_vlan: 3
[ 18.128792][ T368] refcnt after batadv_meshif_destroy_vlan: 2
[ 18.649318][ T12] refcnt before batadv_tt_local_entry_release: 2
[ 18.650220][ T12] refcnt after batadv_tt_local_entry_release: 1
root@node01:~# rmmod batman-adv
[ 27.033891][ T374] batman_adv: bat0: Interface deactivated: dummy0
[ 27.034522][ T374] batman_adv: bat0: Removing interface: dummy0
[ 27.038340][ T374] batman_adv: bat0: Interface deactivated: enp0s1
[ 27.038973][ T374] batman_adv: bat0: Removing interface: enp0s1
[ 27.044439][ T374] br0: port 1(bat0) entered disabled state
[ 27.049110][ T374] bat0 (unregistering): left allmulticast mode
[ 27.049486][ T374] bat0 (unregistering): left promiscuous mode
[ 27.049804][ T374] br0: port 1(bat0) entered disabled state
[ 27.096326][ T374] refcnt before batadv_tt_local_entry_release: 1
[ 27.096851][ T374] refcnt after batadv_tt_local_entry_release: 0
root@node01:~# modprobe batman-adv
root@node01:~# echo scan > /sys/kernel/debug/kmemleak
root@node01:~# echo scan > /sys/kernel/debug/kmemleak
[ 41.460324][ T361] kmemleak: 1 new suspected memory leaks (see /sys/kernel/debug/kmemleak)
root@node01:~# cat /sys/kernel/debug/kmemleak
unreferenced object 0xffff88800ab1bd00 (size 64):
comm "ip", pid 300, jiffies 4294893634
hex dump (first 32 bytes):
c0 cb c7 13 80 88 ff ff 0a 80 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace (crc 552e6e51):
kmemleak_alloc+0x55/0xa0
__kmalloc_cache_noprof+0x2f4/0x540
batadv_meshif_create_vlan+0x7c/0x450 [batman_adv]
batadv_interface_add_vid+0xb6/0xd0 [batman_adv]
vlan_add_rx_filter_info+0xee/0x160
vlan_vid_add+0x2f6/0x910
register_vlan_dev+0xc5/0x6f0
vlan_newlink+0x40e/0x6f0
rtnl_newlink_create+0x2e1/0x770
__rtnl_newlink+0x20b/0x9d0
rtnl_newlink+0x7f7/0xf90
rtnetlink_rcv_msg+0x811/0xbf0
netlink_rcv_skb+0x148/0x3f0
rtnetlink_rcv+0x19/0x20
netlink_unicast+0x5fc/0xa50
netlink_sendmsg+0x82b/0xd70
Because of the errors this patch introduces and the form of the patch: will not
be applied in batadv.git
We can discuss an actual fix when you can explain us how this problem can
actually be reproduced.
--
Sven Eckelmann <sven@narfation.org>
^ permalink raw reply
* Re: [PATCH] fix: net/batman-adv: batadv_interface_kill_vid: extra batadv_meshif_vlan_put after destroy
From: Sven Eckelmann @ 2026-06-27 7:07 UTC (permalink / raw)
To: WenTao Liang
Cc: marek.lindner, sw, antonio, davem, edumazet, kuba, pabeni, horms,
b.a.t.m.a.n, netdev, linux-kernel, stable
In-Reply-To: <178254092045.4739.1497464106445743950.b4-review@b4>
[-- Attachment #1: Type: text/plain, Size: 1251 bytes --]
On Saturday, 27 June 2026 08:15:20 CEST Sven Eckelmann wrote:
> On Sat, 27 Jun 2026 11:46:36 +0800, WenTao Liang <vulab@iscas.ac.cn> wrote:
>
> Hi,
>
> not-acked
Just noticed that we already have another odd patch from you [1] (and you
never answered after my reply). Could it be that you just try to spread AI/
LLM(?) generated patches in stable@vger.kernel.org and hope that something
sticks?
I see a lot more patch bombs and complains all over the place when searching
the whole lore.kernel.org [2] and only checking the last couple of days.
If this is really the case - please don't do this. We already stress them (and
other maintainers) enough by dumping large amounts of legitimate patches on
them. Sending patches shutgun-style all over the place without any
recognizable QA or oversight might just cause an overload. And when you then
don't even take the time to react to the review of the patches or apply the
requests they had to you (and instead invent new things to annoy them)... At
least I will not spend an hour writing a reply to you anymore but directly
reject your patch.
Regards,
Sven
[1] https://lore.kernel.org/batman/20250401083901.2261-1-vulab@iscas.ac.cn/
[2] https://lore.kernel.org/all/?q=vulab@iscas.ac.cn
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [mellanox/mlx5-next RFC 1/1] net/mlx5: RX, Fix refcount warning on frag page release
From: Dragos Tatulea @ 2026-06-27 7:48 UTC (permalink / raw)
To: Nabil S. Alramli, saeedm, tariqt, mbloch
Cc: nalramli, leon, andrew+netdev, davem, edumazet, kuba, pabeni,
netdev, linux-rdma, linux-kernel
In-Reply-To: <aa190e99-2ebf-4d59-a6c9-755ca181e16d@nalramli.com>
On 26.06.26 20:02, Nabil S. Alramli wrote:
> On 6/26/26 09:12, Dragos Tatulea wrote:
>>
>>
>> [...]
>>> ```
>>> ret = atomic_long_sub_return(nr, pp_ref_count);
>>> WARN_ON(ret < 0);
>>> ```
>>>
>>> The actual stack trace looks like this:
>>>
>>> ```
>>> WARNING: CPU: 37 PID: 447795 at include/net/page_pool/helpers.h:277 mlx5e_page_release_fragmented.isra.0+0x51/0x60 [mlx5_core]
>>> Tainted: [S]=CPU_OUT_OF_SPEC, [O]=OOT_MODULE
>>> Hardware name: *
>>> RIP: 0010:mlx5e_page_release_fragmented.isra.0+0x51/0x60 [mlx5_core]
>>> RSP: 0018:ffffc90019814d98 EFLAGS: 00010293
>>> RAX: 000000000000003f RBX: ffff88c0993d0a10 RCX: ffffea02424592c0
>>> RDX: 0000000000000001 RSI: ffffea02424592c0 RDI: ffff88c090e20000
>>> RBP: 000000000000000a R08: 0000000000001409 R09: 0000000000000006
>>> R10: 0000000000000000 R11: ffff88c095fbc040 R12: 000000000000141f
>>> R13: 0000000000000009 R14: ffff88c090e20000 R15: 0000000000000001
>>> FS: 00007f34149fa6c0(0000) GS:ffff89200fa40000(0000) knlGS:0000000000000000
>>> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>>> CR2: 00007ed0265eb000 CR3: 0000005091cbe000 CR4: 0000000000350ef0
>>> Call Trace:
>>> <IRQ>
>>> mlx5e_free_rx_wqes+0x7b/0xa0 [mlx5_core]
>>> mlx5e_post_rx_wqes+0x1ac/0x5a0 [mlx5_core]
>>> mlx5e_napi_poll+0x5e5/0x6f0 [mlx5_core]
>>> __napi_poll+0x2b/0x1a0
>>> net_rx_action+0x30e/0x370
>>> ? sched_clock+0x9/0x10
>>> ? sched_clock_cpu+0xf/0x170
>>> handle_softirqs+0xe2/0x2a0
>>> common_interrupt+0x85/0xa0
>>> </IRQ>
>>> <TASK>
>>> asm_common_interrupt+0x26/0x40
>>> RIP: 0010:page_counter_uncharge+0x34/0x90
>>> RSP: 0018:ffffc900e728bb00 EFLAGS: 00000213
>>> RAX: ffff88aff4762000 RBX: ffff88aff4762100 RCX: 0000000000000304
>>> RDX: 0000000000000001 RSI: 00000000004e9e1a RDI: ffff88aff4762100
>>> RBP: 0000000000000001 R08: ffff891ea0560048 R09: 00007ffffffff000
>>> R10: 0000000000001000 R11: ffff891ae8061b00 R12: ffffffffffffffff
>>> R13: ffff89107fcfd4c0 R14: ffff891ae8061b00 R15: ffff892002fe1400
>>> uncharge_batch+0x40/0xd0
>>> ```
>>>
>> Can you provide more data on how you reproduced this? This helps to
>> narrow down the bug. Reproduction steps would be ideal.
>>
>
> I don't have clear steps to reproduce it, we just have seen it randomly on
> some servers that were under memory pressure. I will try to look into it more
> and find a way to reliably reproduce it. I agree that would be ideal to find a
> proper fix.
>
What NIC is this?
What MTU is being used?
Is strided rq enabled (ethtool --show-priv-flags).
Is XDP/AF_XDP used? If yes, can you provide more details?
Is HW-GRO on?
Based on those answers we can review the code path and see if there
is a case where the accounting for the fragments is not done correctly
Also, is buf_alloc_err growing during these memory pressure?
>>> The fix is to use an atomic page fragment counter, so it will always match
>>> the number of references held in the page_pool.
>>>
>> This is not the right fix. The mlx5 page frag counter is not atomic
>> on purpose because all changes to it happen only within the NAPI
>> context.
>>
>
> That was a question that I had, is it ever possible for frag_page->frags to be
> incremented / set outside of NAPI context? I tried to answer that by looking
> at code and by tracing it but could not get a clear picture. If it's not
> possible then I agree, this is not the right fix.
>
If that happens it is probably a bug.
Thanks,
Dragos
^ permalink raw reply
* [PATCH ipsec v2] xfrm: reject optional IPTFS templates in outbound policies
From: Antony Antony @ 2026-06-27 8:23 UTC (permalink / raw)
To: Steffen Klassert, Herbert Xu, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Christian Hopps
Cc: Tobias Brunner, netdev, syzbot+0ac4d84afe1066a1f3e9,
Antony Antony
syzbot reported a stack-out-of-bounds read in xfrm_state_find()
which flows from xfrm_tmpl_resolve_one().
Commit 3d776e31c841 ("xfrm: Reject optional tunnel/BEET mode
templates in outbound policies") disallowed optional tunnel and
BEET in outbound policies to prevent this. Later when IPTFS
added, it was not covered by that fix and can still trigger
the out-of-bounds read;
Extend the check to disallow optional IPTFS in outbound policies
as well. IPTFS should be identical to tunnel mode.
IN and FWD policies are not affected: xfrm_tmpl_resolve_one()
is only reachable via the outbound path.
Reproducer, before:
ip link add dummy0 type dummy
ip link set dummy0 up
ip addr add 10.1.1.1/24 dev dummy0
ip xfrm policy add src 10.1.1.1/32 dst 10.1.1.2/32 dir out tmpl
src fc00::dead:1 dst fc00::dead:2 proto esp reqid 1 mode iptfs
level use tmpl src fc00::dead:1 dst fc00::dead:2 proto esp reqid
2 mode transport
ping -W 1 -c 1 10.1.1.2
PING 10.1.1.2 (10.1.1.2) 56(84) bytes of data.
[ 64.168420] ==================================================================
[ 64.169977] BUG: KASAN: stack-out-of-bounds in __xfrm6_addr_hash+0x11e/0x170
[ 64.169977] Read of size 4 at addr ffff88800e1ffd20 by task ping/2844
[ 64.169977] CPU: 2 UID: 0 PID: 2844 Comm: ping Not tainted 7.1.0-rc7-00180-geb23b588430a #98 PREEMPT(full)
[ 64.169977] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 64.169977] Call Trace:
[ 64.169977] <TASK>
[ 64.169977] dump_stack_lvl+0x47/0x70
[ 64.169977] ? __xfrm6_addr_hash+0x11e/0x170
[ 64.169977] print_report+0x152/0x4b0
[ 64.169977] ? ksys_mmap_pgoff+0x6d/0xa0
[ 64.169977] ? entry_SYSCALL_64_after_hwframe+0x76/0x7e
[ 64.169977] ? rcu_read_unlock_sched+0xa/0x20
[ 64.169977] ? __virt_addr_valid+0x21b/0x230
[ 64.169977] ? __xfrm6_addr_hash+0x11e/0x170
[ 64.169977] kasan_report+0xa8/0xd0
[ 64.169977] ? __xfrm6_addr_hash+0x11e/0x170
[ 64.169977] __xfrm6_addr_hash+0x11e/0x170
[ 64.169977] __xfrm_dst_hash+0x24/0xc0
[ 64.169977] xfrm_state_find+0xa2d/0x2f90
[ 64.169977] ? __pfx_xfrm_state_find+0x10/0x10
[ 64.169977] ? __pfx_ftrace_graph_ret_addr+0x10/0x10
[ 64.169977] ? __pfx_ftrace_graph_ret_addr+0x10/0x10
[ 64.169977] xfrm_tmpl_resolve_one+0x210/0x570
[ 64.169977] ? __pfx_xfrm_tmpl_resolve_one+0x10/0x10
[ 64.169977] ? __pfx_stack_trace_consume_entry+0x10/0x10
[ 64.169977] ? kernel_text_address+0x5b/0x80
[ 64.169977] ? __kernel_text_address+0xe/0x30
[ 64.169977] ? unwind_get_return_address+0x5e/0x90
[ 64.169977] ? arch_stack_walk+0x8c/0xe0
[ 64.169977] xfrm_tmpl_resolve+0x130/0x200
[ 64.169977] ? __pfx_xfrm_tmpl_resolve+0x10/0x10
[ 64.169977] ? __pfx_xfrm_policy_inexact_lookup_rcu+0x10/0x10
[ 64.169977] ? __refcount_add_not_zero.constprop.0+0xb2/0x110
[ 64.169977] ? __pfx___refcount_add_not_zero.constprop.0+0x10/0x10
[ 64.169977] xfrm_resolve_and_create_bundle+0xd5/0x310
[ 64.169977] ? __pfx_xfrm_resolve_and_create_bundle+0x10/0x10
[ 64.169977] ? __pfx_xfrm_policy_lookup_bytype+0x10/0x10
[ 64.169977] ? __pfx_xfrm_policy_lookup_bytype+0x10/0x10
[ 64.169977] xfrm_lookup_with_ifid+0x3d8/0xb80
[ 64.169977] ? __pfx_xfrm_lookup_with_ifid+0x10/0x10
[ 64.169977] ? ip_route_output_key_hash+0xc6/0x110
[ 64.169977] ? kasan_save_track+0x10/0x30
[ 64.169977] xfrm_lookup_route+0x18/0xe0
[ 64.169977] ip4_datagram_release_cb+0x4c9/0x530
[ 64.169977] ? __pfx_ip4_datagram_release_cb+0x10/0x10
[ 64.169977] ? do_raw_spin_lock+0x71/0xc0
[ 64.169977] ? __pfx_do_raw_spin_lock+0x10/0x10
[ 64.169977] release_sock+0xb0/0x170
[ 64.169977] udp_connect+0x43/0x50
[ 64.169977] __sys_connect+0xa6/0x100
[ 64.169977] ? alloc_fd+0x2e9/0x300
[ 64.169977] ? __pfx___sys_connect+0x10/0x10
[ 64.169977] ? preempt_latency_start+0x1f/0x70
[ 64.169977] ? fd_install+0x7e/0x150
[ 64.169977] ? rcu_read_unlock_sched+0xa/0x20
[ 64.169977] ? __sys_socket+0xdf/0x130
[ 64.169977] ? __pfx___sys_socket+0x10/0x10
[ 64.169977] ? vma_refcount_put+0x43/0xa0
[ 64.169977] __x64_sys_connect+0x7e/0x90
[ 64.169977] do_syscall_64+0x11b/0x2b0
[ 64.169977] entry_SYSCALL_64_after_hwframe+0x76/0x7e
[ 64.169977] RIP: 0033:0x7f4851ecb570
[ 64.169977] Code: 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 80 3d f9 ca 0d 00 00 74 17 b8 2a 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 48 83 ec 18 89 54
[ 64.169977] RSP: 002b:00007ffc830e3498 EFLAGS: 00000202 ORIG_RAX: 000000000000002a
[ 64.169977] RAX: ffffffffffffffda RBX: 00007ffc830e34d0 RCX: 00007f4851ecb570
[ 64.169977] RDX: 0000000000000010 RSI: 00007ffc830e34d0 RDI: 0000000000000005
[ 64.169977] RBP: 0000000000000000 R08: 0000000000000003 R09: 0000000000000000
[ 64.169977] R10: 0000000000000006 R11: 0000000000000202 R12: 0000000000000005
[ 64.169977] R13: 0000000000000000 R14: 00005619a863f340 R15: 0000000000000000
[ 64.169977] </TASK>
[ 64.169977] The buggy address belongs to stack of task ping/2844
[ 64.169977] and is located at offset 88 in frame:
[ 64.169977] ip4_datagram_release_cb+0x0/0x530
[ 64.169977] This frame has 1 object:
[ 64.169977] [32, 88) 'fl4'
[ 64.169977] The buggy address belongs to the physical page:
[ 64.169977] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0xe1ff
[ 64.169977] flags: 0x4000000000000000(zone=1)
[ 64.169977] raw: 4000000000000000 0000000000000000 ffffea0000387fc8 0000000000000000
[ 64.169977] raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000
[ 64.169977] page dumped because: kasan: bad access detected
[ 64.169977] Memory state around the buggy address:
[ 64.169977] ffff88800e1ffc00: f2 f2 00 00 f3 f3 00 00 00 00 00 00 00 00 00 00
[ 64.169977] ffff88800e1ffc80: 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 00 00
[ 64.169977] >ffff88800e1ffd00: 00 00 00 00 f3 f3 f3 f3 f3 00 00 00 00 00 00 00
[ 64.169977] ^
[ 64.169977] ffff88800e1ffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
[ 64.169977] ffff88800e1ffe00: f1 f1 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 64.169977] ==================================================================
[ 64.245153] Disabling lock debugging due to kernel taint
After the fix:
ip xfrm policy add src 10.1.1.1/32 dst 10.1.1.2/32 dir out tmpl \
src fc00::dead:1 dst fc00::dead:2 proto esp reqid 1 mode iptfs \
level use tmpl src fc00::dead:1 dst fc00::dead:2 proto esp reqid 2 \
mode transport
Error: Mode in optional template not allowed in outbound policy.
Fixes: d1716d5a44c3 ("xfrm: add generic iptfs defines and functionality")
Reported-by: syzbot+0ac4d84afe1066a1f3e9@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/all/6a3ceb94.43b4ff68.30a095.0004.GAE@google.com/T/
Signed-off-by: Antony Antony <antony.antony@secunet.com>
---
v1->v2: Fix Signed-off-by:
Link to v1: https://patch.msgid.link/20260625-xfrm-pol-out-tmpl-iptfs-reject-fix-v1-1-814861129086@secunet.com
---
net/xfrm/xfrm_user.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 6384795ee6b2..0f2c921b1e03 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -2104,13 +2104,12 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family,
switch (ut[i].mode) {
case XFRM_MODE_TUNNEL:
case XFRM_MODE_BEET:
+ case XFRM_MODE_IPTFS:
if (ut[i].optional && dir == XFRM_POLICY_OUT) {
NL_SET_ERR_MSG(extack, "Mode in optional template not allowed in outbound policy");
return -EINVAL;
}
break;
- case XFRM_MODE_IPTFS:
- break;
default:
if (ut[i].family != prev_family) {
NL_SET_ERR_MSG(extack, "Mode in template doesn't support a family change");
---
base-commit: 805185b7c7a1069e407b6f7b3bc98e44d415f484
change-id: 20260625-xfrm-pol-out-tmpl-iptfs-reject-fix-10373324a111
Best regards,
--
Antony
^ permalink raw reply related
* Re: [PATCH net-next v3 0/3] net: pse-pd: decouple controller lookup from MDIO probe
From: Jonas Jelonek @ 2026-06-27 8:45 UTC (permalink / raw)
To: Carlo Szelinsky
Cc: Corey Leavitt, Simon Horman, netdev, linux-kernel, Paolo Abeni,
Jakub Kicinski, Eric Dumazet, David S . Miller, Russell King,
Oleksij Rempel, Andrew Lunn, Heiner Kallweit, Kory Maincent
In-Reply-To: <20260626165929.2908782-1-github@szelinsky.de>
Hi Carlo,
On 26.06.26 18:59, Carlo Szelinsky wrote:
> This is v3 of Corey's series [1]. It takes the PSE controller lookup out
> of the MDIO probe path, so a modular PSE driver no longer makes the
> PHY/DSA probe spin on -EPROBE_DEFER until the PSE module loads.
>
> v2 was four patches. The first one (a regulator handle fix) is a
> self-contained bug fix, so on Jakub's suggestion it is going to net on
> its own [2] and is not part of this series. The three patches here are
> the notifier rework and target net-next. net-next was closed for the
> merge window when v2 was posted; it is open again now, so here they are.
>
> How it works: pse_core gets a notifier chain (REGISTERED / UNREGISTERED).
> The phy layer subscribes, owns phydev->psec, and attaches the PSE handle
> when the controller shows up instead of during probe. fwnode_mdio loses
> its PSE awareness, so no -EPROBE_DEFER leaves it and the probe-retry loop
> is gone.
>
> Tested on a Realtek rtl93xx PoE switch with two HS104 PSE controllers on
> i2c:
>
> - clean boot, no probe-retry loop, no watchdog reset
> - 10G SFP+ port: module hotplug works, no deadlock
> - ethtool --set-pse enable/disable cuts and restores power to a PD
> - i2c unbind -> rmmod -> modprobe: PSE detaches on unbind and re-attaches
> on reload with power restored, no reboot. No lockdep splats.
>
> Tested-by: Carlo Szelinsky <github@szelinsky.de>
>
> Changes in v3:
> - Drop patch 1 (regulator handle fix); it goes to net separately [2].
> - Rebase on current net-next. No code changes to the three patches.
>
> v1 was an RFC by Corey [3].
>
> [1] https://lore.kernel.org/netdev/20260620112440.1734404-1-github@szelinsky.de/
> [2] https://lore.kernel.org/netdev/20260624204017.2752934-1-github@szelinsky.de/
> [3] https://lore.kernel.org/netdev/20260423-pse-notifier-decouple-v1-0-86ed750a9d62@leavitt.info/
>
> Corey Leavitt (3):
> net: pse-pd: add notifier chain for controller lifecycle events
> net: pse-pd: fire lifecycle events on controller register/unregister
> net: phy: own phydev->psec via PSE notifier and remove fwnode_mdio
> hook
>
> drivers/net/mdio/fwnode_mdio.c | 34 -------
> drivers/net/phy/phy_device.c | 168 +++++++++++++++++++++++++++++++--
> drivers/net/phy/sfp.c | 2 +-
> drivers/net/pse-pd/pse_core.c | 54 +++++++++++
> include/linux/phy.h | 2 +
> include/linux/pse-pd/pse.h | 41 ++++++++
> 6 files changed, 258 insertions(+), 43 deletions(-)
>
>
> base-commit: 805185b7c7a1069e407b6f7b3bc98e44d415f484
Thanks a lot for continuing the work!
since you need to do a v4 anyway because net-next is still closed, feel
free to include:
Tested-by: Jonas Jelonek <jelonek.jonas@gmail.com>
The issue I reported before, specifically with RTL8241FC, is fixed now.
No deadlock anymore.
Best,
Jonas
^ permalink raw reply
* [PATCH] dt-bindings: Fix bracket
From: Manuel Ebner @ 2026-06-27 9:19 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Oleksij Rempel, open list:NETWORKING DRIVERS,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
open list, Randy Dunlap
Cc: Manuel Ebner
Add "(Alternate" to "ID)"
Signed-off-by: Manuel Ebner <manuelebner@mailbox.org>
---
Documentation/devicetree/bindings/net/microchip,lan95xx.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/net/microchip,lan95xx.yaml b/Documentation/devicetree/bindings/net/microchip,lan95xx.yaml
index accff93d38f8..62bf982aff2b 100644
--- a/Documentation/devicetree/bindings/net/microchip,lan95xx.yaml
+++ b/Documentation/devicetree/bindings/net/microchip,lan95xx.yaml
@@ -33,7 +33,7 @@ properties:
- usb424,9906 # SMSC9505A USB Ethernet Device (HAL)
- usb424,9907 # SMSC9500 USB Ethernet Device (Alternate ID)
- usb424,9908 # SMSC9500A USB Ethernet Device (Alternate ID)
- - usb424,9909 # SMSC9512/9514 USB Hub & Ethernet Device ID)
+ - usb424,9909 # SMSC9512/9514 USB Hub & Ethernet Device (Alternate ID)
- usb424,9e00 # SMSC9500A USB Ethernet Device
- usb424,9e01 # SMSC9505A USB Ethernet Device
- usb424,9e08 # SMSC LAN89530 USB Ethernet Device
--
2.54.0
^ permalink raw reply related
* [RFC PATCH net 1/2] net/ncsi: defer freeing VLAN filter entries after RCU removal
From: Runyu Xiao @ 2026-06-27 9:22 UTC (permalink / raw)
To: sam, fercerpav
Cc: davem, edumazet, kuba, pabeni, horms, netdev, linux-kernel,
runyu.xiao, jianhao.xu
In-Reply-To: <20260627092214.373480-1-runyu.xiao@seu.edu.cn>
NCSI keeps VLAN filter entries on ndp->vlan_vids and updates the list
with RCU primitives. The configuration workqueue reads the list in
set_one_vid() under rcu_read_lock(), then dereferences vlan->vid while
constructing a Set VLAN Filter command.
ncsi_vlan_rx_kill_vid() removes matching entries with list_del_rcu(),
but it frees the object immediately with kfree(). VLAN add/delete
callbacks are serialized by RTNL, but RTNL does not serialize the NCSI
configuration workqueue reader. A reader can therefore keep a pointer to
a struct vlan_vid across list_del_rcu() and race with the immediate
free.
Give struct vlan_vid an rcu_head and release removed entries with
kfree_rcu(). This keeps the existing list structure and makes the
list_del_rcu() lifetime contract match the real set_one_vid() reader.
This was found by our static analysis tool and then manually reviewed
against the current tree. CONFIG_PROVE_RCU_LIST was used as
target-matched triage evidence; the lifetime change is based on the
matching source-level reader and updater paths rather than on the
dynamic warning alone.
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
---
net/ncsi/internal.h | 1 +
net/ncsi/ncsi-manage.c | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
index adee6dcabdc3..d9f0eadc7a24 100644
--- a/net/ncsi/internal.h
+++ b/net/ncsi/internal.h
@@ -310,6 +310,7 @@ enum {
struct vlan_vid {
struct list_head list;
+ struct rcu_head rcu;
__be16 proto;
u16 vid;
};
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index 446e4e3b9553..5316eadd8ce4 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -1737,7 +1737,7 @@ int ncsi_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
netdev_dbg(dev, "NCSI: vid %u found, removing\n", vid);
list_del_rcu(&vlan->list);
found = true;
- kfree(vlan);
+ kfree_rcu(vlan, rcu);
}
if (!found) {
--
2.34.1
^ permalink raw reply related
* [RFC PATCH net 2/2] net/ncsi: stop device work before freeing channels
From: Runyu Xiao @ 2026-06-27 9:22 UTC (permalink / raw)
To: sam, fercerpav
Cc: davem, edumazet, kuba, pabeni, horms, netdev, linux-kernel,
runyu.xiao, jianhao.xu
In-Reply-To: <20260627092214.373480-1-runyu.xiao@seu.edu.cn>
ncsi_unregister_dev() tears down packages and channels before it
disables the NCSI device work item. Current trees already stop the work
before freeing ndp itself, but a teardown window remains where a running
or already scheduled ncsi_dev_work() can still reach package/channel
readers after ncsi_remove_package() has freed the underlying objects.
One visible path is the configuration flow through ncsi_channel_is_tx(),
which walks package channels and ndp->channel_queue while choosing a
transmit channel. Channel queue entries are struct ncsi_channel objects
owned by the package channel lists, and ncsi_remove_channel() frees
those objects during package removal.
Disable the device work before package/channel teardown. Also clear any
remaining channel_queue links while the channel objects are still alive,
so no stale queue membership is carried into teardown.
This was found by our static analysis tool and then manually reviewed
against the current tree. CONFIG_PROVE_RCU_LIST was used as
target-matched triage evidence; the teardown change is based on the
source-level workqueue and channel lifetime review rather than on the
dynamic warning alone.
This is deliberately limited to the teardown ordering problem. It does
not change the normal package/channel RCU-list update model.
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
---
net/ncsi/ncsi-manage.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index 5316eadd8ce4..289974dff0c1 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -1956,10 +1956,18 @@ void ncsi_unregister_dev(struct ncsi_dev *nd)
{
struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
struct ncsi_package *np, *tmp;
+ struct ncsi_channel *nc, *ntmp;
unsigned long flags;
dev_remove_pack(&ndp->ptype);
+ disable_work_sync(&ndp->work);
+
+ spin_lock_irqsave(&ndp->lock, flags);
+ list_for_each_entry_safe(nc, ntmp, &ndp->channel_queue, link)
+ list_del_init(&nc->link);
+ spin_unlock_irqrestore(&ndp->lock, flags);
+
list_for_each_entry_safe(np, tmp, &ndp->packages, node)
ncsi_remove_package(np);
@@ -1967,7 +1975,6 @@ void ncsi_unregister_dev(struct ncsi_dev *nd)
list_del_rcu(&ndp->node);
spin_unlock_irqrestore(&ncsi_dev_lock, flags);
- disable_work_sync(&ndp->work);
kfree(ndp);
}
--
2.34.1
^ permalink raw reply related
* [RFC PATCH net 0/2] net/ncsi: tighten RCU-list lifetime handling
From: Runyu Xiao @ 2026-06-27 9:22 UTC (permalink / raw)
To: sam, fercerpav
Cc: davem, edumazet, kuba, pabeni, horms, netdev, linux-kernel,
runyu.xiao, jianhao.xu
Hi,
This small RFC series addresses two NCSI RCU-list lifetime issues.
The candidates were found by our static analysis tool and then manually
reviewed against the current tree. CONFIG_PROVE_RCU_LIST was used as
target-matched triage evidence; the RFC patches below are based on the
source-level lifetime review rather than on the dynamic warning alone.
Patch 1 defers freeing VLAN filter entries removed with list_del_rcu().
The NCSI configuration workqueue is a real RCU reader of the same list
in set_one_vid(), so RTNL serialization of VLAN add/delete callbacks is
not enough to protect that reader.
Patch 2 moves the existing NCSI device workqueue shutdown before
package/channel teardown and clears channel_queue while the channel
objects are still alive. Current trees already disable the work item
before freeing ndp itself, but still free channels before
disable_work_sync(). NCSI work can walk the package/channel lists and
channel_queue during that window.
I am sending this as RFC because I have not tested it on NCSI hardware,
and maintainers should confirm whether additional request timer
cancellation or RCU-delayed package/channel release is desirable for the
unregister path.
The patches intentionally do not claim a standalone exploitable UAF. The
evidence is a source-level lifetime risk plus target-matched
CONFIG_PROVE_RCU_LIST warnings for the affected NCSI helpers.
Runyu Xiao (2):
net/ncsi: defer freeing VLAN filter entries after RCU removal
net/ncsi: stop device work before freeing channels
net/ncsi/internal.h | 1 +
net/ncsi/ncsi-manage.c | 11 +++++++++--
2 files changed, 10 insertions(+), 2 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH v7 02/10] rust: module: add `THIS_MODULE` const to `ModuleMetadata` trait
From: Alvin Sun @ 2026-06-27 9:28 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci, Alvin Sun
In-Reply-To: <20260627-fix-fops-owner-v7-0-33cd3990edf0@linux.dev>
Since `const_refs_to_static` has been stable as of the MSRV bump, a
`ThisModule` pointer can now be used in const contexts.
Add a `THIS_MODULE` const to the `ModuleMetadata` trait so that modules
can provide their `ThisModule` pointer in const contexts such as static
`file_operations`.
Add a `this_module()` helper to retrieve the `THIS_MODULE` pointer of a
given module type, and update `__init` to use it instead of the
`THIS_MODULE` static generated by the `module!` macro.
The `static THIS_MODULE` generated by the `module!` macro is retained
for backwards compatibility with existing users and removed in a later
patch once all references have been migrated.
Assisted-by: opencode:glm-5.2
Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
rust/kernel/module.rs | 9 +++++++++
rust/macros/module.rs | 18 +++++++++++++++++-
2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/module.rs b/rust/kernel/module.rs
index be242a82e86d2..d713705984477 100644
--- a/rust/kernel/module.rs
+++ b/rust/kernel/module.rs
@@ -42,6 +42,15 @@ fn init(module: &'static ThisModule) -> impl pin_init::PinInit<Self, crate::erro
pub trait ModuleMetadata {
/// The name of the module as specified in the `module!` macro.
const NAME: &'static crate::str::CStr;
+
+ /// The module's `THIS_MODULE` pointer.
+ const THIS_MODULE: ThisModule;
+}
+
+/// Returns a reference to the `THIS_MODULE` of the given module type.
+#[inline]
+pub const fn this_module<M: ModuleMetadata>() -> &'static ThisModule {
+ &M::THIS_MODULE
}
/// Equivalent to `THIS_MODULE` in the C API.
diff --git a/rust/macros/module.rs b/rust/macros/module.rs
index 06c18e2075083..aa9a618d5d19e 100644
--- a/rust/macros/module.rs
+++ b/rust/macros/module.rs
@@ -519,6 +519,22 @@ pub(crate) fn module(info: ModuleInfo) -> Result<TokenStream> {
impl ::kernel::ModuleMetadata for #type_ {
const NAME: &'static ::kernel::str::CStr = #name_cstr;
+
+ #[cfg(MODULE)]
+ const THIS_MODULE: ::kernel::ThisModule = {
+ extern "C" {
+ static __this_module: ::kernel::types::Opaque<::kernel::bindings::module>;
+ }
+
+ // SAFETY: `__this_module` is constructed by the kernel at load time
+ // and lives until the module is unloaded.
+ unsafe { ::kernel::ThisModule::from_ptr(__this_module.get()) }
+ };
+
+ #[cfg(not(MODULE))]
+ const THIS_MODULE: ::kernel::ThisModule = unsafe {
+ ::kernel::ThisModule::from_ptr(::core::ptr::null_mut())
+ };
}
// Double nested modules, since then nobody can access the public items inside.
@@ -616,7 +632,7 @@ pub extern "C" fn #ident_exit() {
/// This function must only be called once.
unsafe fn __init() -> ::kernel::ffi::c_int {
let initer = <super::super::LocalModule as ::kernel::InPlaceModule>::init(
- &super::super::THIS_MODULE
+ ::kernel::module::this_module::<super::super::LocalModule>()
);
// SAFETY: No data race, since `__MOD` can only be accessed by this module
// and there only `__init` and `__exit` access it. These functions are only
--
2.43.0
^ permalink raw reply related
* [PATCH v7 00/10] Fix missing fops.owner in Rust DRM/misc abstractions
From: Alvin Sun @ 2026-06-27 9:28 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci, Alvin Sun
During tyr debugfs development, a kernel NULL pointer dereference was
encountered after `rmmod tyr` while gnome-shell still held /dev/card1 open:
```
[158827.868132] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
[158827.868918] Mem abort info:
[158827.869177] ESR = 0x0000000086000004
[158827.869519] EC = 0x21: IABT (current EL), IL = 32 bits
[158827.870000] SET = 0, FnV = 0
[158827.870281] EA = 0, S1PTW = 0
[158827.870571] FSC = 0x04: level 0 translation fault
[158827.871043] user pgtable: 4k pages, 48-bit VAs, pgdp=0000000108dec000
[158827.871623] [0000000000000000] pgd=0000000000000000, p4d=0000000000000000
[158827.872242] Internal error: Oops: 0000000086000004 [#1] SMP
[158827.872246] Modules linked in: tyr sunrpc snd_soc_simple_card rk805_pwrkey snd_soc_simple_card_utils rtw88_8822bu display_connector rtw88_usb rtw88_8822b snd_soc_rockchip_i2s_tdm snd_soc_hdmi_codec
rtw88_core]
[158827.872337] CPU: 4 UID: 1000 PID: 11276 Comm: gnome-s:disk$0 Tainted: G N 7.1.0-rc1+ #331 PREEMPT
[158827.880534] Tainted: [N]=TEST
[158827.880535] Hardware name: FriendlyElec NanoPi R6C/NanoPi R6C, BIOS v1.1 04/09/2025
[158827.880538] pstate: 60400009 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[158827.880542] pc : 0x0
[158827.880547] lr : _RNvNtCs257m05FHVbX_3tyr2vm8pt_unmap+0x8c/0x12c [tyr]
[158827.880578] sp : ffff800083c236b0
[158827.880579] x29: ffff800083c236d0 x28: ffff00013f8a0000 x27: 0000000000000000
[158827.880585] x26: 000000000000007c x25: ffff000108e6ed80 x24: 0000000000401000
[158827.880590] x23: 0000000000000000 x22: 0000000040000000 x21: 0000000000001000
[158827.880595] x20: ffff00010f778138 x19: 0000000000400000 x18: 00000000ffffffff
[158827.880600] x17: 000000040044ffff x16: 045000f2b5503510 x15: 0720072007200720
[158827.880606] x14: 0720072007200720 x13: 0000000000401000 x12: 0000000000400000
[158827.880611] x11: ffff800083c239d0 x10: ffff000141e4fd88 x9 : 0000000000000000
[158827.880615] x8 : 0000000000000000 x7 : 0000000000000000 x6 : 0000000000400000
[158827.880620] x5 : ffff00013f8a0000 x4 : 0000000000000000 x3 : 0000000000000001
[158827.880625] x2 : 0000000000001000 x1 : 0000000000400000 x0 : ffff00010f778138
[158827.880630] Call trace:
[158827.880632] 0x0 (P)
[158827.880635] _RNvXs6_NtCs257m05FHVbX_3tyr2vmNtB5_9GpuVmDataNtNtNtCsgmSOfgXi5CZ_6kernel3drm5gpuvm11DriverGpuVm13sm_step_unmap+0x3c/0x120 [tyr]
[158827.891166] _RNvMs4_NtNtNtCsgmSOfgXi5CZ_6kernel3drm5gpuvm6sm_opsINtB7_5GpuVmNtNtCs257m05FHVbX_3tyr2vm9GpuVmDataE13sm_step_unmapB13_+0x18/0x34 [tyr]
[158827.891187] op_unmap_cb+0x78/0xb0
[158827.891196] __drm_gpuvm_sm_unmap+0x18c/0x1b4
[158827.891204] drm_gpuvm_sm_unmap+0x38/0x4c
[158827.891209] _RNvMs5_NtCs257m05FHVbX_3tyr2vmNtB5_2Vm7exec_op+0x1cc/0x254 [tyr]
[158827.894085] _RNvMs5_NtCs257m05FHVbX_3tyr2vmNtB5_2Vm11unmap_range+0x124/0x188 [tyr]
[158827.894105] _RINvNtCs5hGKnPbRUFW_4core3ptr13drop_in_placeNtNtCs257m05FHVbX_3tyr3gem8KernelBoEBK_+0x44/0xd8 [tyr]
[158827.894125] _RINvNtCs5hGKnPbRUFW_4core3ptr13drop_in_placeINtNtNtCsgmSOfgXi5CZ_6kernel5alloc4kvec3VecNtNtCs257m05FHVbX_3tyr2fw7SectionNtNtBL_9allocator7KmallocEEB1r_+0x3c/0x100 [tyr]
[158827.894147] _RINvNtCs5hGKnPbRUFW_4core3ptr13drop_in_placeINtNtNtCsgmSOfgXi5CZ_6kernel4sync3arc3ArcNtNtCs257m05FHVbX_3tyr2fw8FirmwareEEB1p_+0x94/0x190 [tyr]
[158827.894167] _RNvMs4_NtNtCsgmSOfgXi5CZ_6kernel3drm6deviceINtB5_6DeviceNtNtCs257m05FHVbX_3tyr6driver12TyrDrmDriverE7releaseBW_+0x30/0x98 [tyr]
[158827.899550] drm_dev_put.part.0+0x88/0xc0
[158827.899557] drm_minor_release+0x18/0x28
[158827.899562] drm_release+0x144/0x170
[158827.899567] __fput+0xe4/0x30c
[158827.899573] ____fput+0x14/0x20
[158827.899579] task_work_run+0x7c/0xe8
[158827.899586] do_exit+0x2a8/0xac4
[158827.899590] do_group_exit+0x34/0x90
[158827.899594] get_signal+0xaac/0xabc
[158827.899599] arch_do_signal_or_restart+0x90/0x3e8
[158827.899606] exit_to_user_mode_loop+0x140/0x1d0
[158827.899613] el0_svc+0x2f4/0x2f8
[158827.899620] el0t_64_sync_handler+0xa0/0xe4
[158827.899627] el0t_64_sync+0x198/0x19c
[158827.899632] ---[ end trace 0000000000000000 ]---
```
The root cause: `fops.owner` was `NULL` in Rust DRM drivers, so the kernel
never blocked module unloading while file descriptors were open. This leads to
use-after-free when drm_release (or other fops) is called on freed module code.
The series moves `THIS_MODULE` into the `ModuleMetadata` as a const, threads it
through `#[vtable]` to set `fops.owner` in DRM/miscdevice, and updates configfs
and rnull to use `this_module::<LocalModule>()`.
Assisted-by: opencode:glm-5.2
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
Changes in v7:
- Use `crate::LocalModule` in `configfs_attrs!` and silence `clippy::crate_in_macro_def`, per Gary's review.
- Link to v6: https://lore.kernel.org/r/20260624-fix-fops-owner-v6-0-5295e333cb3e@linux.dev
Changes in v6:
- Update MAINTAINERS to cover the new `rust/kernel/module.rs`.
- Link to v5: https://lore.kernel.org/r/20260624-fix-fops-owner-v5-0-aa1cba242f05@linux.dev
Changes in v5:
- Add `#[inline]` to the `this_module()` helper.
- Fix configfs doc comment to reference `crate::LocalModule` instead of
bare `LocalModule`.
- Link to v4: https://lore.kernel.org/r/20260623-fix-fops-owner-v4-0-0daf5f077d5c@linux.dev
Changes in v4:
- Move module-related types into a new `rust/kernel/module.rs`.
- Migrate binder from the `module!`-generated `THIS_MODULE` static to
`this_module::<LocalModule>()`.
- Reorganise the series so that every commit builds independently, and
drop the legacy `THIS_MODULE` static once all users are migrated.
- Link to v3: https://lore.kernel.org/r/20260622-fix-fops-owner-v3-0-49d45cb37032@linux.dev
Changes in v3:
- Renamed vtable associated type `ThisModule` to `OwnerModule`
- Added `this_module()` helper for ergonomic `THIS_MODULE` access
- Refined vtable macro implementation: one-liner detection and single `defined_items` set
- Reordered commits to place doctest fallback before vtable auto-insert
- Link to v2: https://lore.kernel.org/r/20260521-fix-fops-owner-v2-0-fd99079c5a04@linux.dev
Changes in v2:
- Merged old `static THIS_MODULE` and v1's `MODULE_PTR` into a single
`ModuleMetadata::THIS_MODULE` const
- `#[vtable]` macro now auto-inserts `type ThisModule`, removing all per-driver
manual patches from v1
- Added configfs & rnull usage site updates and doctest `LocalModule` fallback
- Link to v1: https://lore.kernel.org/r/20260519-fix-fops-owner-v1-0-2ded9830da14@linux.dev
---
Alvin Sun (10):
rust: module: move module types into `module.rs`
rust: module: add `THIS_MODULE` const to `ModuleMetadata` trait
rust: doctest: add LocalModule fallback for #[vtable] ThisModule
rust: macros: auto-insert OwnerModule in #[vtable]
rust: drm: set fops.owner from driver module pointer
rust: miscdevice: set fops.owner from driver module pointer
rust: configfs: use `LocalModule` for `THIS_MODULE`
rust: binder: use `LocalModule` for `THIS_MODULE`
rust: macros: remove `THIS_MODULE` static from `module!`
rust: module: update MAINTAINERS to cover module.rs
MAINTAINERS | 2 +-
drivers/android/binder/rust_binder_main.rs | 3 +-
drivers/block/rnull/configfs.rs | 6 +--
rust/kernel/auxiliary.rs | 2 +-
rust/kernel/configfs.rs | 9 ++--
rust/kernel/drm/device.rs | 3 +-
rust/kernel/drm/gem/mod.rs | 4 +-
rust/kernel/i2c.rs | 2 +-
rust/kernel/lib.rs | 75 +++-------------------------
rust/kernel/miscdevice.rs | 4 +-
rust/kernel/module.rs | 80 ++++++++++++++++++++++++++++++
rust/kernel/net/phy.rs | 6 ++-
rust/kernel/pci.rs | 2 +-
rust/kernel/platform.rs | 2 +-
rust/kernel/usb.rs | 2 +-
rust/macros/lib.rs | 6 +++
rust/macros/module.rs | 34 ++++++-------
rust/macros/vtable.rs | 41 +++++++++++++--
scripts/rustdoc_test_gen.rs | 16 ++++++
19 files changed, 190 insertions(+), 109 deletions(-)
---
base-commit: b7e5ac83cb16f7ffd11dc23736f84276602100ed
change-id: 20260519-fix-fops-owner-e3a77bb27c6c
prerequisite-change-id: 20260519-miscdev-use-format-9ab7e83b1c11:v3
prerequisite-patch-id: 405b334ff0d48ad350014f05a2321bdbaa025400
prerequisite-patch-id: 604b631c81d5423f4ebb2e12ba2d22e9ce371bfc
prerequisite-patch-id: cb550d94cefe01920e0d3ced2b2bcbecd76f3907
prerequisite-patch-id: 3bc830839742591460cb86d9472c04f4686dc600
prerequisite-patch-id: 571058244bc8c7088638d2e3225713011246c7e9
prerequisite-patch-id: 347c5a3c6dbef9832bfce8419fc23e6e08ba477f
prerequisite-patch-id: 3e202d988b56b88446f7535e90d3f00cf5f15701
Best regards,
--
Alvin Sun <alvin.sun@linux.dev>
^ permalink raw reply
* [PATCH v7 01/10] rust: module: move module types into `module.rs`
From: Alvin Sun @ 2026-06-27 9:28 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci, Alvin Sun
In-Reply-To: <20260627-fix-fops-owner-v7-0-33cd3990edf0@linux.dev>
Move `Module`, `InPlaceModule`, `ModuleMetadata` and `ThisModule` from
`lib.rs` into a new `rust/kernel/module.rs`. Re-export them from `lib.rs`
to avoid tree-wide changes.
Switch six bus driver registrations from `module.0` to the public
`ThisModule::as_ptr()` accessor, since the field is no longer visible
outside the new `module` submodule.
No functional change.
Assisted-by: opencode:glm-5.2
Acked-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
rust/kernel/auxiliary.rs | 2 +-
rust/kernel/i2c.rs | 2 +-
rust/kernel/lib.rs | 75 +++++-------------------------------------------
rust/kernel/module.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++
rust/kernel/net/phy.rs | 6 +++-
rust/kernel/pci.rs | 2 +-
rust/kernel/platform.rs | 2 +-
rust/kernel/usb.rs | 2 +-
8 files changed, 88 insertions(+), 74 deletions(-)
diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
index 93c0db1f66555..4a02f83240be3 100644
--- a/rust/kernel/auxiliary.rs
+++ b/rust/kernel/auxiliary.rs
@@ -63,7 +63,7 @@ unsafe fn register(
// SAFETY: `adrv` is guaranteed to be a valid `DriverType`.
to_result(unsafe {
- bindings::__auxiliary_driver_register(adrv.get(), module.0, name.as_char_ptr())
+ bindings::__auxiliary_driver_register(adrv.get(), module.as_ptr(), name.as_char_ptr())
})
}
diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs
index 7b908f0c5a58d..24eff08f47123 100644
--- a/rust/kernel/i2c.rs
+++ b/rust/kernel/i2c.rs
@@ -142,7 +142,7 @@ unsafe fn register(
}
// SAFETY: `idrv` is guaranteed to be a valid `DriverType`.
- to_result(unsafe { bindings::i2c_register_driver(module.0, idrv.get()) })
+ to_result(unsafe { bindings::i2c_register_driver(module.as_ptr(), idrv.get()) })
}
unsafe fn unregister(idrv: &Opaque<Self::DriverType>) {
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index b72b2fbe046d6..040ae85056509 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -93,6 +93,7 @@
pub mod maple_tree;
pub mod miscdevice;
pub mod mm;
+pub mod module;
pub mod module_param;
#[cfg(CONFIG_NET)]
pub mod net;
@@ -139,79 +140,17 @@
#[doc(hidden)]
pub use bindings;
pub use macros;
+pub use module::{
+ InPlaceModule,
+ Module,
+ ModuleMetadata,
+ ThisModule, //
+};
pub use uapi;
/// Prefix to appear before log messages printed from within the `kernel` crate.
const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
-/// The top level entrypoint to implementing a kernel module.
-///
-/// For any teardown or cleanup operations, your type may implement [`Drop`].
-pub trait Module: Sized + Sync + Send {
- /// Called at module initialization time.
- ///
- /// Use this method to perform whatever setup or registration your module
- /// should do.
- ///
- /// Equivalent to the `module_init` macro in the C API.
- fn init(module: &'static ThisModule) -> error::Result<Self>;
-}
-
-/// A module that is pinned and initialised in-place.
-pub trait InPlaceModule: Sync + Send {
- /// Creates an initialiser for the module.
- ///
- /// It is called when the module is loaded.
- fn init(module: &'static ThisModule) -> impl pin_init::PinInit<Self, error::Error>;
-}
-
-impl<T: Module> InPlaceModule for T {
- fn init(module: &'static ThisModule) -> impl pin_init::PinInit<Self, error::Error> {
- let initer = move |slot: *mut Self| {
- let m = <Self as Module>::init(module)?;
-
- // SAFETY: `slot` is valid for write per the contract with `pin_init_from_closure`.
- unsafe { slot.write(m) };
- Ok(())
- };
-
- // SAFETY: On success, `initer` always fully initialises an instance of `Self`.
- unsafe { pin_init::pin_init_from_closure(initer) }
- }
-}
-
-/// Metadata attached to a [`Module`] or [`InPlaceModule`].
-pub trait ModuleMetadata {
- /// The name of the module as specified in the `module!` macro.
- const NAME: &'static crate::str::CStr;
-}
-
-/// Equivalent to `THIS_MODULE` in the C API.
-///
-/// C header: [`include/linux/init.h`](srctree/include/linux/init.h)
-pub struct ThisModule(*mut bindings::module);
-
-// SAFETY: `THIS_MODULE` may be used from all threads within a module.
-unsafe impl Sync for ThisModule {}
-
-impl ThisModule {
- /// Creates a [`ThisModule`] given the `THIS_MODULE` pointer.
- ///
- /// # Safety
- ///
- /// The pointer must be equal to the right `THIS_MODULE`.
- pub const unsafe fn from_ptr(ptr: *mut bindings::module) -> ThisModule {
- ThisModule(ptr)
- }
-
- /// Access the raw pointer for this module.
- ///
- /// It is up to the user to use it correctly.
- pub const fn as_ptr(&self) -> *mut bindings::module {
- self.0
- }
-}
-
#[cfg(not(testlib))]
#[panic_handler]
fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
diff --git a/rust/kernel/module.rs b/rust/kernel/module.rs
new file mode 100644
index 0000000000000..be242a82e86d2
--- /dev/null
+++ b/rust/kernel/module.rs
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Module-related types and helpers.
+
+/// The entrypoint to implementing a kernel module.
+///
+/// For any teardown or cleanup operations, your type may implement [`Drop`].
+pub trait Module: Sized + Sync + Send {
+ /// Called at module initialization time.
+ ///
+ /// Use this method to perform whatever setup or registration your module
+ /// should do.
+ ///
+ /// Equivalent to the `module_init` macro in the C API.
+ fn init(module: &'static ThisModule) -> crate::error::Result<Self>;
+}
+
+/// A module that is pinned and initialised in-place.
+pub trait InPlaceModule: Sync + Send {
+ /// Creates an initialiser for the module.
+ ///
+ /// It is called when the module is loaded.
+ fn init(module: &'static ThisModule) -> impl pin_init::PinInit<Self, crate::error::Error>;
+}
+
+impl<T: Module> InPlaceModule for T {
+ fn init(module: &'static ThisModule) -> impl pin_init::PinInit<Self, crate::error::Error> {
+ let initer = move |slot: *mut Self| {
+ let m = <Self as Module>::init(module)?;
+
+ // SAFETY: `slot` is valid for write per the contract with `pin_init_from_closure`.
+ unsafe { slot.write(m) };
+ Ok(())
+ };
+
+ // SAFETY: On success, `initer` always fully initialises an instance of `Self`.
+ unsafe { pin_init::pin_init_from_closure(initer) }
+ }
+}
+
+/// Metadata attached to a [`Module`] or [`InPlaceModule`].
+pub trait ModuleMetadata {
+ /// The name of the module as specified in the `module!` macro.
+ const NAME: &'static crate::str::CStr;
+}
+
+/// Equivalent to `THIS_MODULE` in the C API.
+///
+/// C header: [`include/linux/init.h`](srctree/include/linux/init.h)
+pub struct ThisModule(*mut crate::bindings::module);
+
+// SAFETY: `THIS_MODULE` may be used from all threads within a module.
+unsafe impl Sync for ThisModule {}
+
+impl ThisModule {
+ /// Creates a [`ThisModule`] given the `THIS_MODULE` pointer.
+ ///
+ /// # Safety
+ ///
+ /// The pointer must be equal to the right `THIS_MODULE`.
+ pub const unsafe fn from_ptr(ptr: *mut crate::bindings::module) -> ThisModule {
+ ThisModule(ptr)
+ }
+
+ /// Access the raw pointer for this module.
+ ///
+ /// It is up to the user to use it correctly.
+ pub const fn as_ptr(&self) -> *mut crate::bindings::module {
+ self.0
+ }
+}
diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 3ca99db5cccf2..8b7036b8fe480 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -659,7 +659,11 @@ pub fn register(
// the `drivers` slice are initialized properly. `drivers` will not be moved.
// So it's just an FFI call.
to_result(unsafe {
- bindings::phy_drivers_register(drivers[0].0.get(), drivers.len().try_into()?, module.0)
+ bindings::phy_drivers_register(
+ drivers[0].0.get(),
+ drivers.len().try_into()?,
+ module.as_ptr(),
+ )
})?;
// INVARIANT: The `drivers` slice is successfully registered to the kernel via `phy_drivers_register`.
Ok(Registration { drivers })
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index af74ddff6114d..916ed2cb6b70b 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -86,7 +86,7 @@ unsafe fn register(
// SAFETY: `pdrv` is guaranteed to be a valid `DriverType`.
to_result(unsafe {
- bindings::__pci_register_driver(pdrv.get(), module.0, name.as_char_ptr())
+ bindings::__pci_register_driver(pdrv.get(), module.as_ptr(), name.as_char_ptr())
})
}
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index 8917d4ee499fb..9fdbafd53bc21 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -82,7 +82,7 @@ unsafe fn register(
}
// SAFETY: `pdrv` is guaranteed to be a valid `DriverType`.
- to_result(unsafe { bindings::__platform_driver_register(pdrv.get(), module.0) })
+ to_result(unsafe { bindings::__platform_driver_register(pdrv.get(), module.as_ptr()) })
}
unsafe fn unregister(pdrv: &Opaque<Self::DriverType>) {
diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs
index 9c17a672cd275..213db32727c17 100644
--- a/rust/kernel/usb.rs
+++ b/rust/kernel/usb.rs
@@ -63,7 +63,7 @@ unsafe fn register(
// SAFETY: `udrv` is guaranteed to be a valid `DriverType`.
to_result(unsafe {
- bindings::usb_register_driver(udrv.get(), module.0, name.as_char_ptr())
+ bindings::usb_register_driver(udrv.get(), module.as_ptr(), name.as_char_ptr())
})
}
--
2.43.0
^ permalink raw reply related
* [PATCH v7 04/10] rust: macros: auto-insert OwnerModule in #[vtable]
From: Alvin Sun @ 2026-06-27 9:28 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci, Alvin Sun
In-Reply-To: <20260627-fix-fops-owner-v7-0-33cd3990edf0@linux.dev>
Auto-add `type OwnerModule: ::kernel::ModuleMetadata;` as a required
associated type on the trait side if not already defined, and
auto-insert `type OwnerModule = crate::LocalModule;` on the impl side
if not explicitly provided, eliminating the need to manually declare
and implement `OwnerModule` in every vtable trait and impl.
Assisted-by: opencode:glm-5.2
Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Suggested-by: Gary Guo <gary@garyguo.net>
Link: https://lore.kernel.org/all/DIMMWHUOLPSH.13JFRHDKDQJGO@garyguo.net
Reviewed-by: Gary Guo <gary@garyguo.net>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
rust/macros/lib.rs | 6 ++++++
rust/macros/vtable.rs | 41 ++++++++++++++++++++++++++++++++++++-----
2 files changed, 42 insertions(+), 5 deletions(-)
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 2cfd59e0f9e7c..bc7ded353c5ca 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -176,6 +176,12 @@ pub fn module(input: TokenStream) -> TokenStream {
///
/// This macro should not be used when all functions are required.
///
+/// Additionally, this macro automatically handles the `OwnerModule`
+/// associated type: on the trait side, `type OwnerModule: ModuleMetadata;`
+/// is added as a required associated type if not already defined; on the
+/// impl side, `type OwnerModule = LocalModule;` is automatically inserted
+/// if not explicitly defined.
+///
/// # Examples
///
/// ```
diff --git a/rust/macros/vtable.rs b/rust/macros/vtable.rs
index c6510b0c4ea1d..be9a5ed8abe5e 100644
--- a/rust/macros/vtable.rs
+++ b/rust/macros/vtable.rs
@@ -30,6 +30,22 @@ fn handle_trait(mut item: ItemTrait) -> Result<ItemTrait> {
const USE_VTABLE_ATTR: ();
});
+ // Add `type OwnerModule: ModuleMetadata` as a required associated type if
+ // the trait does not already define it.
+ if !item
+ .items
+ .iter()
+ .any(|i| matches!(i, TraitItem::Type(t) if t.ident == "OwnerModule"))
+ {
+ gen_items.push(parse_quote! {
+ /// The module implementing this vtable trait.
+ ///
+ /// Automatically set to `crate::LocalModule` by the `#[vtable]`
+ /// impl macro.
+ type OwnerModule: ::kernel::ModuleMetadata;
+ });
+ }
+
for item in &item.items {
if let TraitItem::Fn(fn_item) = item {
let name = &fn_item.sig.ident;
@@ -57,12 +73,18 @@ fn handle_trait(mut item: ItemTrait) -> Result<ItemTrait> {
fn handle_impl(mut item: ItemImpl) -> Result<ItemImpl> {
let mut gen_items = Vec::new();
- let mut defined_consts = HashSet::new();
+ let mut defined_items = HashSet::new();
- // Iterate over all user-defined constants to gather any possible explicit overrides.
+ // Iterate over all user-defined items to gather any possible explicit overrides.
for item in &item.items {
- if let ImplItem::Const(const_item) = item {
- defined_consts.insert(const_item.ident.clone());
+ match item {
+ ImplItem::Const(const_item) => {
+ defined_items.insert(const_item.ident.clone());
+ }
+ ImplItem::Type(type_item) => {
+ defined_items.insert(type_item.ident.clone());
+ }
+ _ => {}
}
}
@@ -70,6 +92,15 @@ fn handle_impl(mut item: ItemImpl) -> Result<ItemImpl> {
const USE_VTABLE_ATTR: () = ();
});
+ // Auto-insert `type OwnerModule = crate::LocalModule` if not explicitly defined.
+ // `crate::LocalModule` resolves to the real module type (via `module!`) or a
+ // dummy fallback in non-module contexts (e.g., doctests).
+ if !defined_items.contains(&parse_quote!(OwnerModule)) {
+ gen_items.push(parse_quote! {
+ type OwnerModule = crate::LocalModule;
+ });
+ }
+
for item in &item.items {
if let ImplItem::Fn(fn_item) = item {
let name = &fn_item.sig.ident;
@@ -78,7 +109,7 @@ fn handle_impl(mut item: ItemImpl) -> Result<ItemImpl> {
name.span(),
);
// Skip if it's declared already -- this allows user override.
- if defined_consts.contains(&gen_const_name) {
+ if defined_items.contains(&gen_const_name) {
continue;
}
let cfg_attrs = crate::helpers::gather_cfg_attrs(&fn_item.attrs);
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox