Coordinated Disclosure Timeline
- 2022-11-15: Email sent to security@kernel.org
- 2022-11-16: Patch series sent for review and testing to security@kernel.org
- 2022-11-23: Patch series sent to linux-wireless@vger.kernel.org
- 2022-12-04: Patches are included in Linux v6.1-rc8 and backported to the 6.0, 5.15 and 5.10 stable kernels
- 2022-12-16: CVE-2022-47518, CVE-2022-47519, CVE-2022-47520 and CVE-2022-47521 assigned
Summary
The Microchip WILC1000 802.11 wireless driver in the Linux kernel does not correctly validate information elements in management frames which can allow remote attackers to trigger memory corruption. In addition, the driver does not correctly validate Robust Security Network (RSN) elements when parsing netlink packets which can allow local users with the CAP_NET_ADMIN capability to trigger an out of bounds read and denial of service.
Product
Linux kernel
Tested Version
Details
Issue 1: Out of bounds read when parsing RSN elements (GHSL-2022-112, CVE-2022-47518)
Missing validation in wilc_parse_join_bss_param can trigger an out of bounds read when parsing a Robust Security Network (RSN) information element from a WiFi netlink packet:
void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
struct cfg80211_crypto_settings *crypto)
{
...
const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie;
int ret;
const struct cfg80211_bss_ies *ies = rcu_dereference(bss->ies);
...
rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len);
if (rsn_ie) {
int offset = 8;
param->mode_802_11i = 2;
param->rsn_found = true;
/* extract RSN capabilities */
offset += (rsn_ie[offset] * 4) + 2; // (a)
offset += (rsn_ie[offset] * 4) + 2; // (b)
memcpy(param->rsn_cap, &rsn_ie[offset], 2); // (c)
}
offset
is not validated after (a)
or (b)
which allows an attacker to trigger an out of bound read at (c)
. Both the expressions at (a)
and (b)
can advance offset up to 1022 bytes, so this can trigger an out of bounds read approximately ~2KB from rsn_ie
.
Impact
A denial of service can be triggered if rsn_ie[offset]
points to unmapped memory. The value stored in param->rsn_cap
is, seemingly, not read anywhere else so this bug cannot be used as an information leak.
This vulnerability can only be triggered locally by a user with CAP_NET_ADMIN
capabilities via the NL80211_CMD_CONNECT
netlink command.
Issue 2: Out of bounds read when parsing channel list from WFA vendor specific information elements (GHSL-2022-113, CVE-2022-47519)
The wilc_wfi_cfg_parse_ch_attr
function is called to handle vendor specific information elements, in particular the WLAN_OUI_TYPE_WFA_P2P
OUI type:
void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size)
{
...
vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P,
buff + ie_offset, size - ie_offset);
if (!vendor_ie)
goto out_rx_mgmt;
p = (struct wilc_vendor_specific_ie *)vendor_ie;
wilc_wfi_cfg_parse_ch_attr(p->attr, p->tag_len - 4, vif->wilc->sta_ch);
...
}
The content of the information element is parsed to extract the IEEE80211_P2P_ATTR_CHANNEL_LIST
attribute:
static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u32 len, u8 sta_ch)
{
struct wilc_attr_entry *e;
struct wilc_attr_ch_list *ch_list;
struct wilc_attr_oper_ch *op_ch;
u32 index = 0;
u8 ch_list_idx = 0;
u8 op_ch_idx = 0;
if (sta_ch == WILC_INVALID_CHANNEL)
return;
while (index + sizeof(*e) <= len) {
e = (struct wilc_attr_entry *)&buf[index];
if (e->attr_type == IEEE80211_P2P_ATTR_CHANNEL_LIST) // (a)
ch_list_idx = index;
else if (e->attr_type == IEEE80211_P2P_ATTR_OPER_CHANNEL)
op_ch_idx = index;
if (ch_list_idx && op_ch_idx)
break;
index += le16_to_cpu(e->attr_len) + sizeof(*e);
}
if (ch_list_idx) {
u16 attr_size;
struct wilc_ch_list_elem *e;
int i;
ch_list = (struct wilc_attr_ch_list *)&buf[ch_list_idx];
attr_size = le16_to_cpu(ch_list->attr_len); // (b)
for (i = 0; i < attr_size;) {
e = (struct wilc_ch_list_elem *)(ch_list->elem + i); // (c)
if (e->op_class == WILC_WLAN_OPERATING_CLASS_2_4GHZ) { // (d)
...
The e->attr_len
field is not validated at (a)
to ensure that it is large enough to contain a valid IEEE80211_P2P_ATTR_CHANNEL_LIST
attribute. The unvalidated attr_len
field is then used at (b)
and (c)
to find a channel within the IEEE80211_P2P_ATTR_CHANNEL_LIST
attribute. This can trigger an out of bounds read at (d)
.
Impact
The wilc_wfi_cfg_parse_ch_attr
function processes data from WiFi frames so this vulnerability can be triggered remotely. The attr_len
field is a 16-bit length so this vulnerability can trigger an out of bounds read up to ~65KB from buf
. This could cause a denial of service if it reads unmapped memory.
Issue 3: Out of bounds write when parsing channel attribute from WFA vendor specific information elements (GHSL-2022-114, CVE-2022-47520)
Similar to issue 2, the wilc_wfi_cfg_parse_ch_attr
function extracts a IEEE80211_P2P_ATTR_OPER_CHANNEL
attribute from a WLAN_OUI_TYPE_WFA_P2P
information element:
static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u32 len, u8 sta_ch)
{
struct wilc_attr_entry *e;
struct wilc_attr_ch_list *ch_list;
struct wilc_attr_oper_ch *op_ch;
u32 index = 0;
u8 ch_list_idx = 0;
u8 op_ch_idx = 0;
if (sta_ch == WILC_INVALID_CHANNEL)
return;
while (index + sizeof(*e) <= len) {
e = (struct wilc_attr_entry *)&buf[index];
if (e->attr_type == IEEE80211_P2P_ATTR_CHANNEL_LIST)
ch_list_idx = index;
else if (e->attr_type == IEEE80211_P2P_ATTR_OPER_CHANNEL) // (a)
op_ch_idx = index;
if (ch_list_idx && op_ch_idx)
break;
index += le16_to_cpu(e->attr_len) + sizeof(*e);
}
...
if (op_ch_idx) {
op_ch = (struct wilc_attr_oper_ch *)&buf[op_ch_idx];
op_ch->op_class = WILC_WLAN_OPERATING_CLASS_2_4GHZ; // (b)
op_ch->op_channel = sta_ch; // (c)
}
}
The e->attr_len
field is not validated at (a)
to ensure that it is large enough to valid IEEE80211_P2P_ATTR_OPER_CHANNEL
attribute. An out of bounds write at (b)
and (c)
can then be triggered.
Impact
This can trigger a one- or two-byte heap buffer overflow. The values written are WILC_WLAN_OPERATING_CLASS_2_4GHZ
(0x51) and sta_ch
which is not directly attacker controlled but is derived from the frequency of the air interface.
Issue 4: Out of bounds write when parsing channel list from WFA vendor specific information elements (GHSL-2022-115, CVE-2022-47521)
The wilc_wfi_cfg_parse_ch_attr
function extracts a IEEE80211_P2P_ATTR_CHANNEL_LIST
attribute:
static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u32 len, u8 sta_ch)
{
struct wilc_attr_entry *e;
struct wilc_attr_ch_list *ch_list;
struct wilc_attr_oper_ch *op_ch;
u32 index = 0;
u8 ch_list_idx = 0;
u8 op_ch_idx = 0;
if (sta_ch == WILC_INVALID_CHANNEL)
return;
while (index + sizeof(*e) <= len) {
e = (struct wilc_attr_entry *)&buf[index];
if (e->attr_type == IEEE80211_P2P_ATTR_CHANNEL_LIST)
ch_list_idx = index;
...
}
if (ch_list_idx) {
u16 attr_size;
struct wilc_ch_list_elem *e;
int i;
ch_list = (struct wilc_attr_ch_list *)&buf[ch_list_idx]; // (a)
attr_size = le16_to_cpu(ch_list->attr_len);
for (i = 0; i < attr_size;) { // (b)
e = (struct wilc_ch_list_elem *)(ch_list->elem + i);
if (e->op_class == WILC_WLAN_OPERATING_CLASS_2_4GHZ) {
memset(e->ch_list, sta_ch, e->no_of_channels); // (c)
break;
}
i += e->no_of_channels;
}
}
The channel list is parsed from the attribute at (a)
and the code then loops over each channel list element at (b)
. e->ch_list
is a variable length array which should contain e->no_of_channels
elements. There is no validation that &e->ch_list + e->no_of_channels
does not extend beyond the end of buf
which can cause an out of bound write at (c)
.
Impact
An attacker can trigger heap corruption by providing a malformed no_of_channels
value. no_of_channels
is a u8
so an attacker can corrupt ~256 bytes following buf
. The value written, sta_ch
, is not directly under attacker control but is derived from the frequency of the air interface.
Credit
These issues were discovered and reported by GHSL team member @philipturnbull.
Contact
You can contact the GHSL team at securitylab@github.com
, please include a reference to GHSL-2022-112
, GHSL-2022-113
,GHSL-2022-114
or GHSL-2022-115
in any communication regarding these issues.