mirror of
https://github.com/outbackdingo/mt76.git
synced 2026-10-24 05:16:57 +00:00
wifi: mt76: mt7996: fix infinite loop in PS sync event parsing
A zero-length TLV makes the parser loop spin forever, since neither skb_pull() nor the remaining length advance, hanging the RX NAPI thread until RCU reports a stall. Reject TLVs shorter than their header, and validate the per-tag payload lengths before dereferencing them. Fixes: https://github.com/openwrt/mt76/issues/1109 Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
+15
-3
@@ -845,22 +845,29 @@ mt7996_mcu_rx_ps_sync(struct mt7996_dev *dev, struct sk_buff *skb)
|
||||
struct tlv *tlv;
|
||||
int len;
|
||||
|
||||
if (skb->len < sizeof(*event))
|
||||
return;
|
||||
|
||||
skb_pull(skb, sizeof(*event));
|
||||
|
||||
len = skb->len;
|
||||
while (len > sizeof(*tlv)) {
|
||||
while (len >= sizeof(*tlv)) {
|
||||
u16 tag, tag_len;
|
||||
|
||||
tlv = (struct tlv *)skb->data;
|
||||
tag = le16_to_cpu(tlv->tag);
|
||||
tag_len = le16_to_cpu(tlv->len);
|
||||
if (tag_len > len)
|
||||
/* a tag_len below the header size would not advance the buffer */
|
||||
if (tag_len < sizeof(*tlv) || tag_len > len)
|
||||
break;
|
||||
|
||||
switch (tag) {
|
||||
case UNI_PS_CLIENT_INFO: {
|
||||
struct mt7996_mcu_ps_client_info *info = (void *)tlv;
|
||||
|
||||
if (tag_len < sizeof(*info))
|
||||
break;
|
||||
|
||||
mt7996_mcu_ps_transition(dev,
|
||||
le16_to_cpu(info->wlan_idx),
|
||||
info->ps_bit);
|
||||
@@ -868,9 +875,14 @@ mt7996_mcu_rx_ps_sync(struct mt7996_dev *dev, struct sk_buff *skb)
|
||||
}
|
||||
case UNI_PS_MULTI_CLIENT_INFO: {
|
||||
struct mt7996_mcu_ps_multi_client_info *info = (void *)tlv;
|
||||
u16 cnt = le16_to_cpu(info->sta_cnt);
|
||||
u16 cnt;
|
||||
int i;
|
||||
|
||||
if (tag_len < sizeof(*info))
|
||||
break;
|
||||
|
||||
cnt = min_t(u16, le16_to_cpu(info->sta_cnt),
|
||||
(tag_len - sizeof(*info)) / sizeof(info->sta_ps_info[0]));
|
||||
for (i = 0; i < cnt; i++) {
|
||||
u16 entry = le16_to_cpu(info->sta_ps_info[i]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user