The issue:
tcf_ife_decode() unconditionally calls eth_type_trans(), which pulls
ETH_HLEN. On egress this consumes the inner Ethernet header; a following
eth_type_trans() from loopback_xmit() then parses L3 data as Ethernet and
can BUG in __skb_pull() when the remaining linear area is short.
The Fix:
Parse the inner Ethernet header with eth_type_trans() in both directions,
then restore the egress data position and MAC length. On ingress the
existing behavior is unchanged. On egress, push the inner Ethernet header
back after parsing so the xmit path sees the original frame and later
actions see a consistent network header.
Decode is a receive-side operation; the egress branch keeps the frame
intact for transmit paths such as loopback. tcf_ife_is_eth_skb() accepts
Ethernet and loopback devices generally.
Conditions to recreate the bug:
- egress tc filter on lo: action ife decode pipe;
- AF_PACKET SOCK_RAW frame: outer Ethernet with ETH_P_IFE, IFE metadata,
inner Ethernet and an 8192-byte payload;
- the egress pipe re-enters eth_type_trans() via loopback_xmit() after the
action consumed the inner header.
Fixes: ef6980b6becb ("introduce IFE action")
Cc: <redacted>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
net/sched/act_ife.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
index 2afd68983ece..3946a9589bb8 100644
--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c
@@ -769,6 +769,10 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
skb->protocol = eth_type_trans(skb, skb->dev);
skb_reset_network_header(skb);
+ if (!skb_at_tc_ingress(skb)) {
+ skb_push(skb, ETH_HLEN);
+ skb_reset_mac_len(skb);
+ }
return action;
}--
2.43.0