wifi: ipw2x00: bound management frame length to the receive buffer

Both management receive paths establish a lower bound on the frame
length and no upper bound, even though the length originates from the
device.

ipw2100_corruption_check() returns 0 without inspecting frame_size for
management frames, and __ipw2100_rx_process() only rejects a frame
smaller than the three-address header, so any reported size up to the
u32 limit reaches libipw_rx_mgt() against a receive allocation of
IPW_RX_NIC_BUFFER_LENGTH bytes.  Check frame_size itself rather than
stats.len, which is a u16: a size of 65566 truncates to 30 on
assignment and would pass a check made afterwards.

ipw_rx() likewise only rejects a frame shorter than the header length.
Bound it against the DMA mapped receive buffer.  The size passed to
alloc_skb() is rounded up by the allocator, so skb_tailroom() can
exceed IPW_RX_BUF_SIZE and is not a usable bound here; the existing
uses of that idiom in the data paths are too permissive for the same
reason.

libipw then hands the remainder to libipw_parse_info_param(), which
walks information elements for as long as the length allows, so an
over-long reported length reads past the receive buffer without any
wraparound being involved.

The length is device-reported, so per
Documentation/process/threat-model.rst this is a robustness fix rather
than a vulnerability.

Found by an AI-assisted review of length arithmetic in management frame
parsers.  Compile-tested only for these two hunks; I do not have the
hardware, so they are not tested on a real device.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Shmulik Cohen <anuk909@gmail.com>
Link: https://patch.msgid.link/20260812190412.18333-4-anuk909@gmail.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Shmulik Cohen 2026-08-12 22:04:12 +03:00 committed by Johannes Berg
parent adb7118b7d
commit c46cfaf8db
2 changed files with 12 additions and 1 deletions

View File

@ -2712,7 +2712,9 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv)
break;
}
#endif
if (stats.len < sizeof(struct libipw_hdr_3addr))
if (sq->drv[i].frame_size <
sizeof(struct libipw_hdr_3addr) ||
sq->drv[i].frame_size > IPW_RX_NIC_BUFFER_LENGTH)
break;
switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
case IEEE80211_FTYPE_MGMT:

View File

@ -8322,6 +8322,15 @@ static void ipw_rx(struct ipw_priv *priv)
break;
}
if (unlikely(le16_to_cpu(pkt->u.frame.length) >
IPW_RX_BUF_SIZE -
IPW_RX_FRAME_SIZE)) {
IPW_DEBUG_DROP("Received oversized packet. Dropping.\n");
priv->net_dev->stats.rx_errors++;
priv->wstats.discard.misc++;
break;
}
switch (WLAN_FC_GET_TYPE
(le16_to_cpu(header->frame_ctl))) {