mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
wifi: mwifiex: bound the pairwise-cipher OUI walk to the IE length
mwifiex_search_oui_in_ie() reads a pairwise-cipher (PTK) count from a
beacon/probe-response RSN or WPA information element and then walks that
many 4-byte OUIs, comparing each with memcmp(). The count comes straight
from the (attacker-supplied) IE and is never checked against the
element's own length, and the callers admit the element on element_id
alone (has_ieee_hdr() / has_vendor_hdr(), no length check). A crafted
RSN/WPA IE with a large pairwise count therefore makes the walk read up
to 255 * 4 bytes past the element -- an out-of-bounds read of the
kmemdup()'d beacon buffer, reachable from any AP whose beacon/probe
response is processed during scan-result parsing.
Pass the number of IE bytes available at the OUI list and bound the walk
to the element. Keep the length signed and reject a negative value
before any unsigned arithmetic, so a small or zero IE length cannot
underflow to a large size_t and defeat the bound.
Found by 0sec automated security-research tooling (https://0sec.ai).
Fixes: 5e6e3a92b9 ("wireless: mwifiex: initial commit for Marvell mwifiex driver")
Cc: stable@vger.kernel.org
Assisted-by: 0sec:multi-model
Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
Link: https://patch.msgid.link/20260814134704.85902-1-doruk@0sec.ai
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
e2de8d5eb2
commit
e667aee1c1
|
|
@ -104,12 +104,24 @@ has_vendor_hdr(struct ieee_types_vendor_specific *ie, u8 key)
|
|||
* a given oui in PTK.
|
||||
*/
|
||||
static u8
|
||||
mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui)
|
||||
mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui, int ie_len)
|
||||
{
|
||||
const size_t ptk_body_offset = offsetof(struct ie_body, ptk_body);
|
||||
u8 count;
|
||||
|
||||
/* ie_len is the number of bytes available at iebody. Keep it signed
|
||||
* and reject a negative (underflowed) length before the unsigned
|
||||
* comparisons below, so a small or zero IE length cannot wrap.
|
||||
*/
|
||||
if (ie_len < 0 || (size_t)ie_len < ptk_body_offset)
|
||||
return MWIFIEX_OUI_NOT_PRESENT;
|
||||
|
||||
count = iebody->ptk_cnt[0];
|
||||
|
||||
/* Reject an OUI count whose list would run past the element. */
|
||||
if (ptk_body_offset + count * sizeof(iebody->ptk_body) > (size_t)ie_len)
|
||||
return MWIFIEX_OUI_NOT_PRESENT;
|
||||
|
||||
/* There could be multiple OUIs for PTK hence
|
||||
1) Take the length.
|
||||
2) Check all the OUIs for AES.
|
||||
|
|
@ -143,11 +155,14 @@ mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
|
|||
u8 ret = MWIFIEX_OUI_NOT_PRESENT;
|
||||
|
||||
if (has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN)) {
|
||||
int ie_len = (int)bss_desc->bcn_rsn_ie->ieee_hdr.len -
|
||||
RSN_GTK_OUI_OFFSET;
|
||||
|
||||
iebody = (struct ie_body *)
|
||||
(((u8 *) bss_desc->bcn_rsn_ie->data) +
|
||||
RSN_GTK_OUI_OFFSET);
|
||||
oui = &mwifiex_rsn_oui[cipher][0];
|
||||
ret = mwifiex_search_oui_in_ie(iebody, oui);
|
||||
ret = mwifiex_search_oui_in_ie(iebody, oui, ie_len);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -169,10 +184,14 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
|
|||
u8 ret = MWIFIEX_OUI_NOT_PRESENT;
|
||||
|
||||
if (has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC)) {
|
||||
int ie_len = (int)bss_desc->bcn_wpa_ie->vend_hdr.len -
|
||||
(int)sizeof(bss_desc->bcn_wpa_ie->vend_hdr.oui) -
|
||||
WPA_GTK_OUI_OFFSET;
|
||||
|
||||
iebody = (struct ie_body *)((u8 *)bss_desc->bcn_wpa_ie->data +
|
||||
WPA_GTK_OUI_OFFSET);
|
||||
oui = &mwifiex_wpa_oui[cipher][0];
|
||||
ret = mwifiex_search_oui_in_ie(iebody, oui);
|
||||
ret = mwifiex_search_oui_in_ie(iebody, oui, ie_len);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user