diff options
| author | Johannes Berg <johannes.berg@intel.com> | 2026-09-04 16:55:02 +0200 |
|---|---|---|
| committer | Johannes Berg <johannes.berg@intel.com> | 2026-09-08 13:09:38 +0200 |
| commit | 48b2c5c628b09cf36cbeca53e0432fc2a7518be7 (patch) | |
| tree | 8fda142ce7423d4957889d56b4e734d965d739c7 | |
| parent | a7783e585360ee05dfe21d3173dbbe985c94f29e (diff) | |
| download | linux-next-48b2c5c628b09cf36cbeca53e0432fc2a7518be7.tar.gz linux-next-48b2c5c628b09cf36cbeca53e0432fc2a7518be7.zip | |
wifi: cfg80211: check IP header size in cfg80211_classify8021d()
A frame that looks like IP can be transmitted, but be too short, so
the DS field is read incorrectly:
BUG: KMSAN: uninit-value in cfg80211_classify8021d+0x99d/0x12b0 net/wireless/util.c:1027
cfg80211_classify8021d+0x99d/0x12b0 net/wireless/util.c:1027
ieee80211_select_queue+0x37a/0x9e0 net/mac80211/wme.c:180
__ieee80211_subif_start_xmit+0x60f/0x1d90 net/mac80211/tx.c:4304
ieee80211_subif_start_xmit+0xa8/0x6d0 net/mac80211/tx.c:4538
...
packet_sendmsg+0x9173/0xa2a0 net/packet/af_packet.c:3108
Use skb_header_pointer() like the MPLS case.
Assisted-by: LLM
Fixes: e31a16d6f64e ("wireless: move some utility functions from mac80211 to cfg80211")
Reported-by: syzbot+878ddc3962f792e9af59@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=878ddc3962f792e9af59
Link: https://patch.msgid.link/20260904165614.5e61a4c80b92.I37d68d3f406cb3b90b32e6943418d66070b65197@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
| -rw-r--r-- | net/wireless/util.c | 26 |
1 files changed, 22 insertions, 4 deletions
diff --git a/net/wireless/util.c b/net/wireless/util.c index 408ebb10924f..5429cf3cfd2f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1039,12 +1039,30 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb, } switch (skb->protocol) { - case htons(ETH_P_IP): - dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc; + case htons(ETH_P_IP): { + const struct iphdr *iph; + struct iphdr _iph; + + iph = skb_header_pointer(skb, sizeof(struct ethhdr), + sizeof(*iph), &_iph); + if (!iph) + return 0; + + dscp = ipv4_get_dsfield(iph) & 0xfc; break; - case htons(ETH_P_IPV6): - dscp = ipv6_get_dsfield(ipv6_hdr(skb)) & 0xfc; + } + case htons(ETH_P_IPV6): { + const struct ipv6hdr *ip6h; + struct ipv6hdr _ip6h; + + ip6h = skb_header_pointer(skb, sizeof(struct ethhdr), + sizeof(*ip6h), &_ip6h); + if (!ip6h) + return 0; + + dscp = ipv6_get_dsfield(ip6h) & 0xfc; break; + } case htons(ETH_P_MPLS_UC): case htons(ETH_P_MPLS_MC): { struct mpls_label mpls_tmp, *mpls; |
