Supplicant: Add bound check for pmk length and serialized data
When PMK length in setPmkCacheInternal() function deserializes the
input PMK bytes to supplicant rsn_pmk_cache_entry without checking
the input PMK length along with size of input PMK bytes, it results
in an Out-of-Bounds write memory access, causing memory corruption.
Fixes:
1. Adding check for invalid pmk length.
2. A specific size check is added in deserializePmkCacheEntry()
function, where we are checking size of serializedEntry to the size
of rsn_pmksa_cache_entry structure. If it is less, the invalid input
is rejected and an error message is returned.
Change-Id: I8e80734820e51b018ac63a7bfd5674482be958ee
Bug: 263834889
Test: Manual - connect/disconnect with WPA3 AP and confirmed
that open authentication with PMK cache works.
diff --git a/wpa_supplicant/aidl/misc_utils.h b/wpa_supplicant/aidl/misc_utils.h
index 5c5b68c..c529e3d 100644
--- a/wpa_supplicant/aidl/misc_utils.h
+++ b/wpa_supplicant/aidl/misc_utils.h
@@ -100,10 +100,21 @@
return ss;
}
-inline std::stringstream& deserializePmkCacheEntry(
+inline std::int8_t deserializePmkCacheEntry(
std::stringstream &ss, struct rsn_pmksa_cache_entry *pmksa_entry) {
ss.seekg(0);
+ if (ss.str().size() < sizeof(pmksa_entry->pmk_len)) {
+ return -1;
+ }
+
ss.read((char *) &pmksa_entry->pmk_len, sizeof(pmksa_entry->pmk_len));
+ if ((pmksa_entry->pmk_len > PMK_LEN_MAX) ||
+ (ss.str().size() < (sizeof(pmksa_entry->pmk_len) + pmksa_entry->pmk_len +
+ PMKID_LEN + ETH_ALEN + sizeof(pmksa_entry->akmp) +
+ sizeof(pmksa_entry->reauth_time) + sizeof(pmksa_entry->expiration) +
+ sizeof(pmksa_entry->opportunistic) + 1 /* fils_cache_id_set */)))
+ return -1;
+
ss.read((char *) pmksa_entry->pmk, pmksa_entry->pmk_len);
ss.read((char *) pmksa_entry->pmkid, PMKID_LEN);
ss.read((char *) pmksa_entry->aa, ETH_ALEN);
@@ -115,8 +126,13 @@
char byte = 0;
ss.read((char *) &byte, sizeof(byte));
pmksa_entry->fils_cache_id_set = (byte) ? 1 : 0;
+ if (pmksa_entry->fils_cache_id_set == 1) {
+ if((ss.str().size() - static_cast<uint32_t>(ss.tellg())) < FILS_CACHE_ID_LEN)
+ return -1;
+ }
+
ss.read((char *) pmksa_entry->fils_cache_id, FILS_CACHE_ID_LEN);
- return ss;
+ return 0;
}
} // namespace misc_utils
} // namespace supplicant
diff --git a/wpa_supplicant/aidl/sta_network.cpp b/wpa_supplicant/aidl/sta_network.cpp
index db13509..5a83b05 100644
--- a/wpa_supplicant/aidl/sta_network.cpp
+++ b/wpa_supplicant/aidl/sta_network.cpp
@@ -2158,7 +2158,11 @@
std::stringstream ss(
std::stringstream::in | std::stringstream::out | std::stringstream::binary);
ss.write((char *) serializedEntry.data(), std::streamsize(serializedEntry.size()));
- misc_utils::deserializePmkCacheEntry(ss, new_entry);
+ if (misc_utils::deserializePmkCacheEntry(ss, new_entry) < 0) {
+ os_free(new_entry);
+ return createStatusWithMsg(SupplicantStatusCode::FAILURE_ARGS_INVALID,
+ "Invalid pmk length");
+ }
new_entry->network_ctx = wpa_ssid;
// If there is an entry has a later expiration, ignore this one.