[PATCH net] net/sched: act_ife: use mac_len for ingress header offset
From: Victor Nogueira <hidden>
Date: 2026-08-10 14:42:09
Subsystem:
networking [general], tc subsystem, the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jamal Hadi Salim, Jiri Pirko, Linus Torvalds
On ingress, the L2 header stripped from the frame is skb->mac_len, not
skb->dev->hard_header_len. Use it for the skb_push/skb_pull offsets in
tcf_ife_encode()/tcf_ife_decode() and the matching header length inside
ife_encode()/ife_decode(). On egress keep hard_header_len.
For devices where hard_header_len differs from mac_len (e.g. PPP, which
reports 4 vs 0), the previous code pushed/pulled the wrong amount and
could hit skb_under_panic on ingress when headroom was tight.
Fixes: 295a6e06d21e1 ("net/sched: act_ife: Change to use ife module")
Reported-by: vega@nebusec.ai
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Victor Nogueira <redacted>
---
net/ife/ife.c | 18 +++++++++++-------
net/sched/act_ife.c | 6 +++---
2 files changed, 14 insertions(+), 10 deletions(-)
diff --git a/net/ife/ife.c b/net/ife/ife.c
index 7a75947a31e3..3d31d68114ef 100644
--- a/net/ife/ife.c
+++ b/net/ife/ife.c@@ -36,8 +36,10 @@ void *ife_encode(struct sk_buff *skb, u16 metalen) /* OUTERHDR:TOTMETALEN:{TLVHDR:Metadatum:TLVHDR..}:ORIGDATA * where ORIGDATA = original ethernet header ... */ + unsigned int hdrlen = skb_at_tc_ingress(skb) ? + skb->mac_len : skb->dev->hard_header_len; int hdrm = metalen + IFE_METAHDRLEN; - int total_push = hdrm + skb->dev->hard_header_len; + int total_push = hdrm + hdrlen; struct ifeheadr *ifehdr; struct ethhdr *iethh; /* inner ether header */ int skboff = 0;
@@ -50,9 +52,9 @@ void *ife_encode(struct sk_buff *skb, u16 metalen) iethh = (struct ethhdr *) skb->data; __skb_push(skb, total_push); - memcpy(skb->data, iethh, skb->dev->hard_header_len); + memcpy(skb->data, iethh, hdrlen); skb_reset_mac_header(skb); - skboff += skb->dev->hard_header_len; + skboff += hdrlen; /* total metadata length */ ifehdr = (struct ifeheadr *) (skb->data + skboff);
@@ -65,16 +67,18 @@ EXPORT_SYMBOL_GPL(ife_encode); void *ife_decode(struct sk_buff *skb, u16 *metalen) { + unsigned int hdrlen = skb_at_tc_ingress(skb) ? + skb->mac_len : skb->dev->hard_header_len; struct ifeheadr *ifehdr; int total_pull; u16 ifehdrln; - if (!pskb_may_pull(skb, skb->dev->hard_header_len + IFE_METAHDRLEN)) + if (!pskb_may_pull(skb, hdrlen + IFE_METAHDRLEN)) return NULL; - ifehdr = (struct ifeheadr *) (skb->data + skb->dev->hard_header_len); + ifehdr = (struct ifeheadr *)(skb->data + hdrlen); ifehdrln = ntohs(ifehdr->metalen); - total_pull = skb->dev->hard_header_len + ifehdrln; + total_pull = hdrlen + ifehdrln; if (unlikely(ifehdrln < 2)) return NULL;
@@ -82,7 +86,7 @@ void *ife_decode(struct sk_buff *skb, u16 *metalen) if (unlikely(!pskb_may_pull(skb, total_pull + ETH_HLEN))) return NULL; - ifehdr = (struct ifeheadr *)(skb->data + skb->dev->hard_header_len); + ifehdr = (struct ifeheadr *)(skb->data + hdrlen); skb_set_mac_header(skb, total_pull); __skb_pull(skb, total_pull); *metalen = ifehdrln - IFE_METAHDRLEN;
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
index 065228026c58..ea7df36ab7e3 100644
--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c@@ -723,7 +723,7 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a, tcf_lastuse_update(&ife->tcf_tm); if (skb_at_tc_ingress(skb)) - skb_push(skb, skb->dev->hard_header_len); + skb_push(skb, skb->mac_len); tlv_data = ife_decode(skb, &metalen); if (unlikely(!tlv_data)) {
@@ -826,7 +826,7 @@ static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a, } if (skb_at_tc_ingress(skb)) - skb_push(skb, skb->dev->hard_header_len); + skb_push(skb, skb->mac_len); ife_meta = ife_encode(skb, metalen); if (!ife_meta)
@@ -856,7 +856,7 @@ static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a, oethh->h_proto = htons(p->eth_type); if (skb_at_tc_ingress(skb)) - skb_pull(skb, skb->dev->hard_header_len); + skb_pull(skb, skb->mac_len); return action; }
--
2.55.0