Takashi Iwai bab6e5
From: Johannes Berg <johannes.berg@intel.com>
Takashi Iwai bab6e5
Date: Wed, 28 Sep 2022 22:07:15 +0200
Takashi Iwai bab6e5
Subject: [PATCH 3/9] wifi: mac80211: fix MBSSID parsing use-after-free
Takashi Iwai bab6e5
Patch-mainline: Not yet, embargoed
Takashi Iwai bab6e5
References: CVE-2022-42719 bsc#1204051
Takashi Iwai bab6e5
Takashi Iwai bab6e5
When we parse a multi-BSSID element, we might point some
Takashi Iwai bab6e5
element pointers into the allocated nontransmitted_profile.
Takashi Iwai bab6e5
However, we free this before returning, causing UAF when the
Takashi Iwai bab6e5
relevant pointers in the parsed elements are accessed.
Takashi Iwai bab6e5
Takashi Iwai bab6e5
Fix this by not allocating the scratch buffer separately but
Takashi Iwai bab6e5
as part of the returned structure instead, that way, there
Takashi Iwai bab6e5
are no lifetime issues with it.
Takashi Iwai bab6e5
Takashi Iwai bab6e5
The scratch buffer introduction as part of the returned data
Takashi Iwai bab6e5
here is taken from MLO feature work done by Ilan.
Takashi Iwai bab6e5
Takashi Iwai bab6e5
This fixes CVE-2022-42719.
Takashi Iwai bab6e5
Takashi Iwai bab6e5
Fixes: 5023b14cf4df ("mac80211: support profile split between elements")
Takashi Iwai bab6e5
Co-developed-by: Ilan Peer <ilan.peer@intel.com>
Takashi Iwai bab6e5
Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Takashi Iwai bab6e5
Reviewed-by: Kees Cook <keescook@chromium.org>
Takashi Iwai bab6e5
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Takashi Iwai bab6e5
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai bab6e5
Takashi Iwai bab6e5
---
Takashi Iwai bab6e5
 net/mac80211/ieee80211_i.h |    8 ++++++++
Takashi Iwai bab6e5
 net/mac80211/util.c        |   32 ++++++++++++++++----------------
Takashi Iwai bab6e5
 2 files changed, 24 insertions(+), 16 deletions(-)
Takashi Iwai bab6e5
Takashi Iwai bab6e5
--- a/net/mac80211/ieee80211_i.h
Takashi Iwai bab6e5
+++ b/net/mac80211/ieee80211_i.h
Takashi Iwai bab6e5
@@ -1601,6 +1601,14 @@ struct ieee802_11_elems {
Takashi Iwai bab6e5
 
Takashi Iwai bab6e5
 	/* whether a parse error occurred while retrieving these elements */
Takashi Iwai bab6e5
 	bool parse_error;
Takashi Iwai bab6e5
+
Takashi Iwai bab6e5
+	/*
Takashi Iwai bab6e5
+	 * scratch buffer that can be used for various element parsing related
Takashi Iwai bab6e5
+	 * tasks, e.g., element de-fragmentation etc.
Takashi Iwai bab6e5
+	 */
Takashi Iwai bab6e5
+	size_t scratch_len;
Takashi Iwai bab6e5
+	u8 *scratch_pos;
Takashi Iwai bab6e5
+	u8 scratch[];
Takashi Iwai bab6e5
 };
Takashi Iwai bab6e5
 
Takashi Iwai bab6e5
 static inline struct ieee80211_local *hw_to_local(
Takashi Iwai bab6e5
--- a/net/mac80211/util.c
Takashi Iwai bab6e5
+++ b/net/mac80211/util.c
Takashi Iwai bab6e5
@@ -1459,26 +1459,28 @@ ieee802_11_parse_elems_full(struct ieee8
Takashi Iwai bab6e5
 	const struct element *non_inherit = NULL;
Takashi Iwai bab6e5
 	u8 *nontransmitted_profile;
Takashi Iwai bab6e5
 	int nontransmitted_profile_len = 0;
Takashi Iwai bab6e5
+	size_t scratch_len = params->len;
Takashi Iwai bab6e5
 
Takashi Iwai bab6e5
-	elems = kzalloc(sizeof(*elems), GFP_ATOMIC);
Takashi Iwai bab6e5
+	elems = kzalloc(sizeof(*elems) + scratch_len, GFP_ATOMIC);
Takashi Iwai bab6e5
 	if (!elems)
Takashi Iwai bab6e5
 		return NULL;
Takashi Iwai bab6e5
 	elems->ie_start = params->start;
Takashi Iwai bab6e5
 	elems->total_len = params->len;
Takashi Iwai bab6e5
+	elems->scratch_len = scratch_len;
Takashi Iwai bab6e5
+	elems->scratch_pos = elems->scratch;
Takashi Iwai bab6e5
 
Takashi Iwai bab6e5
-	nontransmitted_profile = kmalloc(params->len, GFP_ATOMIC);
Takashi Iwai bab6e5
-	if (nontransmitted_profile) {
Takashi Iwai bab6e5
-		nontransmitted_profile_len =
Takashi Iwai bab6e5
-			ieee802_11_find_bssid_profile(params->start, params->len,
Takashi Iwai bab6e5
-						      elems,
Takashi Iwai bab6e5
-						      params->transmitter_bssid,
Takashi Iwai bab6e5
-						      params->bss_bssid,
Takashi Iwai bab6e5
-						      nontransmitted_profile);
Takashi Iwai bab6e5
-		non_inherit =
Takashi Iwai bab6e5
-			cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
Takashi Iwai bab6e5
-					       nontransmitted_profile,
Takashi Iwai bab6e5
-					       nontransmitted_profile_len);
Takashi Iwai bab6e5
-	}
Takashi Iwai bab6e5
+	nontransmitted_profile = elems->scratch_pos;
Takashi Iwai bab6e5
+	nontransmitted_profile_len =
Takashi Iwai bab6e5
+		ieee802_11_find_bssid_profile(params->start, params->len,
Takashi Iwai bab6e5
+					      elems,
Takashi Iwai bab6e5
+					      params->transmitter_bssid,
Takashi Iwai bab6e5
+					      params->bss_bssid,
Takashi Iwai bab6e5
+					      nontransmitted_profile);
Takashi Iwai bab6e5
+	elems->scratch_pos += nontransmitted_profile_len;
Takashi Iwai bab6e5
+	elems->scratch_len -= nontransmitted_profile_len;
Takashi Iwai bab6e5
+	non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
Takashi Iwai bab6e5
+					     nontransmitted_profile,
Takashi Iwai bab6e5
+					     nontransmitted_profile_len);
Takashi Iwai bab6e5
 
Takashi Iwai bab6e5
 	elems->crc = _ieee802_11_parse_elems_full(params, elems, non_inherit);
Takashi Iwai bab6e5
 
Takashi Iwai bab6e5
@@ -1511,8 +1513,6 @@ ieee802_11_parse_elems_full(struct ieee8
Takashi Iwai bab6e5
 	    offsetofend(struct ieee80211_bssid_index, dtim_count))
Takashi Iwai bab6e5
 		elems->dtim_count = elems->bssid_index->dtim_count;
Takashi Iwai bab6e5
 
Takashi Iwai bab6e5
-	kfree(nontransmitted_profile);
Takashi Iwai bab6e5
-
Takashi Iwai bab6e5
 	return elems;
Takashi Iwai bab6e5
 }
Takashi Iwai bab6e5