Coordinated Disclosure Timeline

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.