Thread (3 messages) 3 messages, 2 authors, 18h ago
HOTtoday REVIEWED: 1 (0M)

1 review trailer.

[PATCH] netfilter: ebtables: ebt_802_3: drop short frames before the match reads LLC

From: Guo Zihao <hidden>
Date: 2026-09-28 08:29:07
Also in: bridge, lkml, netfilter-devel
Subsystem: ethernet bridge, networking [general], the rest · Maintainers: Nikolay Aleksandrov, Ido Schimmel, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds

ebt_802_3_mt() takes the frame pointer from skb_mac_header() and reads
the LLC union fields (dsap, ssap, ctrl, type) without making sure that
those bytes are in the linear area. For an 802.3 frame (length field
below 1536) the payload is LLC, but only ETH_HLEN bytes are guaranteed
linear by the time the bridge hooks run, and neither ebt_do_table() nor
ebt_basic_match() pulls more.

A frame that carries nothing past the 14 byte Ethernet header therefore
reads into the skb tailroom. Check that sizeof(struct ebt_802_3_hdr)
bytes are actually linear before reading, and drop the packet through
par->hotdrop when they are not, the same signalling other ebt matches
use for a packet they cannot examine.

No Fixes tag. The unchecked skb_mac_header() dereference comes from the
initial ebtables merge and has not been touched since.

Reviewed-by: Liu Chao <redacted>
Signed-off-by: Guo Zihao <redacted>
---
 net/bridge/netfilter/ebt_802_3.c | 36 +++++++++++++++++++++++---------
 1 file changed, 26 insertions(+), 10 deletions(-)
diff --git a/net/bridge/netfilter/ebt_802_3.c b/net/bridge/netfilter/ebt_802_3.c
index 68c2519bd..533f0d36e 100644
--- a/net/bridge/netfilter/ebt_802_3.c
+++ b/net/bridge/netfilter/ebt_802_3.c
@@ -14,27 +14,43 @@
 #include <linux/skbuff.h>
 #include <uapi/linux/netfilter_bridge/ebt_802_3.h>
 
-static struct ebt_802_3_hdr *ebt_802_3_hdr(const struct sk_buff *skb)
-{
-	return (struct ebt_802_3_hdr *)skb_mac_header(skb);
-}
-
 static bool
 ebt_802_3_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
 	const struct ebt_802_3_info *info = par->matchinfo;
-	const struct ebt_802_3_hdr *hdr = ebt_802_3_hdr(skb);
-	__be16 type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type;
+	struct ebt_802_3_hdr _frame;
+	const struct ebt_802_3_hdr *frame;
+	int mac_offset = skb_mac_offset(skb);
+	__be16 type;
+
+	/* skb->data sits past the Ethernet header when the match runs, so the
+	 * frame starts before skb->data. skb_header_pointer() takes an offset
+	 * relative to skb->data and cannot express that, so check the linear
+	 * area against the mac header ourselves and use skb_mac_header()
+	 * directly once the check has passed.
+	 */
+	if (mac_offset < 0)
+		mac_offset = -mac_offset;
+	if (mac_offset + sizeof(_frame) > skb_headlen(skb)) {
+		/* The frame is too short to hold an LLC header. */
+		par->hotdrop = true;
+		return false;
+	}
+
+	frame = (const struct ebt_802_3_hdr *)skb_mac_header(skb);
+	type = frame->llc.ui.ctrl & IS_UI ? frame->llc.ui.type :
+					    frame->llc.ni.type;
 
 	if (info->bitmask & EBT_802_3_SAP) {
-		if (NF_INVF(info, EBT_802_3_SAP, info->sap != hdr->llc.ui.ssap))
+		if (NF_INVF(info, EBT_802_3_SAP, info->sap != frame->llc.ui.ssap))
 			return false;
-		if (NF_INVF(info, EBT_802_3_SAP, info->sap != hdr->llc.ui.dsap))
+		if (NF_INVF(info, EBT_802_3_SAP, info->sap != frame->llc.ui.dsap))
 			return false;
 	}
 
 	if (info->bitmask & EBT_802_3_TYPE) {
-		if (!(hdr->llc.ui.dsap == CHECK_TYPE && hdr->llc.ui.ssap == CHECK_TYPE))
+		if (!(frame->llc.ui.dsap == CHECK_TYPE &&
+		      frame->llc.ui.ssap == CHECK_TYPE))
 			return false;
 		if (NF_INVF(info, EBT_802_3_TYPE, info->type != type))
 			return false;
-- 
2.50.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help