* [PATCH net 0/2 repost3] net/sched: sch_teql: fix header-cloned write and retry strip
@ 2026-10-27 7:56 Jamal Hadi Salim
2026-10-27 7:56 ` [PATCH net 1/2 repost3] net/sched: sch_teql: unshare the header before writing and fix " Jamal Hadi Salim
2026-10-27 8:01 ` [PATCH net 0/2 repost3] net/sched: sch_teql: fix header-cloned write and retry strip netdev-bot+sinfo
0 siblings, 2 replies; 5+ messages in thread
From: Jamal Hadi Salim @ 2026-10-27 7:56 UTC (permalink / raw)
To: netdev
Cc: Jamal Hadi Salim, Victor Nogueira, Jiri Pirko, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, stable,
sashiko-bot
Two pre-existing defects on the teql transmit path, both around
teql_master_xmit() -> teql_resolve(). The first makes the slave's
header write corrupt a header-cloned skb and strips a userspace-supplied
link header on retry; the second leaves skb->dev pointing at the teql
master while the skb is parked on a slave's neighbour arp_queue.
Patch 1 makes the header private before the write and pulls back only
the header the slave added.
Patch 2 moves skb->dev = slave ahead of teql_resolve() and restores
skb->dev at the arp-queue reinjection point, so a parked skb names the
device whose neighbour took it and is delivered with a link header.
Both are follow-ups to commit dc4b95b8fee9 ("net/sched: sch_teql: restore
skb->dev on the slave failure path").
The pre-existing teql issues reported alongside this series are fixed
separately, not here. In particular, the lower-qdisc drop use-after-free
(`NETDEV_TX_OK` vs `dev_xmit_complete()`) is fixed by:
https://lore.kernel.org/netdev/QDISC-Y0BY.v2.r0.20261024060625-2@mojatatu.com/
This is repost3 of the same two patches; there is no code change. The
only changes since repost2 are the commit messages: the patch 1/2
message now says "header-cloned" instead of "shared", and the patch 2/2
commit message now describes the reinjection behaviour change for
bpf_redirect_neigh() and nft fwd ... neigh instead of claiming the
restore is an identity for every parker.
Jamal Hadi Salim (2):
net/sched: sch_teql: unshare the header before writing and fix retry
strip
net/sched: sch_teql: keep skb->dev consistent on the arp-queue path
net/core/neighbour.c | 1 +
net/sched/sch_teql.c | 34 ++++++++++++++++++++++++++++------
2 files changed, 29 insertions(+), 6 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net 1/2 repost3] net/sched: sch_teql: unshare the header before writing and fix retry strip
2026-10-27 7:56 [PATCH net 0/2 repost3] net/sched: sch_teql: fix header-cloned write and retry strip Jamal Hadi Salim
@ 2026-10-27 7:56 ` Jamal Hadi Salim
2026-10-27 7:56 ` [PATCH net 2/2 repost3] net/sched: sch_teql: keep skb->dev consistent on the arp-queue path Jamal Hadi Salim
2026-10-27 8:01 ` [PATCH net 0/2 repost3] net/sched: sch_teql: fix header-cloned write and retry strip netdev-bot+sinfo
1 sibling, 1 reply; 5+ messages in thread
From: Jamal Hadi Salim @ 2026-10-27 7:56 UTC (permalink / raw)
To: netdev
Cc: Jamal Hadi Salim, Victor Nogueira, Jiri Pirko, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
sashiko-bot, stable
teql_master_xmit() writes the slave's link header into the skb in
teql_resolve() and on retry pulls it back with __skb_pull(). Two bugs:
1. When the skb's header is cloned (e.g. a tc-mirred action on a
physical device's clsact egress redirects to the teql master), the
write corrupts the other clone. Call skb_cow_head() first.
2. The pull always removes skb_network_offset() bytes. For an
AF_PACKET/SOCK_RAW frame with no dst entry, teql_resolve() adds no
header, so the retry strips the user-supplied one. Pull back only
the length this slave added.
Track the added length per iteration; a header-cloned skb is unshared
before the write and an AF_PACKET frame retries with its header intact.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reported-by: Sashiko (gemini) <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260824115928.4099988-1-victor@mojatatu.com
Link: https://lore.kernel.org/netdev/20260824115928.4099988-1-victor@mojatatu.com/
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
net/sched/sch_teql.c | 32 +++++++++++++++++++++++++++-----
1 file changed, 27 insertions(+), 5 deletions(-)
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index 409ce50cc0db..acd03f9afc6b 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -245,7 +245,7 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
static int
__teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res,
struct net_device *dev, struct netdev_queue *txq,
- struct dst_entry *dst)
+ struct dst_entry *dst, int *hlen)
{
struct neighbour *n;
int err = 0;
@@ -265,15 +265,28 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res,
}
if (neigh_event_send(n, skb_res) == 0) {
+ int off = skb_network_offset(skb);
char haddr[MAX_ADDR_LEN];
neigh_ha_snapshot(haddr, n, dev);
+ /* The skb may be shared (e.g. a packet tap clone); make the
+ * headroom private before dev_hard_header() writes into it.
+ */
+ if (skb_cow_head(skb, LL_RESERVED_SPACE(dev)) < 0) {
+ err = -ENOMEM;
+ goto out;
+ }
if (dev_hard_header(skb, dev, ntohs(skb_protocol(skb, false)),
haddr, NULL, skb->len) < 0)
err = -EINVAL;
+ /* The header, if any, is prepended above skb->data, so the
+ * network offset grew by exactly the bytes to undo later.
+ */
+ *hlen = skb_network_offset(skb) - off;
} else {
err = (skb_res == NULL) ? -EAGAIN : 1;
}
+out:
neigh_release(n);
return err;
}
@@ -281,11 +294,13 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res,
static inline int teql_resolve(struct sk_buff *skb,
struct sk_buff *skb_res,
struct net_device *dev,
- struct netdev_queue *txq)
+ struct netdev_queue *txq,
+ int *hlen)
{
struct dst_entry *dst = skb_dst(skb);
int res;
+ *hlen = 0;
if (rcu_access_pointer(txq->qdisc) == &noop_qdisc)
return -ENODEV;
@@ -293,7 +308,7 @@ static inline int teql_resolve(struct sk_buff *skb,
return 0;
rcu_read_lock();
- res = __teql_resolve(skb, skb_res, dev, txq, dst);
+ res = __teql_resolve(skb, skb_res, dev, txq, dst, hlen);
rcu_read_unlock();
return res;
@@ -305,6 +320,7 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
struct Qdisc *start, *q;
int busy;
int nores;
+ int hlen;
int subq = skb_get_queue_mapping(skb);
struct sk_buff *skb_res = NULL;
@@ -332,7 +348,7 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
continue;
}
- switch (teql_resolve(skb, skb_res, slave, slave_txq)) {
+ switch (teql_resolve(skb, skb_res, slave, slave_txq, &hlen)) {
case 0:
if (__netif_tx_trylock(slave_txq)) {
unsigned int length = qdisc_pkt_len(skb);
@@ -374,8 +390,14 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
nores = 1;
break;
}
+ /* Undo only the header teql_resolve() pushed for this slave.
+ * Pulling skb_network_offset() instead would strip a
+ * userspace-supplied header when the slave added none, e.g.
+ * an AF_PACKET/SOCK_RAW frame with no dst entry.
+ */
+ if (hlen > 0)
+ __skb_pull(skb, hlen);
skb->dev = dev;
- __skb_pull(skb, skb_network_offset(skb));
} while ((q = rcu_dereference(NEXT_SLAVE(q))) != start);
if (nores && skb_res == NULL) {
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH net 2/2 repost3] net/sched: sch_teql: keep skb->dev consistent on the arp-queue path
2026-10-27 7:56 ` [PATCH net 1/2 repost3] net/sched: sch_teql: unshare the header before writing and fix " Jamal Hadi Salim
@ 2026-10-27 7:56 ` Jamal Hadi Salim
0 siblings, 0 replies; 5+ messages in thread
From: Jamal Hadi Salim @ 2026-10-27 7:56 UTC (permalink / raw)
To: netdev
Cc: Jamal Hadi Salim, Victor Nogueira, Jiri Pirko, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, stable,
Sashiko
teql_master_xmit() sets skb->dev = slave only right before the slave's
ndo_start_xmit(). If the slave's neighbour is unresolved, teql_resolve()
parks the skb on the slave's arp_queue with skb->dev still naming the
teql master. The master can be freed while the slave lives, so the
queued skb can dereference freed memory.
Set skb->dev = slave before teql_resolve() so the parked skb names the
device whose neighbour owns it, and restore skb->dev = n1->dev at the
neigh_update_process_arp_queue() reinjection point so the skb goes back
through teql_master_xmit() instead of leaving headerless.
The reinjection restore is not an identity for other parkers:
bpf_redirect_neigh() with explicit nexthop parameters and nft
fwd ... neigh can park with dst->dev != skb->dev. For those paths it
moves skb->dev to the dst device and the packet can re-enter that
device's egress path. This is a behaviour change for those paths.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reported-by: Sashiko (nipa) <sashiko-bot@kernel.org>
Closes: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260824115928.4099988-1-victor@mojatatu.com
Link: https://lore.kernel.org/netdev/20260824115928.4099988-1-victor@mojatatu.com/
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
net/core/neighbour.c | 1 +
net/sched/sch_teql.c | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 7448320f7ad5..5823f5007812 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1336,6 +1336,7 @@ static void neigh_update_process_arp_queue(struct neighbour *neigh)
if (n2)
n1 = n2;
}
+ skb->dev = n1->dev;
READ_ONCE(n1->output)(n1, skb);
if (n2)
neigh_release(n2);
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index acd03f9afc6b..3fbd5af10028 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -348,12 +348,12 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
continue;
}
+ skb->dev = slave;
switch (teql_resolve(skb, skb_res, slave, slave_txq, &hlen)) {
case 0:
if (__netif_tx_trylock(slave_txq)) {
unsigned int length = qdisc_pkt_len(skb);
- skb->dev = slave;
if (!netif_xmit_frozen_or_stopped(slave_txq) &&
netdev_start_xmit(skb, slave, slave_txq, false) ==
NETDEV_TX_OK) {
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH net 0/2 repost3] net/sched: sch_teql: fix header-cloned write and retry strip
2026-10-27 7:56 [PATCH net 0/2 repost3] net/sched: sch_teql: fix header-cloned write and retry strip Jamal Hadi Salim
2026-10-27 7:56 ` [PATCH net 1/2 repost3] net/sched: sch_teql: unshare the header before writing and fix " Jamal Hadi Salim
@ 2026-10-27 8:01 ` netdev-bot+sinfo
2026-10-27 9:07 ` Jamal Hadi Salim
1 sibling, 1 reply; 5+ messages in thread
From: netdev-bot+sinfo @ 2026-10-27 8:01 UTC (permalink / raw)
To: Jamal Hadi Salim
Cc: netdev, Victor Nogueira, Jiri Pirko, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, stable,
sashiko-bot
Hi!
This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:
- Whether the issue was actually triggered, or is only theoretical
(e.g. found by code inspection). If it was triggered please include
the symptoms, like the stack trace or error messages.
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] 5+ messages in thread
* Re: [PATCH net 0/2 repost3] net/sched: sch_teql: fix header-cloned write and retry strip
2026-10-27 8:01 ` [PATCH net 0/2 repost3] net/sched: sch_teql: fix header-cloned write and retry strip netdev-bot+sinfo
@ 2026-10-27 9:07 ` Jamal Hadi Salim
0 siblings, 0 replies; 5+ messages in thread
From: Jamal Hadi Salim @ 2026-10-27 9:07 UTC (permalink / raw)
To: netdev-bot+sinfo
Cc: netdev, Victor Nogueira, Jiri Pirko, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, stable,
sashiko-bot
cheers
On Tue, Oct 27, 2026 at 4:01 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:
>
> - Whether the issue was actually triggered, or is only theoretical
> (e.g. found by code inspection). If it was triggered please include
> the symptoms, like the stack trace or error messages.
>
> 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.
My bad for not explicitly calling it out in the commit this time to
avoid you sending this email; answer is the same as before:
https://lore.kernel.org/netdev/CAM0EoM=yCSeB9+Q8gFsB8sjQhddM9qWh8DOfSqqNtp6byubv2w@mail.gmail.com/
https://lore.kernel.org/netdev/CAM0EoMnb78SoNwrqgH5308B_+Mh1sBtm+wJ=SFXtMHS-L2zfXg@mail.gmail.com/
cheers,
jamal
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-10-27 9:07 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-27 7:56 [PATCH net 0/2 repost3] net/sched: sch_teql: fix header-cloned write and retry strip Jamal Hadi Salim
2026-10-27 7:56 ` [PATCH net 1/2 repost3] net/sched: sch_teql: unshare the header before writing and fix " Jamal Hadi Salim
2026-10-27 7:56 ` [PATCH net 2/2 repost3] net/sched: sch_teql: keep skb->dev consistent on the arp-queue path Jamal Hadi Salim
2026-10-27 8:01 ` [PATCH net 0/2 repost3] net/sched: sch_teql: fix header-cloned write and retry strip netdev-bot+sinfo
2026-10-27 9:07 ` 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