mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
wifi: rtw88: Add more validation for the RX descriptor
Some RTL8821CE cards can return frames with corrupted RX descriptor, causing warnings and crashes if they are passed to the upper layers. The PHY status size field is 4 bits wide, but in rtw88 its value should only be 0 or 4. Checking this catches most of the corrupt frames. If a PHY status is present, the PHY status size should not be 0. The frame size should not be less than or equal to 4 and should not exceed 11454. The rate should not exceed 4SS MCS9. Discard the frame if any of these checks fail. Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221286 Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com> Tested-by: Oleksandr Havrylov <goainwo@gmail.com> Acked-by: Ping-Ke Shih <pkshih@realtek.com> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Link: https://patch.msgid.link/5bfecba3-8a90-4e0f-9558-af5cd8a14975@gmail.com
This commit is contained in:
parent
756abe2ebe
commit
aa7d92e838
|
|
@ -1042,20 +1042,21 @@ static int rtw_pci_get_hw_rx_ring_nr(struct rtw_dev *rtwdev,
|
|||
static u32 rtw_pci_rx_napi(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,
|
||||
u8 hw_queue, u32 limit)
|
||||
{
|
||||
struct rtw_pci_rx_ring *ring = &rtwpci->rx_rings[RTW_RX_QUEUE_MPDU];
|
||||
const struct rtw_chip_info *chip = rtwdev->chip;
|
||||
struct napi_struct *napi = &rtwpci->napi;
|
||||
struct rtw_pci_rx_ring *ring = &rtwpci->rx_rings[RTW_RX_QUEUE_MPDU];
|
||||
struct rtw_rx_pkt_stat pkt_stat;
|
||||
u32 pkt_desc_sz = chip->rx_pkt_desc_sz;
|
||||
u32 buf_desc_sz = chip->rx_buf_desc_sz;
|
||||
struct ieee80211_rx_status rx_status;
|
||||
struct rtw_rx_pkt_stat pkt_stat;
|
||||
struct sk_buff *skb, *new;
|
||||
u32 cur_rp = ring->r.rp;
|
||||
u32 count, rx_done = 0;
|
||||
u32 pkt_offset;
|
||||
u32 pkt_desc_sz = chip->rx_pkt_desc_sz;
|
||||
u32 buf_desc_sz = chip->rx_buf_desc_sz;
|
||||
dma_addr_t dma;
|
||||
u32 new_len;
|
||||
u8 *rx_desc;
|
||||
dma_addr_t dma;
|
||||
int ret;
|
||||
|
||||
count = rtw_pci_get_hw_rx_ring_nr(rtwdev, rtwpci);
|
||||
count = min(count, limit);
|
||||
|
|
@ -1067,7 +1068,10 @@ static u32 rtw_pci_rx_napi(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,
|
|||
dma_sync_single_for_cpu(rtwdev->dev, dma, RTK_PCI_RX_BUF_SIZE,
|
||||
DMA_FROM_DEVICE);
|
||||
rx_desc = skb->data;
|
||||
rtw_rx_query_rx_desc(rtwdev, rx_desc, &pkt_stat, &rx_status);
|
||||
ret = rtw_rx_query_rx_desc(rtwdev, rx_desc,
|
||||
&pkt_stat, &rx_status);
|
||||
if (ret)
|
||||
goto next_rp;
|
||||
|
||||
/* offset from rx_desc to payload */
|
||||
pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz +
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include "mac.h"
|
||||
#include "rx.h"
|
||||
#include "ps.h"
|
||||
#include "debug.h"
|
||||
|
|
@ -261,9 +262,9 @@ static void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev,
|
|||
}
|
||||
}
|
||||
|
||||
void rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8,
|
||||
struct rtw_rx_pkt_stat *pkt_stat,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
int rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8,
|
||||
struct rtw_rx_pkt_stat *pkt_stat,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz;
|
||||
struct rtw_rx_desc *rx_desc = rx_desc8;
|
||||
|
|
@ -295,20 +296,28 @@ void rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8,
|
|||
|
||||
pkt_stat->tsf_low = le32_get_bits(rx_desc->w5, RTW_RX_DESC_W5_TSFL);
|
||||
|
||||
if (unlikely(pkt_stat->rate >= DESC_RATE_MAX)) {
|
||||
rtw_dbg(rtwdev, RTW_DBG_UNEXP,
|
||||
"unexpected RX rate=0x%x\n", pkt_stat->rate);
|
||||
if (unlikely(pkt_stat->rate >= DESC_RATE_MAX))
|
||||
return -EINVAL;
|
||||
|
||||
pkt_stat->rate = DESC_RATE1M;
|
||||
pkt_stat->bw = RTW_CHANNEL_WIDTH_20;
|
||||
}
|
||||
if (unlikely(pkt_stat->drv_info_sz &&
|
||||
pkt_stat->drv_info_sz != PHY_STATUS_SIZE))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(pkt_stat->phy_status && !pkt_stat->drv_info_sz))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(pkt_stat->pkt_len > IEEE80211_MAX_MPDU_LEN_VHT_11454))
|
||||
return -EINVAL;
|
||||
|
||||
/* drv_info_sz is in unit of 8-bytes */
|
||||
pkt_stat->drv_info_sz *= 8;
|
||||
|
||||
/* c2h cmd pkt's rx/phy status is not interested */
|
||||
if (pkt_stat->is_c2h)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (unlikely(pkt_stat->pkt_len <= FCS_LEN))
|
||||
return -EINVAL;
|
||||
|
||||
phy_status = rx_desc8 + desc_sz + pkt_stat->shift;
|
||||
hdr = phy_status + pkt_stat->drv_info_sz;
|
||||
|
|
@ -318,5 +327,7 @@ void rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8,
|
|||
rtwdev->chip->ops->query_phy_status(rtwdev, phy_status, pkt_stat);
|
||||
|
||||
rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rtw_rx_query_rx_desc);
|
||||
|
|
|
|||
|
|
@ -45,9 +45,9 @@ struct rtw_rx_desc {
|
|||
|
||||
void rtw_rx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
|
||||
struct sk_buff *skb);
|
||||
void rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8,
|
||||
struct rtw_rx_pkt_stat *pkt_stat,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
int rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8,
|
||||
struct rtw_rx_pkt_stat *pkt_stat,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
void rtw_update_rx_freq_from_ie(struct rtw_dev *rtwdev, struct sk_buff *skb,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct rtw_rx_pkt_stat *pkt_stat);
|
||||
|
|
|
|||
|
|
@ -995,7 +995,13 @@ static void rtw_sdio_rxfifo_recv(struct rtw_dev *rtwdev, u32 rx_len)
|
|||
|
||||
while (true) {
|
||||
rx_desc = skb->data;
|
||||
rtw_rx_query_rx_desc(rtwdev, rx_desc, &pkt_stat, &rx_status);
|
||||
ret = rtw_rx_query_rx_desc(rtwdev, rx_desc,
|
||||
&pkt_stat, &rx_status);
|
||||
if (ret) {
|
||||
dev_kfree_skb_any(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz +
|
||||
pkt_stat.shift;
|
||||
|
||||
|
|
|
|||
|
|
@ -619,8 +619,8 @@ static void rtw_usb_rx_handler(struct work_struct *work)
|
|||
u32 max_skb_len = pkt_desc_sz + PHY_STATUS_SIZE * 8 +
|
||||
IEEE80211_MAX_MPDU_LEN_VHT_11454;
|
||||
u32 pkt_offset, next_pkt, skb_len;
|
||||
int limit, ret;
|
||||
u8 *rx_desc;
|
||||
int limit;
|
||||
|
||||
for (limit = 0; limit < 200; limit++) {
|
||||
rx_skb = skb_dequeue(&rtwusb->rx_queue);
|
||||
|
|
@ -636,8 +636,11 @@ static void rtw_usb_rx_handler(struct work_struct *work)
|
|||
rx_desc = rx_skb->data;
|
||||
|
||||
do {
|
||||
rtw_rx_query_rx_desc(rtwdev, rx_desc, &pkt_stat,
|
||||
&rx_status);
|
||||
ret = rtw_rx_query_rx_desc(rtwdev, rx_desc,
|
||||
&pkt_stat, &rx_status);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz +
|
||||
pkt_stat.shift;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user