mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 03:35:32 -04:00
wifi: wilc1000: validate monitor transmit frame headers
wilc_wfi_mon_xmit() reads the radiotap length before ensuring that the fixed header is present. After stripping that header, it reads the frame type and all three 802.11 addresses without checking how much frame data remains. A truncated monitor injection can therefore cause out-of-bounds reads. Validate the radiotap header first, use the common 802.11 helper to check the variable header length, and require a complete three-address header before using the addresses. This covers QoS and four-address data headers while rejecting short control headers that this path cannot classify. Signed-off-by: Mariano Baragiola <mbaragiola@linux.com> Link: https://patch.msgid.link/20260728192610.2236361-1-mbaragiola@linux.com Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
committed by
Johannes Berg
parent
fd2bf5e718
commit
9d96e037ff
@@ -142,6 +142,9 @@ static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len)
|
||||
static netdev_tx_t wilc_wfi_mon_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_radiotap_header_fixed *rtap_hdr;
|
||||
struct ieee80211_hdr_3addr *hdr;
|
||||
unsigned int hdr_len;
|
||||
u32 rtap_len, ret = 0;
|
||||
struct wilc_wfi_mon_priv *mon_priv;
|
||||
struct sk_buff *skb2;
|
||||
@@ -153,13 +156,26 @@ static netdev_tx_t wilc_wfi_mon_xmit(struct sk_buff *skb,
|
||||
if (!mon_priv)
|
||||
return -EFAULT;
|
||||
|
||||
if (skb->len < sizeof(*rtap_hdr))
|
||||
goto drop;
|
||||
|
||||
rtap_hdr = (void *)skb->data;
|
||||
if (rtap_hdr->it_version)
|
||||
goto drop;
|
||||
|
||||
rtap_len = ieee80211_get_radiotap_len(skb->data);
|
||||
if (skb->len < rtap_len)
|
||||
return -1;
|
||||
if (rtap_len < sizeof(*rtap_hdr) || skb->len < rtap_len)
|
||||
goto drop;
|
||||
|
||||
skb_pull(skb, rtap_len);
|
||||
hdr_len = ieee80211_get_hdrlen_from_skb(skb);
|
||||
if (hdr_len < sizeof(*hdr))
|
||||
goto drop;
|
||||
|
||||
if (skb->data[0] == 0xc0 && is_broadcast_ether_addr(&skb->data[4])) {
|
||||
hdr = (void *)skb->data;
|
||||
|
||||
if (ieee80211_is_deauth(hdr->frame_control) &&
|
||||
is_broadcast_ether_addr(hdr->addr1)) {
|
||||
skb2 = dev_alloc_skb(skb->len + sizeof(*cb_hdr));
|
||||
if (!skb2)
|
||||
return -ENOMEM;
|
||||
@@ -191,8 +207,8 @@ static netdev_tx_t wilc_wfi_mon_xmit(struct sk_buff *skb,
|
||||
}
|
||||
skb->dev = mon_priv->real_ndev;
|
||||
|
||||
ether_addr_copy(srcadd, &skb->data[10]);
|
||||
ether_addr_copy(bssid, &skb->data[16]);
|
||||
ether_addr_copy(srcadd, hdr->addr2);
|
||||
ether_addr_copy(bssid, hdr->addr3);
|
||||
/*
|
||||
* Identify if data or mgmt packet, if source address and bssid
|
||||
* fields are equal send it to mgmt frames handler
|
||||
@@ -207,6 +223,10 @@ static netdev_tx_t wilc_wfi_mon_xmit(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
drop:
|
||||
dev_kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static const struct net_device_ops wilc_wfi_netdev_ops = {
|
||||
|
||||
Reference in New Issue
Block a user