* [PATCH net 0/2] net/sched: sch_teql: fix transmit-path regressions
@ 2026-10-16 8:47 Jamal Hadi Salim
2026-10-16 8:47 ` [PATCH net 1/2] net/sched: sch_teql: fix slaves_lock IRQ deadlock Jamal Hadi Salim
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Jamal Hadi Salim @ 2026-10-16 8:47 UTC (permalink / raw)
To: netdev
Cc: Jamal Hadi Salim, Victor Nogueira, Jiri Pirko, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
Patrick McHardy, owen kwan, linux-rt-devel, stable, sashiko-bot,
zdi-disclosures
Two independent sch_teql regressions on the transmit path.
Patch 1 makes slaves_lock safe for the hard-IRQ-disabled netpoll path and
for PREEMPT_RT by converting it to a raw spinlock taken with IRQs saved.
Patch 2 fixes a use-after-free when a lower virtual device consumes an skb
but returns NET_XMIT_DROP rather than NETDEV_TX_OK.
Jamal Hadi Salim (1):
net/sched: sch_teql: fix slaves_lock IRQ deadlock
owen kwan (1):
net/sched: sch_teql: fix use-after-free on lower qdisc drop
net/sched/sch_teql.c | 49 +++++++++++++++++++++++++++-----------------
1 file changed, 30 insertions(+), 19 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH net 1/2] net/sched: sch_teql: fix slaves_lock IRQ deadlock 2026-10-16 8:47 [PATCH net 0/2] net/sched: sch_teql: fix transmit-path regressions Jamal Hadi Salim @ 2026-10-16 8:47 ` Jamal Hadi Salim 2026-10-16 8:47 ` [PATCH net 2/2] net/sched: sch_teql: fix use-after-free on lower qdisc drop Jamal Hadi Salim 2026-10-16 8:53 ` [PATCH net 0/2] net/sched: sch_teql: fix transmit-path regressions netdev-bot+sinfo 2 siblings, 0 replies; 8+ messages in thread From: Jamal Hadi Salim @ 2026-10-16 8:47 UTC (permalink / raw) To: netdev Cc: Jamal Hadi Salim, Victor Nogueira, Jiri Pirko, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt, linux-rt-devel, stable, Sashiko, zdi-disclosures This is a followup of commit e5b811fe7931 ("net/sched: sch_teql: Introduce slaves_lock to avoid race condition and UAF") as reported by Sashiko. The issue: master->slaves_lock serializes the master's ring of slave qdiscs. The control paths -- teql_dequeue(), teql_destroy() and teql_qdisc_init() -- take it with spin_lock_bh(), while teql_master_xmit() (the master's ndo_start_xmit) takes it with plain spin_lock(). netpoll_send_skb() wraps the transmit in local_irq_save(), and __netpoll_send_skb() asserts lockdep_assert_irqs_disabled(), so teql_master_xmit() reached from netconsole always acquires slaves_lock with hard IRQs disabled. On PREEMPT_RT spinlock_t is an rtmutex, and Documentation/locking/locktypes.rst names local_irq_disable(); spin_lock(&lock); as a sequence that breaks there because the rtmutex requires a fully preemptible context. This is reachable without any panic: the nbcon printer thread calls netconsole's write_thread() callback on every message. The usual remedy -- folding the IRQ disable into the lock with spin_lock_irqsave() -- is unavailable because the local_irq_save() is netpoll's, not ours. On non-RT the same asymmetry leaves slaves_lock acquirable with hard IRQs disabled on one path and held with hard IRQs enabled on another. That is only exploitable during the panic console flush (netconsole is CON_NBCON_ATOMIC_UNSAFE, so console_is_usable() admits its write_atomic() only from nbcon_atomic_flush_unsafe(), which panic() alone calls), and even then an IRQ-saving lock does not help if the holder oopsed inside the section or was stopped by panic_other_cpus_shutdown(). So the non-RT half is hardening; the PREEMPT_RT half is the bug. The Fix: take slaves_lock as a raw spinlock with IRQs saved at every site. Since skb_queue_purge() takes the queue's spinlock_t and may not nest inside a raw lock on PREEMPT_RT, move its call in teql_destroy() outside the raw section; dat->q is the dying qdisc's own queue and was never serialized by slaves_lock, so the move is behaviour-neutral. The new critical sections contain only RCU pointer assignments and netdev_get_tx_queue(); skb_queue_purge(), netif_wake_queue() and dev_reset_queue() are all outside them. teql_destroy()'s ring walk is O(slaves), two pointer loads and a compare per iteration, so even a large ring is microseconds with IRQs off. Keeping the purge conditional rather than dropping it outright is the conservative call for a backport. Some context: commit 6301f6a34ed8 ("net/sched: sch_teql: move rcu_read_lock()/spin_lock() from _bh variants") hardened the parent fix; together they addressed the master->slaves resurrection use-after-free and the xmit-side BH warning but left the reverse direction -- a hard IRQ re-entering xmit while a control path holds the lock -- unaddressed. Conditions to recreate the bug: - CONFIG_PREEMPT_RT, CONFIG_NET_SCH_TEQL, CONFIG_DUMMY and CONFIG_NETCONSOLE. - Run `ip link add dev teqlslave0 type dummy`, bring teqlslave0 up, attach it with `tc qdisc add dev teqlslave0 root teql0`, and bring teql0 up. - Configure a netconsole target on teql0 with explicit local and remote IP addresses and a remote MAC address, then emit a console message. The nbcon printer thread reaches teql_master_xmit() with hard IRQs disabled by netpoll; taking slaves_lock as a spinlock_t is invalid on PREEMPT_RT. No panic or concurrent qdisc change is required. - Reachable by an admin with CAP_NET_ADMIN; teql devices exist only in the initial netns (no per-netns ops), so a user namespace does not suffice. Fixes: e5b811fe7931 ("net/sched: sch_teql: Introduce slaves_lock to avoid race condition and UAF") Reported-by: Sashiko (gemini) <sashiko-bot@kernel.org> Closes: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260630150922.238714-1-jhs%40mojatatu.com Link: https://lore.kernel.org/netdev/20260630150922.238714-1-jhs@mojatatu.com/ Cc: stable@vger.kernel.org Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> --- net/sched/sch_teql.c | 45 +++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 409ce50cc0db..c7dcec25ef42 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -53,7 +53,7 @@ struct teql_master { struct Qdisc_ops qops; struct net_device *dev; struct Qdisc __rcu *slaves; - spinlock_t slaves_lock; /* serializes writes to ->slaves */ + raw_spinlock_t slaves_lock; /* serializes writes to ->slaves */ struct list_head master_list; unsigned long tx_bytes; unsigned long tx_packets; @@ -92,6 +92,7 @@ teql_dequeue(struct Qdisc *sch) { struct teql_sched_data *dat = qdisc_priv(sch); struct netdev_queue *dat_queue; + unsigned long flags; struct sk_buff *skb; struct Qdisc *q; @@ -102,9 +103,9 @@ teql_dequeue(struct Qdisc *sch) if (skb == NULL) { struct net_device *m = qdisc_dev(q); if (m) { - spin_lock_bh(&dat->m->slaves_lock); + raw_spin_lock_irqsave(&dat->m->slaves_lock, flags); rcu_assign_pointer(dat->m->slaves, sch); - spin_unlock_bh(&dat->m->slaves_lock); + raw_spin_unlock_irqrestore(&dat->m->slaves_lock, flags); netif_wake_queue(m); } } else { @@ -137,11 +138,13 @@ teql_destroy(struct Qdisc *sch) struct teql_master *master = dat->m; struct netdev_queue *txq = NULL; bool reset_master_queue = false; + unsigned long flags; + bool purge = false; if (!master) return; - spin_lock_bh(&master->slaves_lock); + raw_spin_lock_irqsave(&master->slaves_lock, flags); prev = rcu_dereference_protected(master->slaves, lockdep_is_held(&master->slaves_lock)); if (prev) { @@ -169,12 +172,18 @@ teql_destroy(struct Qdisc *sch) reset_master_queue = true; } } - skb_queue_purge(&dat->q); + purge = true; break; } while (prev != rcu_dereference_protected(master->slaves, lockdep_is_held(&master->slaves_lock))); } - spin_unlock_bh(&master->slaves_lock); + raw_spin_unlock_irqrestore(&master->slaves_lock, flags); + + /* skb_queue_purge() takes the queue's spinlock_t, which cannot nest + * inside a raw lock on PREEMPT_RT; purge after the raw section. + */ + if (purge) + skb_queue_purge(&dat->q); if (reset_master_queue) dev_reset_queue(master->dev, txq, NULL); @@ -187,6 +196,7 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt, struct teql_master *m = (struct teql_master *)sch->ops; struct teql_sched_data *q = qdisc_priv(sch); struct Qdisc *first; + unsigned long flags; if (dev->hard_header_len > m->dev->hard_header_len) return -EINVAL; @@ -203,7 +213,7 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt, skb_queue_head_init(&q->q); - spin_lock_bh(&m->slaves_lock); + raw_spin_lock_irqsave(&m->slaves_lock, flags); first = rcu_dereference_protected(m->slaves, lockdep_is_held(&m->slaves_lock)); if (first) { if (m->dev->flags & IFF_UP) { @@ -214,7 +224,7 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt, (m->dev->flags & IFF_MULTICAST && !(dev->flags & IFF_MULTICAST)) || dev->mtu < m->dev->mtu) { - spin_unlock_bh(&m->slaves_lock); + raw_spin_unlock_irqrestore(&m->slaves_lock, flags); return -EINVAL; } } else { @@ -237,7 +247,7 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt, m->dev->mtu = dev->mtu; m->dev->flags = (m->dev->flags&~FMASK)|(dev->flags&FMASK); } - spin_unlock_bh(&m->slaves_lock); + raw_spin_unlock_irqrestore(&m->slaves_lock, flags); return 0; } @@ -302,11 +312,12 @@ static inline int teql_resolve(struct sk_buff *skb, static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev) { struct teql_master *master = netdev_priv(dev); - struct Qdisc *start, *q; - int busy; - int nores; int subq = skb_get_queue_mapping(skb); struct sk_buff *skb_res = NULL; + struct Qdisc *start, *q; + unsigned long flags; + int nores; + int busy; restart: nores = 0; @@ -342,13 +353,13 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev) netdev_start_xmit(skb, slave, slave_txq, false) == NETDEV_TX_OK) { __netif_tx_unlock(slave_txq); - spin_lock(&master->slaves_lock); + raw_spin_lock_irqsave(&master->slaves_lock, flags); if (rcu_dereference_protected(master->slaves, lockdep_is_held(&master->slaves_lock)) == q) rcu_assign_pointer(master->slaves, rcu_dereference_protected(NEXT_SLAVE(q), lockdep_is_held(&master->slaves_lock))); - spin_unlock(&master->slaves_lock); + raw_spin_unlock_irqrestore(&master->slaves_lock, flags); netif_wake_queue(dev); master->tx_packets++; master->tx_bytes += length; @@ -361,13 +372,13 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev) busy = 1; break; case 1: - spin_lock(&master->slaves_lock); + raw_spin_lock_irqsave(&master->slaves_lock, flags); if (rcu_dereference_protected(master->slaves, lockdep_is_held(&master->slaves_lock)) == q) rcu_assign_pointer(master->slaves, rcu_dereference_protected(NEXT_SLAVE(q), lockdep_is_held(&master->slaves_lock))); - spin_unlock(&master->slaves_lock); + raw_spin_unlock_irqrestore(&master->slaves_lock, flags); rcu_read_unlock(); return NETDEV_TX_OK; default: @@ -489,7 +500,7 @@ static __init void teql_master_setup(struct net_device *dev) struct teql_master *master = netdev_priv(dev); struct Qdisc_ops *ops = &master->qops; - spin_lock_init(&master->slaves_lock); + raw_spin_lock_init(&master->slaves_lock); master->dev = dev; ops->priv_size = sizeof(struct teql_sched_data); -- 2.43.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH net 2/2] net/sched: sch_teql: fix use-after-free on lower qdisc drop 2026-10-16 8:47 [PATCH net 0/2] net/sched: sch_teql: fix transmit-path regressions Jamal Hadi Salim 2026-10-16 8:47 ` [PATCH net 1/2] net/sched: sch_teql: fix slaves_lock IRQ deadlock Jamal Hadi Salim @ 2026-10-16 8:47 ` Jamal Hadi Salim 2026-10-20 9:13 ` netdev-bot+sashiko 2026-10-16 8:53 ` [PATCH net 0/2] net/sched: sch_teql: fix transmit-path regressions netdev-bot+sinfo 2 siblings, 1 reply; 8+ messages in thread From: Jamal Hadi Salim @ 2026-10-16 8:47 UTC (permalink / raw) To: netdev Cc: owen kwan, Jiri Pirko, Jamal Hadi Salim, Victor Nogueira, David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, Patrick McHardy, stable From: owen kwan <owen@verialabs.com> The issue: teql_master_xmit() tests the slave's ndo_start_xmit() return value against NETDEV_TX_OK alone. A slave that consumes the skb but returns an error code (rc < NET_XMIT_MASK, e.g. NET_XMIT_DROP) is treated as if the skb were still owned, so the loop restores skb->dev and calls __skb_pull() on it. A VLAN slave returns the result of dev_queue_xmit() from its ndo_start_xmit() (propagated since cbbef5e18307), and when the lower qdisc drops the packet that value is NET_XMIT_DROP after the skb has been freed, giving a use-after-free in teql_master_xmit(). The Fix: test for consumption with dev_xmit_complete(), which accepts NETDEV_TX_OK and every rc < NET_XMIT_MASK, matching other callers that need to distinguish consumed results from busy. Conditions to recreate the bug: With CONFIG_NET_SCH_TEQL, CONFIG_VLAN_8021Q and CONFIG_DUMMY enabled, add lkrdummy0 (dummy) and lkrvlan0 (VLAN id 37 on lkrdummy0); set a pfifo limit 0 root on lkrdummy0 and a teql0 root on lkrvlan0; bring teql0 up with an address and send one UDP packet to it. The VLAN xmit returns NET_XMIT_DROP from the lower qdisc while holding a freed skb. Fixes: 572a9d7b6fc7 ("net: allow to propagate errors through ->ndo_hard_start_xmit()") Cc: stable@vger.kernel.org Signed-off-by: owen kwan <owen@verialabs.com> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> --- net/sched/sch_teql.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index c7dcec25ef42..b3efd5c28198 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -350,8 +350,8 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev) skb->dev = slave; if (!netif_xmit_frozen_or_stopped(slave_txq) && - netdev_start_xmit(skb, slave, slave_txq, false) == - NETDEV_TX_OK) { + dev_xmit_complete(netdev_start_xmit(skb, slave, + slave_txq, false))) { __netif_tx_unlock(slave_txq); raw_spin_lock_irqsave(&master->slaves_lock, flags); if (rcu_dereference_protected(master->slaves, -- 2.43.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH net 2/2] net/sched: sch_teql: fix use-after-free on lower qdisc drop 2026-10-16 8:47 ` [PATCH net 2/2] net/sched: sch_teql: fix use-after-free on lower qdisc drop Jamal Hadi Salim @ 2026-10-20 9:13 ` netdev-bot+sashiko 2026-10-23 16:28 ` Simon Horman 0 siblings, 1 reply; 8+ messages in thread From: netdev-bot+sashiko @ 2026-10-20 9:13 UTC (permalink / raw) To: jhs Cc: netdev, owen, jiri, victor, davem, edumazet, kuba, pabeni, horms, kaber, stable Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider. Critical: 0 · High: 0 · Medium: 1 · Low: 0 If you believe none of the issues are legitimate, please reply to each issue of Medium severity or higher and explain why the AI is wrong. If any of them are legitimate and you plan to respin, please let patchwork know by including "pw-bot: cr" as a separate line at the end of your reply (one such reply per series is enough). - [Medium] In teql_master_xmit() (net/sched/sch_teql.c), the patch replaces `== NETDEV_TX_OK` with `dev_xmit_complete(rc)`. -- net/sched: sch_teql: fix use-after-free on lower qdisc drop This patch changes the check on the slave's netdev_start_xmit() return value in teql_master_xmit(). It now uses dev_xmit_complete() instead of comparing against NETDEV_TX_OK, so a slave that consumes the skb and returns NET_XMIT_DROP is no longer treated as still owning it. This fixes a use-after-free when a VLAN slave's lower qdisc drops the packet. > diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c > index c7dcec25ef420..b3efd5c281988 100644 > --- a/net/sched/sch_teql.c > +++ b/net/sched/sch_teql.c > @@ -350,8 +350,8 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev) > > skb->dev = slave; > if (!netif_xmit_frozen_or_stopped(slave_txq) && > - netdev_start_xmit(skb, slave, slave_txq, false) == > - NETDEV_TX_OK) { > + dev_xmit_complete(netdev_start_xmit(skb, slave, > + slave_txq, false))) { [Severity: Medium] This closes the use-after-free. Does the same condition now also count dropped packets as successful transmits on teql0? dev_xmit_complete() returns true for any rc < NET_XMIT_MASK. That covers NET_XMIT_DROP and negative errno values as well as NETDEV_TX_OK. All of these now take the success block in teql_master_xmit(): netif_wake_queue(dev); master->tx_packets++; master->tx_bytes += length; rcu_read_unlock(); return NETDEV_TX_OK; They also advance master->slaves to the next slave. teql_master_stats64() copies these counters directly into struct rtnl_link_stats64. There, tx_packets is defined as "Number of packets successfully transmitted". With the reproducer from the commit message (a VLAN slave on a dummy device with a pfifo limit 0 root), every packet the lower qdisc drops would appear as a good transmit in ip -s link show teql0. tx_dropped and tx_errors would stay at zero. The VLAN slave counts the same rc as a drop in vlan_dev_hard_start_xmit(): if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { ... u64_stats_inc(&stats->tx_packets); ... } else { this_cpu_inc(vlan->vlan_pcpu_stats->tx_dropped); } Could the rc be saved once? dev_xmit_complete(rc) would then decide only whether the skb is still owned, which keeps the use-after-free fix. In that case, tx_packets and tx_bytes would only grow for NETDEV_TX_OK and NET_XMIT_CN. The other consumed codes would go to tx_dropped (or tx_errors), without touching the skb. The commit message describes this only as a use-after-free fix. Could it also mention that teql0's counters behave differently now? > __netif_tx_unlock(slave_txq); > raw_spin_lock_irqsave(&master->slaves_lock, flags); > if (rcu_dereference_protected(master->slaves, -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/QDISC-Y0BY.v1.r0.20261015184107%40mojatatu.com ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net 2/2] net/sched: sch_teql: fix use-after-free on lower qdisc drop 2026-10-20 9:13 ` netdev-bot+sashiko @ 2026-10-23 16:28 ` Simon Horman 2026-10-23 17:50 ` Jamal Hadi Salim 0 siblings, 1 reply; 8+ messages in thread From: Simon Horman @ 2026-10-23 16:28 UTC (permalink / raw) To: netdev-bot+sashiko Cc: jhs, netdev, owen, jiri, victor, davem, edumazet, kuba, pabeni, kaber, stable On Tue, Oct 20, 2026 at 09:13:54AM +0000, netdev-bot+sashiko@kernel.org wrote: > Thank you for your contribution! Sashiko AI review found 1 potential > issue(s) to consider. > > Critical: 0 · High: 0 · Medium: 1 · Low: 0 > > If you believe none of the issues are legitimate, please reply to each > issue of Medium severity or higher and explain why the AI is wrong. > If any of them are legitimate and you plan to respin, please let patchwork > know by including "pw-bot: cr" as a separate line at the end of your reply > (one such reply per series is enough). > > - [Medium] In teql_master_xmit() (net/sched/sch_teql.c), the patch > replaces `== NETDEV_TX_OK` with `dev_xmit_complete(rc)`. Hi Jamal, Maybe things have moved on for some reason. But this concern does seem to warrant a response. > > -- > > net/sched: sch_teql: fix use-after-free on lower qdisc drop > > This patch changes the check on the slave's netdev_start_xmit() return > value in teql_master_xmit(). It now uses dev_xmit_complete() instead of > comparing against NETDEV_TX_OK, so a slave that consumes the skb and > returns NET_XMIT_DROP is no longer treated as still owning it. This fixes > a use-after-free when a VLAN slave's lower qdisc drops the packet. > > > diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c > > index c7dcec25ef420..b3efd5c281988 100644 > > --- a/net/sched/sch_teql.c > > +++ b/net/sched/sch_teql.c > > @@ -350,8 +350,8 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev) > > > > skb->dev = slave; > > if (!netif_xmit_frozen_or_stopped(slave_txq) && > > - netdev_start_xmit(skb, slave, slave_txq, false) == > > - NETDEV_TX_OK) { > > + dev_xmit_complete(netdev_start_xmit(skb, slave, > > + slave_txq, false))) { > > [Severity: Medium] > This closes the use-after-free. Does the same condition now also count > dropped packets as successful transmits on teql0? > > dev_xmit_complete() returns true for any rc < NET_XMIT_MASK. That covers > NET_XMIT_DROP and negative errno values as well as NETDEV_TX_OK. All of > these now take the success block in teql_master_xmit(): > > netif_wake_queue(dev); > master->tx_packets++; > master->tx_bytes += length; > rcu_read_unlock(); > return NETDEV_TX_OK; > > They also advance master->slaves to the next slave. > > teql_master_stats64() copies these counters directly into struct > rtnl_link_stats64. There, tx_packets is defined as "Number of packets > successfully transmitted". > > With the reproducer from the commit message (a VLAN slave on a dummy > device with a pfifo limit 0 root), every packet the lower qdisc drops > would appear as a good transmit in ip -s link show teql0. tx_dropped and > tx_errors would stay at zero. > > The VLAN slave counts the same rc as a drop in vlan_dev_hard_start_xmit(): > > if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { > ... > u64_stats_inc(&stats->tx_packets); > ... > } else { > this_cpu_inc(vlan->vlan_pcpu_stats->tx_dropped); > } > > Could the rc be saved once? dev_xmit_complete(rc) would then decide only > whether the skb is still owned, which keeps the use-after-free fix. In > that case, tx_packets and tx_bytes would only grow for NETDEV_TX_OK and > NET_XMIT_CN. The other consumed codes would go to tx_dropped (or > tx_errors), without touching the skb. > > The commit message describes this only as a use-after-free fix. Could it > also mention that teql0's counters behave differently now? > > > __netif_tx_unlock(slave_txq); > > raw_spin_lock_irqsave(&master->slaves_lock, flags); > > if (rcu_dereference_protected(master->slaves, > > -- > Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/QDISC-Y0BY.v1.r0.20261015184107%40mojatatu.com ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net 2/2] net/sched: sch_teql: fix use-after-free on lower qdisc drop 2026-10-23 16:28 ` Simon Horman @ 2026-10-23 17:50 ` Jamal Hadi Salim 0 siblings, 0 replies; 8+ messages in thread From: Jamal Hadi Salim @ 2026-10-23 17:50 UTC (permalink / raw) To: Simon Horman Cc: netdev-bot+sashiko, netdev, owen, jiri, victor, davem, edumazet, kuba, pabeni, kaber, stable On Fri, Oct 23, 2026 at 12:28 PM Simon Horman <horms@kernel.org> wrote: > > On Tue, Oct 20, 2026 at 09:13:54AM +0000, netdev-bot+sashiko@kernel.org wrote: > > Thank you for your contribution! Sashiko AI review found 1 potential > > issue(s) to consider. > > > > Critical: 0 · High: 0 · Medium: 1 · Low: 0 > > > > If you believe none of the issues are legitimate, please reply to each > > issue of Medium severity or higher and explain why the AI is wrong. > > If any of them are legitimate and you plan to respin, please let patchwork > > know by including "pw-bot: cr" as a separate line at the end of your reply > > (one such reply per series is enough). > > > > - [Medium] In teql_master_xmit() (net/sched/sch_teql.c), the patch > > replaces `== NETDEV_TX_OK` with `dev_xmit_complete(rc)`. > > Hi Jamal, > > Maybe things have moved on for some reason. > But this concern does seem to warrant a response. > Yikes, My new perfect "dont miss anything" script failed and didnt alert me ;-> Thanks for catching this. I will resend, one of those comments is legit - so i will send a v2. I do find sashiko-nipa sometimes misses showing up on the list, so i have a script that politely polls the site. Polling the site is more reliable. It is still strange - sometimes the embargo is lifted in 7 days but i just saw something with the embargo lifted after 2 days. Is there a human who decides this and intervenes? The script has a bug which i just fixed: it took reviews[0] which for nipa was for patch-1 which was empty review (meaning "No issue found") and decide that patch-2 was also "No issues found." At one point i think that approach worked. Note: The site didn't hide it; the script just selected the wrong array element. Fixed by matching patch_id/message_id. cheers, jamal > > > > -- > > > > net/sched: sch_teql: fix use-after-free on lower qdisc drop > > > > This patch changes the check on the slave's netdev_start_xmit() return > > value in teql_master_xmit(). It now uses dev_xmit_complete() instead of > > comparing against NETDEV_TX_OK, so a slave that consumes the skb and > > returns NET_XMIT_DROP is no longer treated as still owning it. This fixes > > a use-after-free when a VLAN slave's lower qdisc drops the packet. > > > > > diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c > > > index c7dcec25ef420..b3efd5c281988 100644 > > > --- a/net/sched/sch_teql.c > > > +++ b/net/sched/sch_teql.c > > > @@ -350,8 +350,8 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev) > > > > > > skb->dev = slave; > > > if (!netif_xmit_frozen_or_stopped(slave_txq) && > > > - netdev_start_xmit(skb, slave, slave_txq, false) == > > > - NETDEV_TX_OK) { > > > + dev_xmit_complete(netdev_start_xmit(skb, slave, > > > + slave_txq, false))) { > > > > [Severity: Medium] > > This closes the use-after-free. Does the same condition now also count > > dropped packets as successful transmits on teql0? > > > > dev_xmit_complete() returns true for any rc < NET_XMIT_MASK. That covers > > NET_XMIT_DROP and negative errno values as well as NETDEV_TX_OK. All of > > these now take the success block in teql_master_xmit(): > > > > netif_wake_queue(dev); > > master->tx_packets++; > > master->tx_bytes += length; > > rcu_read_unlock(); > > return NETDEV_TX_OK; > > > > They also advance master->slaves to the next slave. > > > > teql_master_stats64() copies these counters directly into struct > > rtnl_link_stats64. There, tx_packets is defined as "Number of packets > > successfully transmitted". > > > > With the reproducer from the commit message (a VLAN slave on a dummy > > device with a pfifo limit 0 root), every packet the lower qdisc drops > > would appear as a good transmit in ip -s link show teql0. tx_dropped and > > tx_errors would stay at zero. > > > > The VLAN slave counts the same rc as a drop in vlan_dev_hard_start_xmit(): > > > > if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { > > ... > > u64_stats_inc(&stats->tx_packets); > > ... > > } else { > > this_cpu_inc(vlan->vlan_pcpu_stats->tx_dropped); > > } > > > > Could the rc be saved once? dev_xmit_complete(rc) would then decide only > > whether the skb is still owned, which keeps the use-after-free fix. In > > that case, tx_packets and tx_bytes would only grow for NETDEV_TX_OK and > > NET_XMIT_CN. The other consumed codes would go to tx_dropped (or > > tx_errors), without touching the skb. > > > > The commit message describes this only as a use-after-free fix. Could it > > also mention that teql0's counters behave differently now? > > > > > __netif_tx_unlock(slave_txq); > > > raw_spin_lock_irqsave(&master->slaves_lock, flags); > > > if (rcu_dereference_protected(master->slaves, > > > > -- > > Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/QDISC-Y0BY.v1.r0.20261015184107%40mojatatu.com ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net 0/2] net/sched: sch_teql: fix transmit-path regressions 2026-10-16 8:47 [PATCH net 0/2] net/sched: sch_teql: fix transmit-path regressions Jamal Hadi Salim 2026-10-16 8:47 ` [PATCH net 1/2] net/sched: sch_teql: fix slaves_lock IRQ deadlock Jamal Hadi Salim 2026-10-16 8:47 ` [PATCH net 2/2] net/sched: sch_teql: fix use-after-free on lower qdisc drop Jamal Hadi Salim @ 2026-10-16 8:53 ` netdev-bot+sinfo 2026-10-16 9:00 ` Jamal Hadi Salim 2 siblings, 1 reply; 8+ messages in thread From: netdev-bot+sinfo @ 2026-10-16 8:53 UTC (permalink / raw) To: Jamal Hadi Salim Cc: netdev, Victor Nogueira, Jiri Pirko, David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt, Patrick McHardy, owen kwan, linux-rt-devel, stable, sashiko-bot, zdi-disclosures Hi! This is an automated message. This series looks like a fix, but its commit messages seem to be missing some information: - How the issue was discovered, e.g. hit in production, hit during development, syzbot report, manual code inspection, LLM or static analysis tool scan. Please do not repost the series just to address the above. Instead, reply to this email with the missing information, so that reviewers can take it into account. If the series needs another revision for other reasons, please include the information in the commit messages then. The evaluation is done by an LLM so it may be wrong, if you think that is the case please reply and explain. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net 0/2] net/sched: sch_teql: fix transmit-path regressions 2026-10-16 8:53 ` [PATCH net 0/2] net/sched: sch_teql: fix transmit-path regressions netdev-bot+sinfo @ 2026-10-16 9:00 ` Jamal Hadi Salim 0 siblings, 0 replies; 8+ messages in thread From: Jamal Hadi Salim @ 2026-10-16 9:00 UTC (permalink / raw) To: netdev-bot+sinfo Cc: netdev, Victor Nogueira, Jiri Pirko, David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt, Patrick McHardy, owen kwan, linux-rt-devel, stable, sashiko-bot, zdi-disclosures On Fri, Oct 16, 2026 at 4:53 AM <netdev-bot+sinfo@kernel.org> wrote: > > Hi! > > This is an automated message. This series looks like a fix, but its > commit messages seem to be missing some information: > > - How the issue was discovered, e.g. hit in production, hit during > development, syzbot report, manual code inspection, LLM or static > analysis tool scan. > > Please do not repost the series just to address the above. Instead, > reply to this email with the missing information, so that reviewers > can take it into account. If the series needs another revision for > other reasons, please include the information in the commit messages > then. > Patch 1 is a followup that addresses an issue discovered by sashiko and proven by our system. Patch 2 was sent to the security list - likely from a drive-by AI submission (i.e found and produced by an LLM). I am not getting responses from the OP but have veried the legitimacy of the bug and we have reproduced the issue; and it looks serious enough to push upstream. cheers, jamal > The evaluation is done by an LLM so it may be wrong, if you think > that is the case please reply and explain. ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-10-23 17:50 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-16 8:47 [PATCH net 0/2] net/sched: sch_teql: fix transmit-path regressions Jamal Hadi Salim 2026-10-16 8:47 ` [PATCH net 1/2] net/sched: sch_teql: fix slaves_lock IRQ deadlock Jamal Hadi Salim 2026-10-16 8:47 ` [PATCH net 2/2] net/sched: sch_teql: fix use-after-free on lower qdisc drop Jamal Hadi Salim 2026-10-20 9:13 ` netdev-bot+sashiko 2026-10-23 16:28 ` Simon Horman 2026-10-23 17:50 ` Jamal Hadi Salim 2026-10-16 8:53 ` [PATCH net 0/2] net/sched: sch_teql: fix transmit-path regressions netdev-bot+sinfo 2026-10-16 9:00 ` Jamal Hadi Salim
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox