net/sched/cls_flower.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
Reject loading flower filters that match on Ethernet addresses
(eth_dst/eth_src) when the underlying device does not have an Ethernet
header (hard_header_len < sizeof(flow_dissector_key_eth_addrs)).
When such a filter is installed on a device like TUN (IFF_TUN mode,
hard_header_len=0), the flow dissector will attempt to read 12 bytes
from skb mac_header during classification. Since TUN is an L3 device
with no link-layer header, this reads uninitialized skb memory, causing
KMSAN to report uninit-value in __fl_lookup via rhashtable_lookup_fast.
Fix this at the source by preventing nonsensical filter configurations
rather than adding bounds checks in the hot classification path.
Reported-by: syzbot+fa2f5b1fb06147be5e16@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=fa2f5b1fb06147be5e16
Fixes: 77b9900ef53a ("tc: introduce Flower classifier")
Signed-off-by: Yun Zhou <yun.zhou@windriver.com>
Suggested-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
net/sched/cls_flower.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index 88f8a32fab2b..187cb6a60309 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -2465,6 +2465,18 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
if (err)
goto unbind_filter;
+ if (FL_KEY_IS_MASKED(&mask->key, eth)) {
+ struct Qdisc *q = tp->chain->block->q;
+
+ if (q && qdisc_dev(q)->hard_header_len <
+ sizeof(struct flow_dissector_key_eth_addrs)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Device does not have an Ethernet header");
+ err = -EINVAL;
+ goto unbind_filter;
+ }
+ }
+
fl_mask_update_range(mask);
fl_set_masked_key(&fnew->mkey, &fnew->key, mask);
--
2.43.0
On Wed, 3 Jun 2026 18:11:35 +0800 Yun Zhou wrote: > Fix this at the source by preventing nonsensical filter configurations > rather than adding bounds checks in the hot classification path. That's obviously preferable but we'd need much more code to make it work. The TC action blocks can be shared between arbitrary devices. I'm kinda surprised we can even get to a real device from the block, but either way I think the check you're adding is meaningless? -- pw-bot: cr
© 2016 - 2026 Red Hat, Inc.