* Re: [PATCH 0/7] rust: Use kernel style vertical imports in various drivers
From: Gary Guo @ 2026-07-05 12:08 UTC (permalink / raw)
To: Guru Das Srinagesh, Andrew Lunn
Cc: Miguel Ojeda, rust-for-linux, linux-kernel, Danilo Krummrich,
Abdiel Janulgue, Daniel Almeida, Robin Murphy, Andreas Hindborg,
Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Alice Ryhl, Trevor Gross, Tamir Duberstein, Alexandre Courbot,
Onur Özkan, Drew Fustini, Guo Ren, Fu Wei, Michal Wilczynski,
Uwe Kleine-König, Rafael J. Wysocki, Viresh Kumar,
Jens Axboe, FUJITA Tomonori, Heiner Kallweit, Russell King,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
David Airlie, Simona Vetter, driver-core, linux-riscv, linux-pwm,
linux-pm, linux-block, netdev, nova-gpu, dri-devel
In-Reply-To: <akmnh0AKFfu9-OYn@gurudas.dev>
On Sun Jul 5, 2026 at 1:38 AM BST, Guru Das Srinagesh wrote:
> On Mon, Jun 29, 2026 at 04:06:36PM +0200, Andrew Lunn wrote:
>> On Sun, Jun 28, 2026 at 08:38:14PM -0700, Guru Das Srinagesh wrote:
>> > Came across a recent commit bc58905eb07 ("samples: rust_misc_device: use
>> > vertical import style") and found a few more locations that could
>> > benefit from this cleanup. No functional changes.
>> >
>> > Signed-off-by: Guru Das Srinagesh <linux@gurudas.dev>
>> > ---
>> > Guru Das Srinagesh (7):
>> > samples: rust_dma: use vertical import style
>> > pwm: th1520: use vertical import style
>> > cpufreq: rcpufreq_dt: use vertical import style
>> > block: rnull: use vertical import style
>> > net: phy: ax88796b: use vertical import style
>> > net: phy: qt2025: use vertical import style
>> > drm/nova: use vertical import style
>>
>> You have multiple subsystems here, so you need to split this patch
>> setup, per subsystem, and submit them separately. Maintainers only
>> accept patchsets for their own subsystems.
>>
>> For netdev, please take a read of:
>>
>> https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html
>>
>> You need to get the correct tree, and set the Subject: line correctly.
>>
>> Andrew
>
> Hi Andrew,
>
> Thanks for the feedback.
>
> I was aware of the per-subsystem rule, but reasoned that since these changes are
> purely about Rust import formatting coding style with no functional impact on any
> subsystem, they might go through the rust-for-linux tree with acks from the
> respective subsystem maintainers. The Rust coding style is independent of any
> subsystem-specific guidelines.
Patches should usually be merged via their usual tree, otherwise you're just
creating unnecessary merge conflicts.
There are obiviously exceptions to this for series that need to touch multiple
subsystems and cannot be split, but it is not the case for this sort of small
cleanups.
Best,
Gary
>
> Is that reasoning off-base, or is the right path to split these out per subsystem
> regardless?
^ permalink raw reply
* [PATCH net] tipc: fix NULL deref in tipc_named_node_up() on empty publication list
From: Weiming Shi @ 2026-07-05 11:59 UTC (permalink / raw)
To: Jon Maloy, netdev, tipc-discussion
Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Hoang Huu Le, Xiang Mei, linux-kernel, Weiming Shi
named_distribute() builds the bulk messages for @pls into @list and then
dereferences the tail skb:
hdr = buf_msg(skb_peek_tail(list));
msg_set_last_bulk(hdr);
If @pls is empty no skb is enqueued, skb_peek_tail() returns NULL, and
msg_set_last_bulk() writes through buf_msg(NULL).
tipc_named_node_up() passes &nt->cluster_scope. With a node-id
configuration the TIPC_NODE_STATE name is published by tipc_net_finalize()
from a work item, which sets the node address before publishing the name.
The node accepts links once the address is set, so a link that comes up
before the publish runs named_distribute() on an empty cluster_scope:
KASAN: null-ptr-deref in range [0x00000000000000d8-0x00000000000000df]
RIP: 0010:tipc_named_node_up (net/tipc/name_distr.c:196)
tipc_named_node_up (net/tipc/name_distr.c:196 net/tipc/name_distr.c:221)
tipc_node_write_unlock (net/tipc/node.c:428)
tipc_rcv (net/tipc/node.c:2185)
tipc_udp_recv (net/tipc/udp_media.c:392)
Kernel panic - not syncing: Fatal exception in interrupt
TIPC genl ops use GENL_UNS_ADMIN_PERM, so an unprivileged user can reach
this from a user+net namespace.
Return early from named_distribute() when the list is empty, and skip
tipc_node_xmit() for an empty chain. The empty chain would otherwise hit
tipc_lxc_xmit() -> buf_msg(skb_peek(list)), the same zero-skb case fixed
for tipc_link_xmit() in commit b77413446408 ("tipc: fix NULL deref in
tipc_link_xmit()").
Fixes: cad2929dc432 ("tipc: update a binding service via broadcast")
Reported-by: Xiang Mei <xmei5@asu.edu>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
---
net/tipc/name_distr.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index ba4f4906e13b..c04fea4650a5 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -192,7 +192,10 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,
skb_trim(skb, INT_H_SIZE + (msg_dsz - msg_rem));
__skb_queue_tail(list, skb);
}
- hdr = buf_msg(skb_peek_tail(list));
+ skb = skb_peek_tail(list);
+ if (!skb)
+ return;
+ hdr = buf_msg(skb);
msg_set_last_bulk(hdr);
msg_set_named_seqno(hdr, seqno);
}
@@ -219,7 +222,8 @@ void tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities)
read_lock_bh(&nt->cluster_scope_lock);
named_distribute(net, &head, dnode, &nt->cluster_scope, seqno);
- tipc_node_xmit(net, &head, dnode, 0);
+ if (!skb_queue_empty(&head))
+ tipc_node_xmit(net, &head, dnode, 0);
read_unlock_bh(&nt->cluster_scope_lock);
}
--
2.43.0
^ permalink raw reply related
* Re: [PATCH net 3/3] ipv4: igmp: Fix potential memory leak in igmp_mod_timer()
From: Ido Schimmel @ 2026-07-05 11:58 UTC (permalink / raw)
To: Eric Dumazet
Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
Kuniyuki Iwashima, David Ahern, netdev, eric.dumazet
In-Reply-To: <20260704194346.4065071-4-edumazet@google.com>
On Sat, Jul 04, 2026 at 07:43:46PM +0000, Eric Dumazet wrote:
> When a timer is deleted and not re-armed in igmp_mod_timer(), the code
> currently decrements the reference counter of the multicast list entry
> @im using refcount_dec(&im->refcnt).
>
> However, igmp_mod_timer() can be called from the RCU reader path (e.g., in
> igmp_heard_query() via for_each_pmc_rcu()). If the group im was
> concurrently removed from the list by ip_mc_dec_group(), its reference count
> might have already been decremented to 1.
>
> In this case, timer_delete() succeeds, and refcount_dec() decrements
> the refcount from 1 to 0. Since refcount_dec() does not free the object
> when it hits 0 (unlike ip_ma_put()), the im structure is leaked.
>
> Fix this by using ip_ma_put(im) instead of refcount_dec(&im->refcnt).
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> ---
> net/ipv4/igmp.c | 7 ++++++-
> 1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
> index f5f9763895641bf86bfcf9fd7fd7b06012fa4ece..2170b33ba147ce4990e3ee71ba4868e8696b00cb 100644
> --- a/net/ipv4/igmp.c
> +++ b/net/ipv4/igmp.c
> @@ -266,6 +266,8 @@ static void igmp_ifc_start_timer(struct in_device *in_dev, int delay)
>
> static void igmp_mod_timer(struct ip_mc_list *im, int max_delay)
> {
> + bool put = false;
> +
> spin_lock_bh(&im->lock);
> im->unsolicit_count = 0;
> if (timer_delete(&im->timer)) {
> @@ -275,10 +277,13 @@ static void igmp_mod_timer(struct ip_mc_list *im, int max_delay)
> spin_unlock_bh(&im->lock);
> return;
> }
> - refcount_dec(&im->refcnt);
> + put = true;
> }
> igmp_start_timer(im, max_delay);
> spin_unlock_bh(&im->lock);
> +
> + if (put)
> + ip_ma_put(im);
> }
Don't we also need something similar in igmp_stop_timer() [1]? It can
also be called from an RCU reader (i.e., igmp_rcv() ->
igmp_heard_report() -> igmp_stop_timer()).
[1]
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 8e2b60dcc183..d08331b44519 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -217,13 +217,18 @@ static void ip_sf_list_clear_all(struct ip_sf_list *psf)
static void igmp_stop_timer(struct ip_mc_list *im)
{
+ bool put = false;
+
spin_lock_bh(&im->lock);
if (timer_delete(&im->timer))
- refcount_dec(&im->refcnt);
+ put = true;
WRITE_ONCE(im->tm_running, 0);
WRITE_ONCE(im->reporter, 0);
im->unsolicit_count = 0;
spin_unlock_bh(&im->lock);
+
+ if (put)
+ ip_ma_put(im);
}
/* It must be called with locked im->lock */
^ permalink raw reply related
* [PATCH net] nfc: llcp: bound the remaining LLCP TLV parsers to their buffers
From: Doruk Tan Ozturk @ 2026-07-05 11:56 UTC (permalink / raw)
To: David Heidelberg, oe-linux-nfc
Cc: Simon Horman, David Laight, netdev, linux-kernel, stable,
Doruk Tan Ozturk
Commit 27256cdb290e ("nfc: llcp: bound SNL TLV parsing to the skb and
add length checks") fixed the unbounded TLV walk in
nfc_llcp_recv_snl(), but three sibling parsers that share the exact
same pattern were left unbounded:
- nfc_llcp_parse_gb_tlv()
- nfc_llcp_parse_connection_tlv()
- nfc_llcp_connect_sn()
Each walks a TLV list, reading a two-byte header (type, length)
followed by length bytes of value, without checking that the two
header bytes or the declared length stay within the buffer.
nfc_llcp_connect_sn() then returns a pointer to a service name of up to
255 bytes that may point past the end of the skb; it is subsequently
consumed by memcmp() in nfc_llcp_sock_from_sn().
nfc_llcp_parse_connection_tlv() is worse: it tracks the walk offset in
a u8, so a single crafted TLV with length == 254 advances the offset by
256, which wraps to 0. The loop condition "offset < tlv_array_len" then
never makes progress while the tlv pointer keeps marching forward,
producing an infinite loop with a runaway out-of-bounds read and a
guaranteed oops even without KASAN.
nfc_llcp_parse_connection_tlv() and nfc_llcp_connect_sn() are reachable
from nfc_llcp_recv_connect() and nfc_llcp_recv_cc(), i.e. from received
CONNECT and CC PDUs. A nearby NFC device can reach this without
authentication; LLCP link activation happens automatically after
NFC-DEP, and the nfc_llcp_rx_skb() dispatcher applies no minimum-length
guard.
Walk each TLV list by pointer, bounded by the end of the buffer
(skb_tail_pointer() for connect_sn, tlv_array + tlv_array_len for the
gb and connection parsers), and validate each declared length before
use, matching the approach already used for nfc_llcp_recv_snl().
Dropping the u8 offset also removes the wrap, and for very short
connect frames this avoids the size_t underflow of
"skb->len - LLCP_HEADER_SIZE".
Found by 0sec automated security-research tooling (https://0sec.ai).
Fixes: d646960f7986 ("NFC: Initial LLCP support")
Cc: stable@vger.kernel.org
Assisted-by: 0sec:claude-opus-4-8
Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
---
net/nfc/llcp_commands.c | 18 ++++++++++++------
net/nfc/llcp_core.c | 10 ++++++----
2 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c
index 291f26facbf3..1a0a2f4aca70 100644
--- a/net/nfc/llcp_commands.c
+++ b/net/nfc/llcp_commands.c
@@ -193,17 +193,21 @@ int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
const u8 *tlv_array, u16 tlv_array_len)
{
const u8 *tlv = tlv_array;
- u8 type, length, offset = 0;
+ const u8 *tlv_end = tlv_array + tlv_array_len;
+ u8 type, length;
pr_debug("TLV array length %d\n", tlv_array_len);
if (local == NULL)
return -ENODEV;
- while (offset < tlv_array_len) {
+ while (tlv + 2 < tlv_end) {
type = tlv[0];
length = tlv[1];
+ if (tlv + 2 + length > tlv_end)
+ break;
+
pr_debug("type 0x%x length %d\n", type, length);
switch (type) {
@@ -227,7 +231,6 @@ int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
break;
}
- offset += length + 2;
tlv += length + 2;
}
@@ -243,17 +246,21 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
const u8 *tlv_array, u16 tlv_array_len)
{
const u8 *tlv = tlv_array;
- u8 type, length, offset = 0;
+ const u8 *tlv_end = tlv_array + tlv_array_len;
+ u8 type, length;
pr_debug("TLV array length %d\n", tlv_array_len);
if (sock == NULL)
return -ENOTCONN;
- while (offset < tlv_array_len) {
+ while (tlv + 2 < tlv_end) {
type = tlv[0];
length = tlv[1];
+ if (tlv + 2 + length > tlv_end)
+ break;
+
pr_debug("type 0x%x length %d\n", type, length);
switch (type) {
@@ -270,7 +277,6 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
break;
}
- offset += length + 2;
tlv += length + 2;
}
diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c
index aed5fe1afef0..0de20279e046 100644
--- a/net/nfc/llcp_core.c
+++ b/net/nfc/llcp_core.c
@@ -849,13 +849,16 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local,
static const u8 *nfc_llcp_connect_sn(const struct sk_buff *skb, size_t *sn_len)
{
u8 type, length;
- const u8 *tlv = &skb->data[2];
- size_t tlv_array_len = skb->len - LLCP_HEADER_SIZE, offset = 0;
+ const u8 *tlv = &skb->data[LLCP_HEADER_SIZE];
+ const u8 *tlv_end = skb_tail_pointer(skb);
- while (offset < tlv_array_len) {
+ while (tlv + 2 < tlv_end) {
type = tlv[0];
length = tlv[1];
+ if (tlv + 2 + length > tlv_end)
+ break;
+
pr_debug("type 0x%x length %d\n", type, length);
if (type == LLCP_TLV_SN) {
@@ -863,7 +866,6 @@ static const u8 *nfc_llcp_connect_sn(const struct sk_buff *skb, size_t *sn_len)
return &tlv[2];
}
- offset += length + 2;
tlv += length + 2;
}
--
2.43.0
^ permalink raw reply related
* [PATCH net] macsec: fix promiscuity refcount leak in macsec_dev_open()
From: James Raphael Tiovalen @ 2026-07-05 11:36 UTC (permalink / raw)
To: Sabrina Dubroca, netdev
Cc: James Raphael Tiovalen, stable, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Antoine Tenart,
linux-kernel
When a MACsec interface with IFF_PROMISC set is brought up on top of a
device that has hardware offload enabled, macsec_dev_open() first calls
dev_set_promiscuity(real_dev, 1) and then propagates the open to the
offload device. If that propagation fails, the error path jumps to the
clear_allmulti label, which only reverts allmulti and the unicast
address. The promiscuity taken on the lower device is never dropped, so
real_dev is left permanently stuck in promiscuous mode. Its promiscuity
count can no longer be balanced from software.
Add a clear_promisc label that drops the promiscuity reference and
route the two offload failure paths to it. The dev_set_promiscuity()
failure itself still jumps to clear_allmulti, since on that failure the
count was not incremented.
Fixes: 3cf3227a21d1 ("net: macsec: hardware offloading infrastructure")
Cc: stable@vger.kernel.org
Signed-off-by: James Raphael Tiovalen <jamestiotio@gmail.com>
---
drivers/net/macsec.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index fb009120a924..71e4676b1dd9 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -3615,19 +3615,22 @@ static int macsec_dev_open(struct net_device *dev)
ops = macsec_get_ops(netdev_priv(dev), &ctx);
if (!ops) {
err = -EOPNOTSUPP;
- goto clear_allmulti;
+ goto clear_promisc;
}
ctx.secy = &macsec->secy;
err = macsec_offload(ops->mdo_dev_open, &ctx);
if (err)
- goto clear_allmulti;
+ goto clear_promisc;
}
if (netif_carrier_ok(real_dev))
netif_carrier_on(dev);
return 0;
+clear_promisc:
+ if (dev->flags & IFF_PROMISC)
+ dev_set_promiscuity(real_dev, -1);
clear_allmulti:
if (dev->flags & IFF_ALLMULTI)
dev_set_allmulti(real_dev, -1);
--
2.43.0
^ permalink raw reply related
* Re: [PATCH net 1/3] ipv4: igmp: Fix potential UAF in igmp_gq_start_timer()
From: Ido Schimmel @ 2026-07-05 11:33 UTC (permalink / raw)
To: Eric Dumazet
Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
Kuniyuki Iwashima, David Ahern, netdev, eric.dumazet,
Zero Day Initiative
In-Reply-To: <20260704194346.4065071-2-edumazet@google.com>
On Sat, Jul 04, 2026 at 07:43:44PM +0000, Eric Dumazet wrote:
> A race condition exists between device teardown (inetdev_destroy) and
> incoming IGMP query processing (igmp_rcv), leading to a Use-After-Free
> in the IGMP timer callback.
>
> During device destruction, inetdev_destroy() drops the primary reference
> to in_device, which can drop its refcount to 0. The actual freeing of
> in_device memory is deferred via RCU (using call_rcu()).
>
> Concurrently, igmp_rcv() runs under RCU read lock and obtains the
> in_device pointer. Because the memory is RCU-protected, CPU-0 can safely
> dereference in_device even if its refcount has hit 0.
>
> However, if CPU-0 calls igmp_gq_start_timer() and re-arms the timer, it
> attempts to acquire a reference using in_dev_hold(). This increments the
> refcount from 0 to 1, triggering a "refcount_t: addition on 0" warning.
> Since the in_device memory is still scheduled to be freed after the RCU
> grace period (as the free callback does not check the refcount again),
> the device is freed while the timer is still armed. When the timer
> expires, it accesses the freed memory, causing a kernel panic.
>
> Fix this by using refcount_inc_not_zero() (via a new helper
> in_dev_hold_safe()) to prevent acquiring a reference if the device is
> already being destroyed. If the refcount is 0, we do not arm the timer.
>
> A similar issue in IPv6 MLD is fixed in a subsequent patch.
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Reported-by: Zero Day Initiative <zdi-disclosures@trendmicro.com>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
^ permalink raw reply
* Re: [Intel-wired-lan] [PATCH net] e1000e: fix IRQ leak when request_irq() fails in e1000_request_msix()
From: Ruinskiy, Dima @ 2026-07-05 11:30 UTC (permalink / raw)
To: Jiayuan Chen, netdev@vger.kernel.org
Cc: Nguyen, Anthony L, Kitszel, Przemyslaw, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Jeff Garzik, Bruce Allan, intel-wired-lan@lists.osuosl.org,
linux-kernel@vger.kernel.org
In-Reply-To: <20260626083917.49745-1-jiayuan.chen@linux.dev>
On 26/06/2026 11:39, Jiayuan Chen wrote:
> An internal syzbot instance reported the warning below.
>
> comedi (comedi_parport) lets userspace request_irq() an arbitrary IRQ
> number and can thus grab one of e1000e's MSI-X vectors. When
> e1000_request_msix() then fails partway through, it returned without
> freeing the vectors it had already requested; pci_disable_msix() later
> tears those descriptors down while their irqaction is still attached,
> leaking the /proc/irq entry.
>
> Free the already requested IRQs on the error path.
>
> genirq: Flags mismatch irq 28. 00200000 (eth1-tx-0) vs. 00200000 (comedi_parport)
>
> remove_proc_entry: removing non-empty directory 'irq/27', leaking at least 'eth1-rx-0'
> WARNING: fs/proc/generic.c:742 at remove_proc_entry+0x436/0x560, CPU#3: ip/445
> Modules linked in:
> CPU: 3 UID: 0 PID: 445 Comm: ip Not tainted 7.1.0+ #284 PREEMPT
> RIP: 0010:remove_proc_entry (fs/proc/generic.c:742 (discriminator 4))
> PKRU: 55555554
> Call Trace:
> <TASK>
> unregister_irq_proc (kernel/irq/proc.c:406)
> free_desc (kernel/irq/irqdesc.c:482)
> irq_free_descs (kernel/irq/irqdesc.c:874 kernel/irq/irqdesc.c:865)
> irq_domain_free_irqs (kernel/irq/irqdomain.c:1917)
> msi_domain_free_locked.part.0 (kernel/irq/msi.c:1619 kernel/irq/msi.c:1645)
> msi_domain_free_irqs_all_locked (kernel/irq/msi.c:1632)
> pci_msi_teardown_msi_irqs (drivers/pci/msi/irqdomain.c:28)
> pci_free_msi_irqs (drivers/pci/msi/msi.c:925)
> pci_disable_msix (drivers/pci/msi/api.c:200 drivers/pci/msi/api.c:193)
> e1000_request_irq (drivers/net/ethernet/intel/e1000e/netdev.c:2028)
> e1000e_open (drivers/net/ethernet/intel/e1000e/netdev.c:4681)
> __dev_open (net/core/dev.c:1702)
> netif_change_flags (net/core/dev.c:9806)
> do_setlink.isra.0 (net/core/rtnetlink.c:3207 (discriminator 1))
> rtnetlink_rcv_msg (net/core/rtnetlink.c:7068)
> netlink_rcv_skb (net/netlink/af_netlink.c:2556)
>
> Fixes: 4662e82b2cb4 ("e1000e: add support for new 82574L part")
> Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
> Assisted-by: Claude:claude-opus-4-8
> ---
> drivers/net/ethernet/intel/e1000e/netdev.c | 13 +++++++++----
> 1 file changed, 9 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
> index 808e5cddd6a9..19b9823c5679 100644
> --- a/drivers/net/ethernet/intel/e1000e/netdev.c
> +++ b/drivers/net/ethernet/intel/e1000e/netdev.c
> @@ -2099,7 +2099,7 @@ void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
> static int e1000_request_msix(struct e1000_adapter *adapter)
> {
> struct net_device *netdev = adapter->netdev;
> - int err = 0, vector = 0;
> + int err = 0, vector = 0, i;
>
> if (strlen(netdev->name) < (IFNAMSIZ - 5))
> snprintf(adapter->rx_ring->name,
> @@ -2111,7 +2111,7 @@ static int e1000_request_msix(struct e1000_adapter *adapter)
> e1000_intr_msix_rx, 0, adapter->rx_ring->name,
> netdev);
> if (err)
> - return err;
> + goto err_free;
> adapter->rx_ring->itr_register = adapter->hw.hw_addr +
> E1000_EITR_82574(vector);
> adapter->rx_ring->itr_val = adapter->itr;
> @@ -2127,7 +2127,7 @@ static int e1000_request_msix(struct e1000_adapter *adapter)
> e1000_intr_msix_tx, 0, adapter->tx_ring->name,
> netdev);
> if (err)
> - return err;
> + goto err_free;
> adapter->tx_ring->itr_register = adapter->hw.hw_addr +
> E1000_EITR_82574(vector);
> adapter->tx_ring->itr_val = adapter->itr;
> @@ -2136,11 +2136,16 @@ static int e1000_request_msix(struct e1000_adapter *adapter)
> err = request_irq(adapter->msix_entries[vector].vector,
> e1000_msix_other, 0, netdev->name, netdev);
> if (err)
> - return err;
> + goto err_free;
>
> e1000_configure_msix(adapter);
>
> return 0;
> +
> +err_free:
> + for (i = vector - 1; i >= 0; i--)
> + free_irq(adapter->msix_entries[i].vector, netdev);
> + return err;
> }
>
> /**
Reviewed-by: Dima Ruinskiy <dima.ruinskiy@intel.com>
^ permalink raw reply
* Re: [PATCH net 2/3] ipv6: mcast: Fix potential UAF in MLD delayed work
From: Ido Schimmel @ 2026-07-05 10:53 UTC (permalink / raw)
To: Eric Dumazet
Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
Kuniyuki Iwashima, David Ahern, netdev, eric.dumazet
In-Reply-To: <20260704194346.4065071-3-edumazet@google.com>
On Sat, Jul 04, 2026 at 07:43:45PM +0000, Eric Dumazet wrote:
> A race condition exists between device teardown and incoming MLD query
> processing, leading to a Use-After-Free in the MLD delayed work.
>
> During device destruction, the primary reference to inet6_dev is dropped,
> which can drop its refcount to 0. The actual freeing of inet6_dev memory
> is deferred via RCU.
>
> Concurrently, the packet receive path runs under RCU read lock and obtains
> the inet6_dev pointer. Because the memory is RCU-protected, CPU-0 can
> safely dereference inet6_dev even if its refcount has hit 0.
>
> However, if CPU-0 calls igmp6_event_query() and schedules delayed work, it
> attempts to acquire a reference using in6_dev_hold(). This increments the
> refcount from 0 to 1, triggering a "refcount_t: addition on 0" warning.
> Since the inet6_dev memory is still scheduled to be freed after the RCU
> grace period, the device is freed while the work is still scheduled.
> When the work runs, it accesses the freed memory, causing a kernel panic.
>
> Fix this by using refcount_inc_not_zero() (via a new helper
> in6_dev_hold_safe()) to prevent acquiring a reference if the device is
> already being destroyed. If the refcount is 0, we do not schedule the work.
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Eric, thanks for taking care of this!
> ---
> include/net/addrconf.h | 5 +++++
> net/ipv6/mcast.c | 38 ++++++++++++++++++++++++++++----------
> 2 files changed, 33 insertions(+), 10 deletions(-)
[...]
> @@ -1395,6 +1401,7 @@ static void mld_process_v2(struct inet6_dev *idev, struct mld2_query *mld,
> void igmp6_event_query(struct sk_buff *skb)
> {
> struct inet6_dev *idev = __in6_dev_get(skb->dev);
> + bool put = false;
>
> if (!idev || idev->dead)
> goto out;
> @@ -1402,11 +1409,16 @@ void igmp6_event_query(struct sk_buff *skb)
> spin_lock_bh(&idev->mc_query_lock);
> if (skb_queue_len(&idev->mc_query_queue) < MLD_MAX_SKBS) {
> __skb_queue_tail(&idev->mc_query_queue, skb);
Shouldn't we only enqueue the skb if we managed to take a reference?
Something like [1] (on top of this patch).
If we failed to take a reference, then ipv6_mc_destroy_dev() already ran
and the queue will not be purged, thereby leaking this skb.
> - if (!mod_delayed_work(mld_wq, &idev->mc_query_work, 0))
> - in6_dev_hold(idev);
> + if (in6_dev_hold_safe(idev)) {
> + if (mod_delayed_work(mld_wq, &idev->mc_query_work, 0))
> + put = true;
> + }
> skb = NULL;
> }
> spin_unlock_bh(&idev->mc_query_lock);
> +
> + if (put)
> + in6_dev_put(idev);
> out:
> kfree_skb(skb);
> }
> @@ -1570,6 +1582,7 @@ static void mld_query_work(struct work_struct *work)
> void igmp6_event_report(struct sk_buff *skb)
> {
> struct inet6_dev *idev = __in6_dev_get(skb->dev);
> + bool put = false;
>
> if (!idev || idev->dead)
> goto out;
> @@ -1577,11 +1590,16 @@ void igmp6_event_report(struct sk_buff *skb)
> spin_lock_bh(&idev->mc_report_lock);
> if (skb_queue_len(&idev->mc_report_queue) < MLD_MAX_SKBS) {
> __skb_queue_tail(&idev->mc_report_queue, skb);
Same here
> - if (!mod_delayed_work(mld_wq, &idev->mc_report_work, 0))
> - in6_dev_hold(idev);
> + if (in6_dev_hold_safe(idev)) {
> + if (mod_delayed_work(mld_wq, &idev->mc_report_work, 0))
> + put = true;
> + }
> skb = NULL;
> }
> spin_unlock_bh(&idev->mc_report_lock);
> +
> + if (put)
> + in6_dev_put(idev);
> out:
> kfree_skb(skb);
> }
[1]
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 12d22de6f496..aaba4c2aae23 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1408,12 +1408,11 @@ void igmp6_event_query(struct sk_buff *skb)
goto out;
spin_lock_bh(&idev->mc_query_lock);
- if (skb_queue_len(&idev->mc_query_queue) < MLD_MAX_SKBS) {
+ if (skb_queue_len(&idev->mc_query_queue) < MLD_MAX_SKBS &&
+ in6_dev_hold_safe(idev)) {
__skb_queue_tail(&idev->mc_query_queue, skb);
- if (in6_dev_hold_safe(idev)) {
- if (mod_delayed_work(mld_wq, &idev->mc_query_work, 0))
- put = true;
- }
+ if (mod_delayed_work(mld_wq, &idev->mc_query_work, 0))
+ put = true;
skb = NULL;
}
spin_unlock_bh(&idev->mc_query_lock);
@@ -1589,12 +1588,11 @@ void igmp6_event_report(struct sk_buff *skb)
goto out;
spin_lock_bh(&idev->mc_report_lock);
- if (skb_queue_len(&idev->mc_report_queue) < MLD_MAX_SKBS) {
+ if (skb_queue_len(&idev->mc_report_queue) < MLD_MAX_SKBS &&
+ in6_dev_hold_safe(idev)) {
__skb_queue_tail(&idev->mc_report_queue, skb);
- if (in6_dev_hold_safe(idev)) {
- if (mod_delayed_work(mld_wq, &idev->mc_report_work, 0))
- put = true;
- }
+ if (mod_delayed_work(mld_wq, &idev->mc_report_work, 0))
+ put = true;
skb = NULL;
}
spin_unlock_bh(&idev->mc_report_lock);
^ permalink raw reply related
* Re: [PATCH net-next v14 0/9] tls: Add TLS 1.3 hardware offload support
From: Nils Juenemann @ 2026-07-05 10:44 UTC (permalink / raw)
To: rjethwani
Cc: borisp, davem, edumazet, john.fastabend, kuba, leon, mbloch,
netdev, pabeni, saeedm, sd, tariqt
In-Reply-To: <20260515212715.3151307-1-rjethwani@purestorage.com>
Hi Rishikesh, all,
Another NULL deref we hit while testing v14, on the RX resync path. Looks
pre-existing in mlx5e rather than introduced by v14. TLS 1.3 RX HW-kTLS,
mlx5/ConnectX; seen once in ~3 weeks of load:
BUG: kernel NULL pointer dereference, address: 0000000000000030
RIP: mlx5e_ktls_handle_rx_skb+0x10a [mlx5_core]
Call Trace:
<IRQ>
mlx5e_build_rx_skb
mlx5e_handle_rx_cqe_mpwrq
mlx5e_poll_rx_cq
mlx5e_napi_poll
It faults in the CQE_TLS_OFFLOAD_RESYNC branch, in resync_update_sn():
resync_async = tls_offload_ctx_rx(tls_get_ctx(sk))->resync_async;
The NULL is tls_get_ctx(sk) itself: RAX=0 and the faulting instruction is
the priv_ctx_rx load off struct tls_context. CR2=0x30 matches
offsetof(struct tls_context, priv_ctx_rx), and [sk+0x4f8] is
icsk_ulp_data in the matching vmlinux.
So the socket returned by inet_lookup_established() no longer has a TLS
ULP context. resync_update_sn() reads tls_get_ctx(sk) twice: once in
resync_queue_get_psv() just above, which also dereferences it, and again
here, where it is NULL. This looks like icsk_ulp_data being cleared
between the two reads, i.e. RX resync racing TLS ULP teardown. In any
case, the second read is dereferenced without a NULL check.
I can send the full decoded oops or kdump specifics if that helps
narrow it down.
Thanks,
Nils Juenemann
PS: aside from this RX issue the series has been solid here. TLS 1.3
HW-kTLS TX has been running stably above 100 Gbit/s egress (~99.5% of
eligible TX traffic HW-offloaded) on AMD EPYC (Zen2) from a Go server
using a small in-house kTLS library and sendfile(). On this workload the
main win is not just AES offload, but avoiding ciphertext writes back
into DRAM: our measured DRAM-bytes/egress-bytes amplification drops from
~5.4x to ~2.2x. Thanks for the work on this.
^ permalink raw reply
* [PATCH] atm: solos-pci: validate DMA receive size
From: Pengpeng Hou @ 2026-07-05 8:45 UTC (permalink / raw)
To: Chas Williams, linux-atm-general, netdev, linux-kernel; +Cc: Pengpeng Hou
The DMA receive path reads header->size from the RX buffer and uses it
to extend the skb with skb_put(skb, size + sizeof(*header)). RX DMA skbs
are allocated with RX_DMA_SIZE bytes, but the DMA path did not check
that the device-provided size fits in that buffer. The MMIO path already
has a similar size check against card->buffer_size.
Reject an oversized DMA receive item before skb_put() and drop the
invalid skb, then continue through the normal DMA RX refill path so the
port is not left without a replacement receive buffer.
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -784,6 +784,12 @@
header = (void *)skb->data;
size = le16_to_cpu(header->size);
+ if (size > RX_DMA_SIZE - sizeof(*header)) {
+ dev_warn(&card->dev->dev, "Invalid DMA buffer size\n");
+ dev_kfree_skb_any(skb);
+ goto refill_rx;
+ }
+
skb_put(skb, size + sizeof(*header));
skb_pull(skb, sizeof(*header));
} else {
@@ -865,6 +871,7 @@
break;
}
}
+refill_rx:
/* Allocate RX skbs for any ports which need them */
if (card->using_dma && card->atmdev[port] &&
!card->rx_skb[port]) {
^ permalink raw reply
* [PATCH] net: usb: sr9700: validate receive packet extent
From: Pengpeng Hou @ 2026-07-05 8:37 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Ethan Nelson-Moore, Peter Korsgaard, Simon Horman,
linux-usb, netdev, linux-kernel
Cc: Pengpeng Hou
sr9700_rx_fixup() copies len bytes from skb->data + SR_RX_OVERHEAD when
a URB contains multiple packets. The old check compared len against
skb->len, but the source pointer has already skipped SR_RX_OVERHEAD
bytes.
Validate len against the remaining bytes after SR_RX_OVERHEAD before the
copy and cursor advance.
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
--- a/drivers/net/usb/sr9700.c
+++ b/drivers/net/usb/sr9700.c
@@ -355,7 +355,8 @@
/* ignore the CRC length */
len = (skb->data[1] | (skb->data[2] << 8)) - 4;
- if (len > ETH_FRAME_LEN || len > skb->len || len < 0)
+ if (len > ETH_FRAME_LEN || len < 0 ||
+ len > skb->len - SR_RX_OVERHEAD)
return 0;
/* the last packet of current skb */
^ permalink raw reply
* [PATCH] net: usb: cx82310_eth: bound partial receive continuation
From: Pengpeng Hou @ 2026-07-05 8:36 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Kees Cook, linux-usb, netdev, linux-kernel
Cc: Pengpeng Hou
cx82310_rx_fixup() completes a packet that started in the previous URB
by copying dev->partial_rem bytes from the current skb. It then pulls
the same continuation extent, rounded up to an even byte count. The code
does not first prove that the current skb contains that continuation.
Add a fail-closed bound check before the copy and pull. If the
continuation is shorter than the pending packet state expects, drop that
pending partial packet before returning so later URBs are not consumed as
stale continuation bytes. This keeps the existing cross-URB packet
model, but avoids consuming bytes that are not present in the current
skb.
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
diff --git a/drivers/net/usb/cx82310_eth.c b/drivers/net/usb/cx82310_eth.c
--- a/drivers/net/usb/cx82310_eth.c
+++ b/drivers/net/usb/cx82310_eth.c
@@ -242,7 +242,7 @@
*/
static int cx82310_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
- int len;
+ int len, pull_len;
struct sk_buff *skb2;
struct cx82310_priv *priv = dev->driver_priv;
@@ -251,6 +251,13 @@
* end of that packet at the beginning.
*/
if (dev->partial_rem) {
+ pull_len = (dev->partial_rem + 1) & ~1;
+ if (skb->len < pull_len) {
+ dev->partial_len = 0;
+ dev->partial_rem = 0;
+ return 0;
+ }
+
len = dev->partial_len + dev->partial_rem;
skb2 = alloc_skb(len, GFP_ATOMIC);
if (!skb2)
@@ -261,7 +265,7 @@
memcpy(skb2->data + dev->partial_len, skb->data,
dev->partial_rem);
usbnet_skb_return(dev, skb2);
- skb_pull(skb, (dev->partial_rem + 1) & ~1);
+ skb_pull(skb, pull_len);
dev->partial_rem = 0;
if (skb->len < 2)
return 1;
^ permalink raw reply
* Re: [PATCH net] ipv4: fib: free fib_alias with kfree_rcu() on insert error path
From: Ido Schimmel @ 2026-07-05 8:00 UTC (permalink / raw)
To: Weiming Shi
Cc: netdev, dsahern, edumazet, kuba, pabeni, davem, horms, xmei5,
linux-kernel
In-Reply-To: <20260704171421.1786806-1-bestswngs@gmail.com>
On Sat, Jul 04, 2026 at 10:14:21AM -0700, Weiming Shi wrote:
> fib_table_insert() publishes new_fa into the leaf's fa_list with
> fib_insert_alias() before calling the fib entry notifiers. When a
> notifier fails, the error path removes new_fa with fib_remove_alias()
> (hlist_del_rcu) and frees it right away with kmem_cache_free().
>
> fib_table_lookup() walks that list under rcu_read_lock() only, so a
> concurrent lookup that already reached new_fa keeps reading it after the
> free:
>
> BUG: KASAN: slab-use-after-free in fib_table_lookup (net/ipv4/fib_trie.c:1601)
> Read of size 1 at addr ffff88810676d4eb by task exploit/297
> Call Trace:
> fib_table_lookup (net/ipv4/fib_trie.c:1601)
> ip_route_output_key_hash_rcu (net/ipv4/route.c:2814)
> ip_route_output_key_hash (net/ipv4/route.c:2705)
> __ip4_datagram_connect (net/ipv4/datagram.c:49)
> udp_connect (net/ipv4/udp.c:2144)
> __sys_connect (net/socket.c:2167)
> __x64_sys_connect (net/socket.c:2173)
> do_syscall_64
> entry_SYSCALL_64_after_hwframe
> which belongs to the cache ip_fib_alias of size 56
>
> Triggering the error path needs CAP_NET_ADMIN and a registered fib
> notifier that can reject a route; a netdevsim device whose IPv4 FIB
> resource is exhausted is enough.
>
> Free new_fa with alias_free_mem_rcu(), as fib_table_delete() already
> does for a fib_alias removed from the trie.
>
> Fixes: a6c76c17df02 ("ipv4: Notify route after insertion to the routing table")
> Reported-by: Xiang Mei <xmei5@asu.edu>
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Weiming Shi <bestswngs@gmail.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
^ permalink raw reply
* [PATCH net v4 3/3] net/smc: bound the send length to the send buffer in smc_tx_sendmsg()
From: Bryam Vargas via B4 Relay @ 2026-07-05 7:54 UTC (permalink / raw)
To: Dust Li, David S. Miller, Sidraya Jayagond, Eric Dumazet,
D. Wythe, Jakub Kicinski, Simon Horman, Wenjia Zhang, Paolo Abeni
Cc: Stefan Raspl, Wen Gu, linux-kernel, netdev, Mahanta Jambigi,
Tony Lu, Ursula Braun, linux-s390, linux-rdma
In-Reply-To: <20260705-b4-disp-28a1bbca-v4-0-be089b98acc6@proton.me>
From: Bryam Vargas <hexlabsecurity@proton.me>
On the SMC-D DMB-merge (nocopy) path, smc_cdc_msg_recv_action()
advances conn->sndbuf_space from the peer's wire-controlled consumer
cursor via smc_curs_diff(), which can return more than sndbuf_desc->len;
a forged cursor drives sndbuf_space past the send buffer, and over many
CDC messages overflows the signed counter negative. smc_tx_sendmsg()
reads it as the write space and does a wrap-around copy whose second
chunk is not re-bounded to sndbuf_desc->len, spilling the local
sender's outbound data past the send buffer at a peer-controlled
length: a heap out-of-bounds write. The nearby len > sndbuf_desc->len
test only feeds SMC_STAT_RMB_TX_SIZE_SMALL on the user length; it does
not bound the copy.
Bound the write space to sndbuf_desc->len at the consumer, treating a
negative (sign-overflowed) value as out of range too, so the copy can
never exceed the ring. This enforces the documented
0 <= sndbuf_space <= sndbuf_desc->len invariant where it is race-free
against the CDC tasklet; conforming peers are unaffected.
Fixes: cc0ab806fc52 ("net/smc: adapt cursor update when sndbuf and peer DMB are merged")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
---
net/smc/smc_tx.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/net/smc/smc_tx.c b/net/smc/smc_tx.c
index 3144b4b1fe29..5916f02060fb 100644
--- a/net/smc/smc_tx.c
+++ b/net/smc/smc_tx.c
@@ -233,6 +233,19 @@ int smc_tx_sendmsg(struct smc_sock *smc, struct msghdr *msg, size_t len)
/* initialize variables for 1st iteration of subsequent loop */
/* could be just 1 byte, even after smc_tx_wait above */
writespace = atomic_read(&conn->sndbuf_space);
+ /* sndbuf_space is advanced from the peer's wire-controlled
+ * consumer cursor on the SMC-D DMB-merge path; a forged cursor
+ * can inflate it past the send buffer, or overflow the signed
+ * accumulator to a negative value across many CDC messages
+ * (which a plain "> len" check would miss before the size_t
+ * cast below turns it huge). Bound it to the send buffer in
+ * either case so the wrap-around write cannot run past
+ * sndbuf_desc->len. This enforces the documented
+ * 0 <= sndbuf_space <= sndbuf_desc->len invariant at the
+ * producer, race-free against the CDC tasklet.
+ */
+ if (writespace < 0 || writespace > conn->sndbuf_desc->len)
+ writespace = conn->sndbuf_desc->len;
/* not more than what user space asked for */
copylen = min_t(size_t, send_remaining, writespace);
/* determine start of sndbuf */
--
2.43.0
^ permalink raw reply related
* [PATCH net v4 0/3] net/smc: bound wire-controlled CDC cursors against the local buffers
From: Bryam Vargas via B4 Relay @ 2026-07-05 7:54 UTC (permalink / raw)
To: Dust Li, David S. Miller, Sidraya Jayagond, Eric Dumazet,
D. Wythe, Jakub Kicinski, Simon Horman, Wenjia Zhang, Paolo Abeni
Cc: Stefan Raspl, Wen Gu, linux-kernel, netdev, Mahanta Jambigi,
Tony Lu, Ursula Braun, linux-s390, linux-rdma
A peer's CDC producer/consumer cursors are copied from the wire and used,
without an upper bound against the local buffers, as (a) a raw index into the
RMB on the urgent path, (b) the receive length in smc_rx_recvmsg(), and (c) the
send length in smc_tx_sendmsg() on the SMC-D DMB-merge path. A malicious or
buggy peer can forge a cursor so each runs past the relevant buffer: an
out-of-bounds read of adjacent kernel memory (disclosed to the peer) on the
receive/urgent side, and, on the send side, an out-of-bounds write whose
length the peer controls and whose overflowing bytes are the local sender's
own outbound data.
This series bounds each length where it is consumed. The clamp is synchronous
and race-free against the tasklet that advances the cursor, so it is the minimal
fix for stable. A separate net-next series adds the wire-boundary validation and
connection abort that Dust Li suggested; those do not replace these clamps.
The clamp is not subsumed by validating cursors at the input boundary. A peer
that only increments prod.wrap with count == 0 hits the differing-wrap branch of
smc_curs_diff(), which returns (len - 0) + 0 == len every CDC, so bytes_to_rcv
(and sndbuf_space on the send side) accumulates past the buffer while every
per-cursor bound sees count == 0 and accepts the message. The overflow lives in
the accumulator, not the cursor; only the consumer-side clamp bounds it. And
because a queued abort runs asynchronously (queue_work -> smc_conn_kill) while
smc_rx_recvmsg() reads the accumulator under lock_sock, only the synchronous
clamp closes that window. So the clamp goes to stable; the abort is net-next.
The nearby readable >= rmb_desc->len / len > sndbuf_desc->len tests only feed
statistics counters (SMC_STAT_RMB_RX_FULL / SMC_STAT_RMB_TX_SIZE_SMALL) on an
earlier, separate read; they do not bound the copy.
A/B (in-kernel KASAN replaying the sink arithmetic over a real rmb_desc->len /
sndbuf_desc->len slab; kasan.fault=report kasan_multi_shot, 2026-07-05):
- urgent index (1/3): count = len+1 -> slab-out-of-bounds Read; clamped -> clean
- recv length (2/3): bytes_to_rcv = 5*len via wrap++/count=0 -> OOB Read; clamped -> clean
- send length (3/3): sndbuf_space inflated -> slab-out-of-bounds Write; clamped -> clean
- signed overflow: readable = -1 -> v1 ">len" misses -> OOB; "<0 || >len" -> clean
- concurrent TOCTOU race: a producer-side clamp is racy (OOB in a racing consumer
kthread on another CPU); the consumer-side clamp is race-free (0 hits / 5,000,000 reads).
- every in-bounds / honest-peer arm: clean.
Changes since v3:
- split into this stable-bound clamp series and a separate net-next
validate/abort series, per Dust Li's review;
- tightened the commit messages; noted that the nearby SMC_STAT_* tests are not
bounds; no functional change to the three clamps.
v3: https://lore.kernel.org/all/20260614-b4-disp-edd64be9-v3-0-551fa514257e@proton.me/
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
---
Bryam Vargas (3):
net/smc: bound the wire-controlled producer cursor to the RMB
net/smc: bound the receive length to the RMB in smc_rx_recvmsg()
net/smc: bound the send length to the send buffer in smc_tx_sendmsg()
net/smc/smc_cdc.h | 27 ++++++++++++++++++++++++---
net/smc/smc_rx.c | 12 ++++++++++++
net/smc/smc_tx.c | 13 +++++++++++++
3 files changed, 49 insertions(+), 3 deletions(-)
---
base-commit: d6456743424721a837e1509b912f362caaeecd97
change-id: 20260705-b4-disp-28a1bbca-cc9f53ade448
Best regards,
--
Bryam Vargas <hexlabsecurity@proton.me>
^ permalink raw reply
* [PATCH net v4 1/3] net/smc: bound the wire-controlled producer cursor to the RMB
From: Bryam Vargas via B4 Relay @ 2026-07-05 7:54 UTC (permalink / raw)
To: Dust Li, David S. Miller, Sidraya Jayagond, Eric Dumazet,
D. Wythe, Jakub Kicinski, Simon Horman, Wenjia Zhang, Paolo Abeni
Cc: Stefan Raspl, Wen Gu, linux-kernel, netdev, Mahanta Jambigi,
Tony Lu, Ursula Braun, linux-s390, linux-rdma
In-Reply-To: <20260705-b4-disp-28a1bbca-v4-0-be089b98acc6@proton.me>
From: Bryam Vargas <hexlabsecurity@proton.me>
smcr_cdc_msg_to_host() and smcd_cdc_msg_to_host() import a peer's
producer cursor from the wire into conn->local_rx_ctrl.prod without
bounding it against the receive buffer. The urgent-data path in
smc_cdc_msg_recv_action() then uses that count as a raw index into the
RMB, so a peer that advertises a producer cursor past rmb_desc->len
reads out of bounds of the RMB allocation in the receive tasklet and
can disclose adjacent kernel memory.
Bound the producer cursor count to rmb_desc->len at the wire-to-host
conversion, for both SMC-R and SMC-D. Bound only the producer cursor:
the consumer cursor indexes the peer's RMB and is bounded by
peer_rmbe_size, so clamping it to our rmb_desc->len would under-credit
peer_rmbe_space and stall transmit to a peer with a larger RMB.
Conforming peers are unaffected.
Fixes: de8474eb9d50 ("net/smc: urgent data support")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
---
net/smc/smc_cdc.h | 27 ++++++++++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/net/smc/smc_cdc.h b/net/smc/smc_cdc.h
index 696cc11f2303..ca76ef630356 100644
--- a/net/smc/smc_cdc.h
+++ b/net/smc/smc_cdc.h
@@ -221,7 +221,8 @@ static inline void smc_host_msg_to_cdc(struct smc_cdc_msg *peer,
static inline void smc_cdc_cursor_to_host(union smc_host_cursor *local,
union smc_cdc_cursor *peer,
- struct smc_connection *conn)
+ struct smc_connection *conn,
+ int max_count)
{
union smc_host_cursor temp, old;
union smc_cdc_cursor net;
@@ -235,6 +236,15 @@ static inline void smc_cdc_cursor_to_host(union smc_host_cursor *local,
if ((old.wrap == temp.wrap) &&
(old.count > temp.count))
return;
+ /* The peer producer cursor is wire-controlled and is later used as a
+ * raw index into our RMB by the urgent path; bound its count to the
+ * RMB. max_count == 0 leaves the consumer cursor unbounded here: it
+ * indexes the peer's RMB (bounded by peer_rmbe_size, not our
+ * rmb_desc->len), so clamping it to rmb_desc->len would under-credit
+ * peer_rmbe_space and stall transmit to peers with a larger RMB.
+ */
+ if (max_count && temp.count > max_count)
+ temp.count = max_count;
smc_curs_copy(local, &temp, conn);
}
@@ -246,8 +256,13 @@ static inline void smcr_cdc_msg_to_host(struct smc_host_cdc_msg *local,
local->len = peer->len;
local->seqno = ntohs(peer->seqno);
local->token = ntohl(peer->token);
- smc_cdc_cursor_to_host(&local->prod, &peer->prod, conn);
- smc_cdc_cursor_to_host(&local->cons, &peer->cons, conn);
+ /* bound the wire-controlled producer cursor to our RMB (used as a raw
+ * index by the urgent path); leave the consumer cursor unbounded -- it
+ * indexes the peer's RMB and is bounded by peer_rmbe_size.
+ */
+ smc_cdc_cursor_to_host(&local->prod, &peer->prod, conn,
+ conn->rmb_desc->len);
+ smc_cdc_cursor_to_host(&local->cons, &peer->cons, conn, 0);
local->prod_flags = peer->prod_flags;
local->conn_state_flags = peer->conn_state_flags;
}
@@ -260,6 +275,12 @@ static inline void smcd_cdc_msg_to_host(struct smc_host_cdc_msg *local,
temp.wrap = peer->prod.wrap;
temp.count = peer->prod.count;
+ /* the peer producer cursor is wire-controlled and is used as a raw
+ * index into our RMB by the urgent path; bound it to the RMB. The
+ * consumer cursor below indexes the peer's RMB and is left unbounded.
+ */
+ if (temp.count > conn->rmb_desc->len)
+ temp.count = conn->rmb_desc->len;
smc_curs_copy(&local->prod, &temp, conn);
temp.wrap = peer->cons.wrap;
--
2.43.0
^ permalink raw reply related
* [PATCH net v4 2/3] net/smc: bound the receive length to the RMB in smc_rx_recvmsg()
From: Bryam Vargas via B4 Relay @ 2026-07-05 7:54 UTC (permalink / raw)
To: Dust Li, David S. Miller, Sidraya Jayagond, Eric Dumazet,
D. Wythe, Jakub Kicinski, Simon Horman, Wenjia Zhang, Paolo Abeni
Cc: Stefan Raspl, Wen Gu, linux-kernel, netdev, Mahanta Jambigi,
Tony Lu, Ursula Braun, linux-s390, linux-rdma
In-Reply-To: <20260705-b4-disp-28a1bbca-v4-0-be089b98acc6@proton.me>
From: Bryam Vargas <hexlabsecurity@proton.me>
conn->bytes_to_rcv is accumulated in the receive tasklet from the
peer's wire-controlled producer cursor via smc_curs_diff(), whose
differing-wrap branch can exceed rmb_desc->len; a forged cursor drives
bytes_to_rcv past the RMB, and over many CDC messages overflows the
signed counter negative. smc_rx_recvmsg() reads it as the readable
length and does a wrap-around copy whose second chunk is not re-bounded
to rmb_desc->len, reading past the RMB into adjacent kernel memory and
disclosing it to the peer. The nearby readable >= rmb_desc->len test
only feeds SMC_STAT_RMB_RX_FULL on a separate earlier read; it does not
bound the copy.
Bound the readable length to rmb_desc->len at the consumer, treating a
negative (sign-overflowed) value as out of range too, so the copy can
never exceed the ring. This enforces the documented
0 <= bytes_to_rcv <= rmb_desc->len invariant where it is race-free
against the producer update in the tasklet; conforming peers are
unaffected.
Fixes: 952310ccf2d8 ("smc: receive data from RMBE")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
---
net/smc/smc_rx.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/net/smc/smc_rx.c b/net/smc/smc_rx.c
index c1d9b923938d..f461cf10b085 100644
--- a/net/smc/smc_rx.c
+++ b/net/smc/smc_rx.c
@@ -442,6 +442,18 @@ int smc_rx_recvmsg(struct smc_sock *smc, struct msghdr *msg,
/* initialize variables for 1st iteration of subsequent loop */
/* could be just 1 byte, even after waiting on data above */
readable = smc_rx_data_available(conn, peeked_bytes);
+ /* bytes_to_rcv is accumulated from the peer's wire-controlled
+ * producer cursor; a forged cursor can drive it past the RMB,
+ * or overflow the signed accumulator to a negative value across
+ * many CDC messages (which a plain "> len" check would miss
+ * before the size_t cast below turns it huge). Bound it to the
+ * RMB in either case so the wrap-around copy cannot run past
+ * rmb_desc->len. This enforces the documented
+ * 0 <= bytes_to_rcv <= rmb_desc->len invariant at the consumer,
+ * race-free against the producer update in the receive tasklet.
+ */
+ if (readable < 0 || readable > conn->rmb_desc->len)
+ readable = conn->rmb_desc->len;
splbytes = atomic_read(&conn->splice_pending);
if (!readable || (msg && splbytes)) {
if (splbytes)
--
2.43.0
^ permalink raw reply related
* Re: [PATCH net] net: microchip: vcap: fix races on the shared Super VCAP block
From: patchwork-bot+netdevbpf @ 2026-07-05 7:30 UTC (permalink / raw)
To: =?utf-8?q?Jens_Emil_Schulz_=C3=98stergaard_=3Cjensemil=2Eschulzostergaard=40?=,
=?utf-8?q?microchip=2Ecom=3E?=
Cc: horatiu.vultur, UNGLinuxDriver, andrew+netdev, davem, edumazet,
kuba, pabeni, Steen.Hegelund, daniel.machon, steen.hegelund,
netdev, linux-kernel, linux-arm-kernel
In-Reply-To: <20260630-microchip_fix_vcap_locking-v1-1-f60a4596734d@microchip.com>
Hello:
This patch was applied to netdev/net.git (main)
by Paolo Abeni <pabeni@redhat.com>:
On Tue, 30 Jun 2026 14:20:13 +0200 you wrote:
> The VCAP instances on a chip are not independent, yet they are locked
> independently. On sparx5 and lan969x the IS0 and IS2 instances are
> backed by the same Super VCAP hardware block and share its cache and
> command registers: every access drives the shared VCAP_SUPER_CTRL
> register and moves data through the shared cache registers.
>
> Accessing one instance therefore races with accessing another. The
> per-instance admin->lock cannot prevent this, as each instance takes a
> different lock.
>
> [...]
Here is the summary with links:
- [net] net: microchip: vcap: fix races on the shared Super VCAP block
https://git.kernel.org/netdev/net/c/d7a8d500d7e4
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 2/3] net/sched: Handle TC_ACT_REDIRECT from qdisc filter chains
From: Paolo Abeni @ 2026-07-05 7:26 UTC (permalink / raw)
To: Jamal Hadi Salim, Daniel Borkmann
Cc: Jakub Kicinski, Sebastian Andrzej Siewior, Andrii Nakryiko,
Kumar Kartikeya Dwivedi, bpf, Linux Kernel Network Developers,
Victor Nogueira
In-Reply-To: <CAM0EoMnZPbKG3GCndk2Xp44KxUfPJzSMGXYPDZeoa_-6JZ+Uuw@mail.gmail.com>
Hi,
On 7/1/26 5:35 PM, Jamal Hadi Salim wrote:
> On Tue, Jun 30, 2026 at 11:23 AM Daniel Borkmann <daniel@iogearbox.net> wrote:
>>
>> On 6/30/26 5:16 PM, Jamal Hadi Salim wrote:
>>> On Tue, Jun 30, 2026 at 8:33 AM Daniel Borkmann <daniel@iogearbox.net> wrote:
>>>> From: Jamal Hadi Salim <jhs@mojatatu.com>
>>>>
>>>> When a TC filter attached to a qdisc filter chain returns
>>>> TC_ACT_REDIRECT (ex: via an eBPF program calling bpf_redirect() or an
>>>> act_bpf action), the redirect was silently lost i.e no qdisc classify
>>>> function handled TC_ACT_REDIRECT, so the packet fell through the
>>>> switch and was enqueued normally instead of being redirected.
>>>>
>>>> This has been broken since bpf_redirect() was introduced for TC in
>>>> commit 27b29f63058d ("bpf: add bpf_redirect() helper"). We got lucky
>>>> for a long time because bpf_net_context was a per-CPU variable that
>>>> was always available.
>>>>
>>>> commit 401cb7dae813 ("net: Reference bpf_redirect_info via task_struct
>>>> on PREEMPT_RT.") turned bpf_net_context into a task_struct member that
>>>> is only set up by explicit callers. Without a caller setting it up,
>>>> bpf_redirect() itself crashes with a NULL pointer dereference in
>>>> bpf_net_ctx_get_ri(). However, even with bpf_net_context available,
>>>> TC_ACT_REDIRECT from qdisc filter chains cannot be honored without
>>>> adding skb_do_redirect() calls to every qdisc classify function, which
>>>> would require changes across net/sched/. Isolate it to ebpf core where
>>>> it belongs.
>>>>
>>>> Instead, add a tcf_classify_qdisc() inline helper in pkt_cls.h, as a
>>>> wrapper around tcf_classify() for use by qdisc classify functions and
>>>> tcf_qevent_handle(). When the classify verdict is TC_ACT_REDIRECT,
>>>> the wrapper converts it to TC_ACT_SHOT, dropping the packet rather
>>>> than letting it continue silently. Dropping is preferred over
>>>> letting the packet through because the user immediately sees packet
>>>> loss. Silently passing the packet through would hide the problem and
>>>> leave the user wondering why their redirect is not working.
>>>>
>>>> The clsact fast path, tc_run() continues to call tcf_classify() directly
>>>> and is unaffected: TC_ACT_REDIRECT is returned as-is and handled by
>>>> sch_handle_egress/ingress() calling skb_do_redirect() as before.
>>>>
>>>> Fixes: 27b29f63058d ("bpf: add bpf_redirect() helper")
>>>> Fixes: 401cb7dae813 ("net: Reference bpf_redirect_info via task_struct on PREEMPT_RT.")
>>>> Tested-by: Victor Nogueira <victor@mojatatu.com>
>>>> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
>>>> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
>>>> ---
>>>> include/net/pkt_cls.h | 14 +++++++++++++-
>>>> net/sched/cls_api.c | 4 +---
>>>> net/sched/sch_cake.c | 2 +-
>>>> net/sched/sch_drr.c | 2 +-
>>>> net/sched/sch_dualpi2.c | 2 +-
>>>> net/sched/sch_ets.c | 2 +-
>>>> net/sched/sch_fq_codel.c | 2 +-
>>>> net/sched/sch_fq_pie.c | 2 +-
>>>> net/sched/sch_hfsc.c | 2 +-
>>>> net/sched/sch_htb.c | 2 +-
>>>> net/sched/sch_multiq.c | 2 +-
>>>> net/sched/sch_prio.c | 2 +-
>>>> net/sched/sch_qfq.c | 2 +-
>>>> net/sched/sch_sfb.c | 2 +-
>>>> net/sched/sch_sfq.c | 2 +-
>>>> 15 files changed, 27 insertions(+), 17 deletions(-)
>>>>
>>>> diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
>>>> index 3bd08d7f39c1..5f5cb36439fe 100644
>>>> --- a/include/net/pkt_cls.h
>>>> +++ b/include/net/pkt_cls.h
>>>> @@ -156,8 +156,20 @@ static inline int tcf_classify(struct sk_buff *skb,
>>>> {
>>>> return TC_ACT_UNSPEC;
>>>> }
>>>> -
>>>> #endif
>>>> +static inline int tcf_classify_qdisc(struct sk_buff *skb,
>>>> + const struct tcf_proto *tp,
>>>> + struct tcf_result *res, bool compat_mode)
>>>> +{
>>>> + int ret = tcf_classify(skb, NULL, tp, res, compat_mode);
>>>> +
>>>> + /* TC_ACT_REDIRECT from qdisc filter chains is not supported.
>>>> + * Use BPF via tcx or mirred redirect instead.
>>>> + */
>>>> + if (unlikely(ret == TC_ACT_REDIRECT))
>>>> + ret = TC_ACT_SHOT;
>>>> + return ret;
>>>> +}
>>>
>>> Why did you remove the warning?
>>> A lesser issue is that you introduced a space above #endif
>>
>> I don't think we need to put out an extra warn to spam the log, this
>> can be easily traced either via bpftrace or qdisc stats etc; plus the
>> guidance to eBPF with clsact is also obsolete. Given noone has run
>> into this the last 10y, I don't think it really matters tbh.
>
> It's a bit entitled for you to change someone else's patch to fit your
> philosophy without a mention.
> It's only one message per qdisc. But fine, let's keep it that way.
> Sashiko is hallucinating on TC_ACT_CONSUMED for patch 1. Let's ignore it.
@Jamal: I read the above as if you are ok with the series in the current
form as a whole. Please LMK.
FTR, I have a slight preference towards the extra warn message in case
of misconfiguration, but big deal either way.
/P
^ permalink raw reply
* Re: [PATCH net] llc: fix SAP refcount leak in llc_ui_autobind()
From: patchwork-bot+netdevbpf @ 2026-07-05 7:10 UTC (permalink / raw)
To: Shuangpeng Bai
Cc: netdev, davem, edumazet, kuba, pabeni, horms, linux-kernel,
stable
In-Reply-To: <20260630194856.1036497-1-shuangpeng.kernel@gmail.com>
Hello:
This patch was applied to netdev/net.git (main)
by Paolo Abeni <pabeni@redhat.com>:
On Tue, 30 Jun 2026 15:48:56 -0400 you wrote:
> llc_ui_autobind() opens a SAP after choosing a dynamic LSAP.
> llc_sap_open() returns a reference owned by the caller, and
> llc_sap_add_socket() takes a second reference for the socket's
> membership in the SAP hash tables.
>
> llc_ui_bind() drops the caller's reference after adding the socket,
> but llc_ui_autobind() keeps it. When the socket is closed,
> llc_sap_remove_socket() releases only the socket reference, leaving
> the SAP on llc_sap_list with sk_count == 0.
>
> [...]
Here is the summary with links:
- [net] llc: fix SAP refcount leak in llc_ui_autobind()
https://git.kernel.org/netdev/net/c/660667cd4066
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [BUG] rxrpc/afs: leaked peer during netns teardown
From: Shuangpeng Bai @ 2026-07-05 6:54 UTC (permalink / raw)
To: David Howells, Marc Dionne
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, linux-afs, netdev, linux-kernel
Hi,
I can reproduce an RxRPC leaked-peer warning during network namespace
teardown after adding an AFS cell.
Reproducer:
dmesg -C
unshare -n sh -c '
ip link set lo up 2>/dev/null || true
echo "add reprocell 127.0.0.1" > /proc/fs/afs/cells
cat /proc/net/rxrpc/peers
'
sleep 2
dmesg | grep "Leaked peer"
Observed output:
Proto Local Remote Use SST Maxd LastUse RTT RTO
UDP [::]:7001 127.0.0.1:7003 1 128 1440 37s -1 0
[ 37.969040] rxrpc: Leaked peer 61 {1} 127.0.0.1:7003
Tested on:
commit 9fbbf69eab3417732ec2adf93e42e507351dd80a
Linux 7.1.0-13212-g9fbbf69eab34
CONFIG_NET_NS=y
CONFIG_AF_RXRPC=y
CONFIG_AFS_FS=y
Thanks.
^ permalink raw reply
* Re: [syzbot] [net?] WARNING in rcu_note_context_switch (5)
From: syzbot @ 2026-07-05 6:26 UTC (permalink / raw)
To: davem, edumazet, horms, kuba, linux-kernel, netdev, pabeni,
syzkaller-bugs
In-Reply-To: <694ebdbd.050a0220.35954c.0077.GAE@google.com>
syzbot has found a reproducer for the following issue on:
HEAD commit: b73bc9ca3686 Merge tag 'nf-next-26-07-02' of https://git.k..
git tree: net-next
console output: https://syzkaller.appspot.com/x/log.txt?x=1043ef19580000
kernel config: https://syzkaller.appspot.com/x/.config?x=5c4196ba0e33631d
dashboard link: https://syzkaller.appspot.com/bug?extid=84d4a405ed798b40c96d
compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=11d07719580000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=1443ef19580000
Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/b7f8c662a498/disk-b73bc9ca.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/d3ffbd688a32/vmlinux-b73bc9ca.xz
kernel image: https://storage.googleapis.com/syzbot-assets/235149e2b678/bzImage-b73bc9ca.xz
IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+84d4a405ed798b40c96d@syzkaller.appspotmail.com
------------[ cut here ]------------
Voluntary context switch within RCU read-side critical section!
WARNING: kernel/rcu/tree_plugin.h:332 at rcu_note_context_switch+0xc58/0xef0 kernel/rcu/tree_plugin.h:332, CPU#1: syz.0.17/5817
Modules linked in:
CPU: 1 UID: 0 PID: 5817 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/09/2026
RIP: 0010:rcu_note_context_switch+0xc58/0xef0 kernel/rcu/tree_plugin.h:332
Code: 00 41 c6 45 00 00 48 8b 3d 35 15 ab 0e 48 81 c4 a8 00 00 00 5b 41 5c 41 5d 41 5e 41 5f 5d e9 af 60 ff ff 48 8d 3d c8 d6 ae 0e <67> 48 0f b9 3a e9 6f f4 ff ff 90 0f 0b 90 45 84 e4 0f 84 3e f4 ff
RSP: 0018:ffffc90002eced20 EFLAGS: 00010002
RAX: 0000000000000000 RBX: ffff888030d80000 RCX: 0000000080000002
RDX: 0000000000000000 RSI: ffffffff8c4bd260 RDI: ffffffff905ad640
RBP: dffffc0000000000 R08: ffffffff905767f7 R09: 1ffffffff20aecfe
R10: dffffc0000000000 R11: fffffbfff20aecff R12: 0000000000000000
R13: dffffc0000000000 R14: ffff8880b873c180 R15: ffff888030d804c4
FS: 000055557f679500(0000) GS:ffff888125060000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007ff0e1073780 CR3: 0000000022684000 CR4: 00000000003526f0
Call Trace:
<TASK>
__schedule+0x2e9/0x56c0 kernel/sched/core.c:7088
__schedule_loop kernel/sched/core.c:7311 [inline]
schedule+0x164/0x2b0 kernel/sched/core.c:7326
netlink_broadcast_filtered+0xe53/0xea0 net/netlink/af_netlink.c:1553
nlmsg_multicast_filtered include/net/netlink.h:1165 [inline]
nlmsg_multicast include/net/netlink.h:1184 [inline]
nlmsg_notify+0xe3/0x1a0 net/netlink/af_netlink.c:2599
__ip6_del_rt_siblings+0x5ed/0x7d0 net/ipv6/route.c:4080
ip6_route_del+0x104f/0x1100 net/ipv6/route.c:4220
inet6_rtm_delroute+0x5d7/0x6d0 net/ipv6/route.c:5657
rtnetlink_rcv_msg+0x802/0xc00 net/core/rtnetlink.c:7076
netlink_rcv_skb+0x226/0x4a0 net/netlink/af_netlink.c:2556
netlink_unicast_kernel net/netlink/af_netlink.c:1319 [inline]
netlink_unicast+0x7bb/0x940 net/netlink/af_netlink.c:1345
netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1900
sock_sendmsg_nosec+0x13a/0x180 net/socket.c:775
__sock_sendmsg net/socket.c:790 [inline]
____sys_sendmsg+0x54e/0x850 net/socket.c:2684
___sys_sendmsg+0x2a5/0x360 net/socket.c:2738
__sys_sendmsg net/socket.c:2770 [inline]
__do_sys_sendmsg net/socket.c:2775 [inline]
__se_sys_sendmsg net/socket.c:2773 [inline]
__x64_sys_sendmsg+0x1b1/0x290 net/socket.c:2773
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7ff0e119de59
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ffd842e7d98 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
RAX: ffffffffffffffda RBX: 00007ff0e1425fa0 RCX: 00007ff0e119de59
RDX: 0000000000000000 RSI: 0000200000000280 RDI: 0000000000000004
RBP: 00007ff0e1233e6f R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007ff0e1425fac R14: 00007ff0e1425fa0 R15: 00007ff0e1425fa0
</TASK>
----------------
Code disassembly (best guess):
0: 00 41 c6 add %al,-0x3a(%rcx)
3: 45 00 00 add %r8b,(%r8)
6: 48 8b 3d 35 15 ab 0e mov 0xeab1535(%rip),%rdi # 0xeab1542
d: 48 81 c4 a8 00 00 00 add $0xa8,%rsp
14: 5b pop %rbx
15: 41 5c pop %r12
17: 41 5d pop %r13
19: 41 5e pop %r14
1b: 41 5f pop %r15
1d: 5d pop %rbp
1e: e9 af 60 ff ff jmp 0xffff60d2
23: 48 8d 3d c8 d6 ae 0e lea 0xeaed6c8(%rip),%rdi # 0xeaed6f2
* 2a: 67 48 0f b9 3a ud1 (%edx),%rdi <-- trapping instruction
2f: e9 6f f4 ff ff jmp 0xfffff4a3
34: 90 nop
35: 0f 0b ud2
37: 90 nop
38: 45 84 e4 test %r12b,%r12b
3b: 0f .byte 0xf
3c: 84 3e test %bh,(%rsi)
3e: f4 hlt
3f: ff .byte 0xff
---
If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.
^ permalink raw reply
* [PATCH] octeon_ep_vf: Fix RX page leak on napi_build_skb() failure
From: Guangshuo Li @ 2026-07-05 3:16 UTC (permalink / raw)
To: Veerasenareddy Burru, Sathesh Edara, Shinas Rasheed,
Satananda Burla, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, David Carlier, netdev, linux-kernel
Cc: Guangshuo Li
__octep_vf_oq_process_rx() clears buff_info->page before building an skb
from the RX page. On the success path the page is consumed by the skb,
either as the skb head or as an RX fragment.
If napi_build_skb() fails, however, the page is not consumed by an skb.
The error path advances the descriptor and leaves the ring slot cleared,
so the page is no longer tracked and is leaked. In the multi-fragment
case, the remaining fragment pages are also unmapped and removed from
their ring slots without being released.
Release the head page when napi_build_skb() fails, and release each
remaining fragment page before clearing its ring slot.
Fixes: dd66b4285470 ("octeon_ep_vf: add NULL check for napi_build_skb()")
Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
---
drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c
index d98247408242..302559b16be7 100644
--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c
+++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c
@@ -418,6 +418,7 @@ static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
skb = napi_build_skb((void *)resp_hw, PAGE_SIZE);
if (!skb) {
oq->stats->alloc_failures++;
+ put_page(virt_to_page(resp_hw));
desc_used++;
read_idx = octep_vf_oq_next_idx(oq, read_idx);
continue;
@@ -434,6 +435,7 @@ static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
skb = napi_build_skb((void *)resp_hw, PAGE_SIZE);
if (!skb) {
oq->stats->alloc_failures++;
+ put_page(virt_to_page(resp_hw));
desc_used++;
read_idx = octep_vf_oq_next_idx(oq, read_idx);
data_len = buff_info->len - oq->max_single_buffer_size;
@@ -442,6 +444,7 @@ static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
PAGE_SIZE, DMA_FROM_DEVICE);
buff_info = (struct octep_vf_rx_buffer *)
&oq->buff_info[read_idx];
+ put_page(buff_info->page);
buff_info->page = NULL;
if (data_len < oq->buffer_size)
data_len = 0;
--
2.43.0
^ permalink raw reply related
* Re: [PATCH net v2] ppp: defer channel free to an RCU grace period to fix pppol2tp RX UAF
From: Qingfang Deng @ 2026-07-05 2:57 UTC (permalink / raw)
To: Breno Leitao
Cc: Norbert Szetei, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Sebastian Andrzej Siewior, Taegu Ha,
Kees Cook, linux-ppp, linux-kernel, Guillaume Nault, netdev
In-Reply-To: <akfjpBVML_1RFF91@gmail.com>
On 7/4/2026 at 12:32 AM, Breno Leitao wrote:
> On Fri, Jul 03, 2026 at 03:27:00PM +0800, Qingfang Deng wrote:
>> AI-review found an issue: https://sashiko.dev/#/patchset/D9C0245B-608B-4884-8A09-F55BA4A9F948%40doyensec.com
>>
>> An rcu_barrier() call is needed at the end of ppp_cleanup().
>
> I was initially unclear why rcu_barrier() would be necessary on a kfree path,
> but it appears to be required during module unload to ensure that
> ppp_release_channel_free() completes before the module's struct rcu_head is
> destroyed. Is that the correct understanding?
It's required to ensure that all ppp_release_channel_free() callback
complete before the text segment of the module is unloaded.
^ permalink raw reply
* [PATCH net-next v5 2/2] selftests: net: add FOU multicast encapsulation resubmit test
From: Anton Danilov @ 2026-07-05 2:36 UTC (permalink / raw)
To: netdev
Cc: Willem de Bruijn, David S . Miller, David Ahern, Eric Dumazet,
Kuniyuki Iwashima, Jakub Kicinski, Paolo Abeni, Simon Horman,
Shuah Khan, linux-kselftest
In-Reply-To: <cover.1783218197.git.littlesmilingcloud@gmail.com>
Add a selftest to verify that FOU-encapsulated packets addressed to a
multicast destination are correctly resubmitted to the inner protocol
handler (GRE) via the UDP multicast delivery path. Both IPv4 and IPv6
paths are tested.
The test creates two network namespaces connected by a veth pair with
a FOU/GRETAP (IPv4) and FOU/ip6gretap (IPv6) tunnel using multicast
remote addresses (239.0.0.1 and ff0e::1). Ping is sent through each
tunnel and received packets are counted on the receiver's tunnel
interface.
The veth pair is created directly inside the namespaces to avoid
possible name collisions with devices in the root namespace.
Static neighbor entries are configured on the sender because ARP/ND
replies from the receiver cannot traverse the unidirectional multicast
tunnel back to the sender.
The early demux optimization (net.ipv4.ip_early_demux, which controls
both IPv4 and IPv6) is disabled on the receiver to force packets
through __udp4_lib_mcast_deliver() / __udp6_lib_mcast_deliver(), which
is the code path being tested.
Signed-off-by: Anton Danilov <littlesmilingcloud@gmail.com>
Assisted-by: Claude:claude-opus-4-6
---
tools/testing/selftests/net/Makefile | 1 +
.../testing/selftests/net/fou_mcast_encap.sh | 177 ++++++++++++++++++
2 files changed, 178 insertions(+)
create mode 100755 tools/testing/selftests/net/fou_mcast_encap.sh
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 708d960ae07d..7e9ae937cffa 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -39,6 +39,7 @@ TEST_PROGS := \
fib_rule_tests.sh \
fib_tests.sh \
fin_ack_lat.sh \
+ fou_mcast_encap.sh \
fq_band_pktlimit.sh \
gre_gso.sh \
gre_ipv6_lladdr.sh \
diff --git a/tools/testing/selftests/net/fou_mcast_encap.sh b/tools/testing/selftests/net/fou_mcast_encap.sh
new file mode 100755
index 000000000000..728513d55db4
--- /dev/null
+++ b/tools/testing/selftests/net/fou_mcast_encap.sh
@@ -0,0 +1,177 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Test that UDP encapsulation (FOU) correctly handles packet resubmit
+# when packets are delivered via the multicast UDP delivery path.
+#
+# When a FOU-encapsulated packet arrives with a multicast destination IP,
+# __udp4_lib_mcast_deliver() / __udp6_lib_mcast_deliver() must resubmit
+# it to the inner protocol handler (e.g., GRE) rather than consuming it.
+# This test verifies both IPv4 and IPv6 paths by creating a FOU/GRETAP
+# tunnel with a multicast remote address and sending ping through it.
+#
+# The early demux optimization can mask this issue by routing packets via
+# the unicast path (udp[6]_unicast_rcv_skb), so we disable it to force
+# packets through the multicast delivery function.
+
+source lib.sh
+
+NSENDER=""
+NRECV=""
+
+FOU_PORT4=4797
+FOU_PORT6=4798
+MCAST4=239.0.0.1
+MCAST6=ff0e::1
+
+TUN4_S=192.168.99.1
+TUN4_R=192.168.99.2
+TUN6_S=2001:db8:99::1
+TUN6_R=2001:db8:99::2
+
+cleanup() {
+ cleanup_all_ns
+}
+
+trap cleanup EXIT
+
+setup_common() {
+ setup_ns NSENDER NRECV
+
+ # Create veth pair directly inside namespaces to avoid name
+ # collisions with devices in the root namespace.
+ ip link add veth_s netns "$NSENDER" type veth \
+ peer name veth_r netns "$NRECV"
+
+ ip -n "$NSENDER" link set veth_s up
+ ip -n "$NRECV" link set veth_r up
+
+ # Same sysctl controls early demux for both IPv4 and IPv6.
+ ip netns exec "$NRECV" sysctl -wq net.ipv4.ip_early_demux=0
+}
+
+setup_ipv4() {
+ ip -n "$NSENDER" addr add 10.0.0.1/24 dev veth_s
+ ip -n "$NRECV" addr add 10.0.0.2/24 dev veth_r
+
+ # Join multicast group on receiver
+ ip -n "$NRECV" addr add "$MCAST4/32" dev veth_r autojoin
+
+ ip -n "$NSENDER" route add 239.0.0.0/8 dev veth_s
+ ip -n "$NRECV" route add 239.0.0.0/8 dev veth_r
+
+ # Sender: GRETAP with FOU encap (no FOU listener needed on TX side)
+ ip -n "$NSENDER" link add eoudp4 type gretap \
+ remote "$MCAST4" local 10.0.0.1 \
+ encap fou encap-sport "$FOU_PORT4" encap-dport "$FOU_PORT4" \
+ key "$MCAST4"
+ ip -n "$NSENDER" link set eoudp4 up
+ ip -n "$NSENDER" addr add "$TUN4_S/24" dev eoudp4
+
+ # Receiver: FOU listener + GRETAP
+ ip netns exec "$NRECV" ip fou add port "$FOU_PORT4" ipproto 47
+ ip -n "$NRECV" link add eoudp4 type gretap \
+ remote "$MCAST4" local 10.0.0.2 \
+ encap fou encap-sport "$FOU_PORT4" encap-dport "$FOU_PORT4" \
+ key "$MCAST4"
+ ip -n "$NRECV" link set eoudp4 up
+ ip -n "$NRECV" addr add "$TUN4_R/24" dev eoudp4
+
+ # Static neigh on sender: ARP replies cannot traverse the
+ # unidirectional multicast tunnel.
+ local recv_mac
+ recv_mac=$(ip -n "$NRECV" link show eoudp4 | awk '/ether/{print $2}')
+ ip -n "$NSENDER" neigh add "$TUN4_R" lladdr "$recv_mac" dev eoudp4
+}
+
+setup_ipv6() {
+ # Skip cleanly if IPv6 is not available in the running kernel.
+ [ -e /proc/sys/net/ipv6 ] || return "$ksft_skip"
+ modprobe -q fou6 || return "$ksft_skip"
+
+ ip -n "$NSENDER" addr add 2001:db8::1/64 dev veth_s nodad
+ ip -n "$NRECV" addr add 2001:db8::2/64 dev veth_r nodad
+
+ # Join multicast group on receiver
+ ip -n "$NRECV" addr add "$MCAST6/128" dev veth_r autojoin
+
+ ip -n "$NSENDER" -6 route add ff00::/8 dev veth_s
+ ip -n "$NRECV" -6 route add ff00::/8 dev veth_r
+
+ # Sender: ip6gretap with FOU encap
+ ip -n "$NSENDER" link add eoudp6 type ip6gretap \
+ remote "$MCAST6" local 2001:db8::1 \
+ encap fou encap-sport "$FOU_PORT6" encap-dport "$FOU_PORT6" \
+ key 42
+ ip -n "$NSENDER" link set eoudp6 up
+ ip -n "$NSENDER" addr add "$TUN6_S/64" dev eoudp6 nodad
+
+ # Receiver: FOU listener (IPv6) + ip6gretap
+ ip netns exec "$NRECV" ip fou add port "$FOU_PORT6" ipproto 47 -6
+ ip -n "$NRECV" link add eoudp6 type ip6gretap \
+ remote "$MCAST6" local 2001:db8::2 \
+ encap fou encap-sport "$FOU_PORT6" encap-dport "$FOU_PORT6" \
+ key 42
+ ip -n "$NRECV" link set eoudp6 up
+ ip -n "$NRECV" addr add "$TUN6_R/64" dev eoudp6 nodad
+
+ # Static neigh on sender: neighbor discovery cannot traverse the
+ # unidirectional multicast tunnel.
+ local recv_mac
+ recv_mac=$(ip -n "$NRECV" link show eoudp6 | awk '/ether/{print $2}')
+ ip -n "$NSENDER" neigh add "$TUN6_R" lladdr "$recv_mac" dev eoudp6
+}
+
+get_rx_packets() {
+ local dev="$1"
+
+ ip -n "$NRECV" -s link show "$dev" | awk '/RX:/{getline; print $2}'
+}
+
+run_ping_test() {
+ local family="$1"
+ local dev="$2"
+ local dst="$3"
+ local count=100
+ local rx_before rx_after rx_delta
+
+ # Warmup: let any initial broadcast/ND traffic settle
+ ip netns exec "$NSENDER" ping "$family" -c 1 -W 1 "$dst" \
+ >/dev/null 2>&1
+ sleep 1
+
+ rx_before=$(get_rx_packets "$dev")
+ ip netns exec "$NSENDER" ping "$family" -c $count -W 1 "$dst" \
+ >/dev/null 2>&1
+ sleep 1
+ rx_after=$(get_rx_packets "$dev")
+
+ rx_delta=$((rx_after - rx_before))
+
+ if [ "$rx_delta" -ge "$count" ]; then
+ echo "PASS: received $rx_delta/$count packets"
+ return "$ksft_pass"
+ elif [ "$rx_delta" -gt 0 ]; then
+ echo "FAIL: only $rx_delta/$count packets received"
+ return "$ksft_fail"
+ else
+ echo "FAIL: 0/$count packets received"
+ return "$ksft_fail"
+ fi
+}
+
+ret=0
+
+echo "TEST: FOU/GRETAP IPv4 multicast encapsulation resubmit"
+setup_common
+setup_ipv4
+run_ping_test -4 eoudp4 "$TUN4_R" || ret=$?
+
+echo "TEST: FOU/GRETAP IPv6 multicast encapsulation resubmit"
+if setup_ipv6; then
+ run_ping_test -6 eoudp6 "$TUN6_R" || ret=$?
+else
+ echo "SKIP: IPv6 unavailable"
+fi
+
+exit $ret
--
2.47.3
^ 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