[PATCH net 2/3 repost2] net/sched: act_ife: require a full Ethernet header on egress
flat view
HOTtoday
REVIEWED: 1 (0M)
From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2026-10-31 20:18:28
Also in:
stable
Subsystem:
networking [general], tc subsystem, the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jamal Hadi Salim, Jiri Pirko, Linus Torvalds
Status: Reviewed.
1 review trailer.
This is a followup of commit 5b483f7791b0 ("net/sched: act_ife: Only operate on Ethernet frames") as reported by Sashiko. The finding was raised by both Sashiko providers (nipa and gemini) while reviewing the parent patchset. shaos [off-list ref] independently reported the same undersized-egress path with a reproducer, which was reproduced and verified in our test environment. The issue: On egress tcf_ife_is_eth_skb() only checks the device type; it does not check that the skb carries a full Ethernet header. For an Ethernet or loopback device it returns true even when the skb has no Ethernet header. tcf_ife_encode() then calls ife_encode(), which copies ETH_HLEN bytes from skb->data. A short skb therefore reads past its linear data and the copied bytes, including stale kernel memory, are emitted in the outer Ethernet header. The parent commit fixed the reported ingress mac_len case but left the egress path without a length check. A total-length test is not sufficient: a non-GSO TUN skb can have a large total length while only a single byte sits in the linear area, so ife_encode() still reads past the linear header. Require instead that the Ethernet header the encoder copies is present in the linear part of the skb. The Fix: On egress require pskb_may_pull(skb, ETH_HLEN) before encoding, which ensures the Ethernet header is present in the linear data ife_encode() copies from; the ingress mac_len check is unchanged. A short egress skb is now dropped instead of being encoded. Conditions to recreate the bug: CONFIG_NET_ACT_IFE=y, CONFIG_NET_CLS_MATCHALL=y, CONFIG_NET_SCH_INGRESS=y, CONFIG_TUN=y, CONFIG_NET_ACT_MIRRED=y. In two user and network namespaces (a victim and an attacker), open a TUN device in IFF_TUN mode and attach clsact to it and to lo. Redirect ingress traffic from the TUN device to lo egress with mirred, and install an ife encode action on lo egress: tc qdisc add dev <tun> clsact tc qdisc add dev lo clsact tc filter add dev <tun> ingress matchall action mirred egress \ redirect dev lo tc filter add dev lo egress matchall action ife encode use mark 1 \ action ok Send a TUN packet shorter than ETH_HLEN (a one-byte payload is enough) and receive the emitted frame on the other side. Without the fix the outer Ethernet header contains bytes copied past the short packet; with the fix the short skb is dropped. The attacker needs CAP_NET_ADMIN in its user namespace; no init-net privilege is required. The same path is reachable when the total length is large but the Ethernet header is not linear: write a non-GSO virtio header with hdr_len=1 followed by an 8192-byte packet so that only one byte stays linear. Without the fix the copied header reads past the linear data; with the fix the header is pulled into the linear area before the copy. Fixes: ef6980b6becb ("introduce IFE action") Reported-by: Sashiko (nipa) <sashiko-bot@kernel.org> Reported-by: Sashiko (gemini) <sashiko-bot@kernel.org> Reported-by: shaos <redacted> Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260821164031.32824-1-victor%40mojatatu.com Link: https://sashiko.dev/#/patchset/20260821164031.32824-1-victor@mojatatu.com Link: https://lore.kernel.org/netdev/20261022144736.61227-1-shawnq1@163.com/ (local) Cc: <redacted> Reviewed-by: Victor Nogueira <redacted> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> --- repost1 -> repost2: rebased onto the current net tip. The repost1 posting was recalled because 3/3 no longer applied; this patch is unchanged. act_ife.c gained 498c631f9c6d ("act_ife: do not consume the inner header on egress") since repost1, but it touches tcf_ife_decode(), not the encoder, so only the hunk offset moved. --- net/sched/act_ife.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
index 6b23a3965121..5a527da00566 100644
--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c@@ -878,13 +878,16 @@ static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a, * is an Ethernet header because the skb could've been redirected with mirred * from a non-Ethernet device. */ -static bool tcf_ife_is_eth_skb(const struct sk_buff *skb) +static bool tcf_ife_is_eth_skb(struct sk_buff *skb) { if (skb->dev->type != ARPHRD_ETHER && skb->dev->type != ARPHRD_LOOPBACK) return false; - return !skb_at_tc_ingress(skb) || skb->mac_len == ETH_HLEN; + if (skb_at_tc_ingress(skb)) + return skb->mac_len == ETH_HLEN; + + return pskb_may_pull(skb, ETH_HLEN); } TC_INDIRECT_SCOPE int tcf_ife_act(struct sk_buff *skb,
--
2.43.0