Merge branch 'bugfix/invalid_memory_access_supplicant_v6.0' into 'release/v6.0'

fix(esp_wifi): Fix some invalid memory access (v6.0)

See merge request espressif/esp-idf!44273
This commit is contained in:
Jiang Jiang Jian
2026-01-08 20:11:29 +08:00
8 changed files with 92 additions and 63 deletions
@@ -832,6 +832,7 @@ static void periodic_scan_roam(struct timeval *now)
roaming_app_get_ap_info(&g_roaming_app.current_bss.ap);
ESP_LOGD(ROAMING_TAG, "Connected AP's RSSI=%d", g_roaming_app.current_bss.ap.rssi);
if (g_roaming_app.current_bss.ap.rssi > g_roaming_app.config.scan_rssi_threshold) {
ESP_LOGD(ROAMING_TAG, "Not going for scan, Scan RSSI threshold=%d", g_roaming_app.config.scan_rssi_threshold);
return;
}
@@ -255,31 +255,6 @@ cleanup:
return res;
}
int crypto_bignum_to_string(const struct crypto_bignum *a,
u8 *buf, size_t buflen, size_t padlen)
{
int num_bytes, offset;
size_t outlen;
if (padlen > buflen) {
return -1;
}
num_bytes = mbedtls_mpi_size((mbedtls_mpi *) a);
if (padlen > (size_t) num_bytes) {
offset = padlen - num_bytes;
} else {
offset = 0;
}
os_memset(buf, 0, offset);
mbedtls_mpi_write_string((mbedtls_mpi *) a, 16, (char *)(buf + offset),
mbedtls_mpi_size((mbedtls_mpi *)a), &outlen);
return outlen;
}
int crypto_bignum_addmod(const struct crypto_bignum *a,
const struct crypto_bignum *b,
const struct crypto_bignum *c,
@@ -169,6 +169,9 @@ static int handle_assoc_frame(u8 *frame, size_t len,
u8 *sender, int8_t rssi, u8 channel)
{
if (gWpaSm.key_mgmt == WPA_KEY_MGMT_FT_PSK || gWpaSm.key_mgmt == WPA_KEY_MGMT_FT_SAE) {
if (len < 6) { /* Cap info + status code */
return -1;
}
if (gWpaSm.ft_protocol) {
if (wpa_ft_validate_reassoc_resp(&gWpaSm, frame + 6, len - 6, sender)) {
wpa_sm_set_ft_params(&gWpaSm, NULL, 0);
@@ -385,6 +385,10 @@ static esp_err_t esp_dpp_rx_peer_disc_resp(struct action_rx_param *rx_param)
return ESP_ERR_INVALID_ARG;
}
if (rx_param->vendor_data_len < 2) {
wpa_printf(MSG_INFO, "DPP: Too short vendor specific data");
return ESP_FAIL;
}
size_t len = rx_param->vendor_data_len - 2;
buf = rx_param->action_frm->u.public_action.v.pa_vendor_spec.vendor_data;
@@ -519,28 +523,38 @@ static esp_err_t gas_query_resp_rx(struct action_rx_param *rx_param)
{
struct dpp_authentication *auth = s_dpp_ctx.dpp_auth;
uint8_t *pos = rx_param->action_frm->u.public_action.v.pa_gas_resp.data;
uint8_t *resp = &pos[10];
uint8_t *resp = &pos[10]; /* first byte of DPP attributes */
size_t vendor_len = rx_param->vendor_data_len;
int i, res;
if (pos[1] == WLAN_EID_VENDOR_SPECIFIC && pos[2] == 5 &&
WPA_GET_BE24(&pos[3]) == OUI_WFA && pos[6] == 0x1a && pos[7] == 1 && auth) {
/* Basic structural checks on the Advertisement Protocol payload */
if (!(pos[1] == WLAN_EID_VENDOR_SPECIFIC && pos[2] == 5 &&
WPA_GET_BE24(&pos[3]) == OUI_WFA && pos[6] == 0x1a && pos[7] == 1 && auth)) {
wpa_hexdump(MSG_INFO, "DPP: Failed, Configuration Response adv_proto", pos, 8);
return ESP_OK;
}
eloop_cancel_timeout(gas_query_timeout, NULL, auth);
if (dpp_conf_resp_rx(auth, resp, rx_param->vendor_data_len - 2) < 0) {
wpa_printf(MSG_INFO, "DPP: Configuration attempt failed");
/* DPP attribute length = vendor_data_len - 2, caller validated vendor_data_len
* (we skip the 2-byte length field and pass only the attributes). */
size_t dpp_data_len = vendor_len - 2;
eloop_cancel_timeout(gas_query_timeout, NULL, auth);
if (dpp_conf_resp_rx(auth, resp, dpp_data_len) < 0) {
wpa_printf(MSG_INFO, "DPP: Configuration attempt failed");
goto fail;
}
for (i = 0; i < auth->num_conf_obj; i++) {
res = esp_dpp_handle_config_obj(auth, &auth->conf_obj[i]);
if (res < 0) {
wpa_printf(MSG_INFO, "DPP: Configuration parsing failed");
goto fail;
}
for (i = 0; i < auth->num_conf_obj; i++) {
res = esp_dpp_handle_config_obj(auth, &auth->conf_obj[i]);
if (res < 0) {
wpa_printf(MSG_INFO, "DPP: Configuration parsing failed");
goto fail;
}
}
}
return ESP_OK;
fail:
return ESP_FAIL;
}
@@ -821,11 +835,17 @@ static char *esp_dpp_parse_chan_list(const char *chan_list)
}
char *uri_ptr = uri_channels;
size_t current_offset = 0; // Use an offset to track current position
params->num_chan = 0;
/* Append " chan=" at the beginning of the URI */
strcpy(uri_ptr, " chan=");
uri_ptr += strlen(" chan=");
int written = os_snprintf(uri_ptr + current_offset, max_uri_len - current_offset, " chan=");
if (written < 0 || written >= max_uri_len - current_offset) { // Check for error or truncation
wpa_printf(MSG_ERROR, "DPP: URI buffer too small for initial string");
os_free(uri_channels);
return NULL;
}
current_offset += written;
while (*chan_list && params->num_chan < ESP_DPP_MAX_CHAN_COUNT) {
int channel = 0;
@@ -860,16 +880,23 @@ static char *esp_dpp_parse_chan_list(const char *chan_list)
/* Add the valid channel to the list */
params->chan_list[params->num_chan++] = channel;
/* Check if there's space left in uri_channels buffer */
size_t remaining_space = max_uri_len - (uri_ptr - uri_channels);
if (remaining_space <= 8) { // Oper class + "/" + channel + "," + null terminator
wpa_printf(MSG_ERROR, "DPP: Not enough space in URI buffer");
// Calculate space needed for current channel string (e.g., "81/1,")
int needed_for_channel = os_snprintf(NULL, 0, "%d/%d,", oper_class, channel);
if (current_offset + needed_for_channel + 1 > max_uri_len) { // +1 for null terminator
wpa_printf(MSG_ERROR, "DPP: Not enough space in URI buffer for channel %d", channel);
os_free(uri_channels);
return NULL;
}
/* Append the operating class and channel to the URI */
uri_ptr += sprintf(uri_ptr, "%d/%d,", oper_class, channel);
written = os_snprintf(uri_ptr + current_offset, max_uri_len - current_offset, "%d/%d,", oper_class, channel);
if (written < 0 || written >= max_uri_len - current_offset) { // Check for error or truncation
wpa_printf(MSG_ERROR, "DPP: Error writing channel %d to URI buffer", channel);
os_free(uri_channels);
return NULL;
}
current_offset += written;
/* Skip any delimiters (comma or space) */
while (*chan_list == ',' || *chan_list == ' ') {
@@ -884,8 +911,8 @@ static char *esp_dpp_parse_chan_list(const char *chan_list)
}
/* Replace the last comma with a space if there was content added */
if (uri_ptr > uri_channels && *(uri_ptr - 1) == ',') {
*(uri_ptr - 1) = ' ';
if (current_offset > strlen(" chan=") && uri_ptr[current_offset - 1] == ',') {
uri_ptr[current_offset - 1] = ' ';
}
return uri_channels;
@@ -214,7 +214,8 @@ void *hostap_init(void)
}
#endif /* CONFIG_SAE */
os_memcpy(hapd->conf->ssid.wpa_passphrase, esp_wifi_ap_get_prof_password_internal(), strlen((char *)esp_wifi_ap_get_prof_password_internal()));
os_snprintf(hapd->conf->ssid.wpa_passphrase, WIFI_PASSWORD_LEN_MAX,
"%s", esp_wifi_ap_get_prof_password_internal());
hapd->conf->ssid.wpa_passphrase[WIFI_PASSWORD_LEN_MAX - 1] = '\0';
hapd->conf->max_num_sta = esp_wifi_ap_get_max_sta_conn();
auth_conf->transition_disable = esp_wifi_ap_get_transition_disable_internal();
@@ -343,8 +343,16 @@ static int wpa3_parse_sae_commit(u8 *buf, u32 len, u16 status)
wpa_printf(MSG_ERROR, "Invalid SAE anti-clogging token container header");
return ESP_FAIL;
}
if (len < 5) {
wpa_printf(MSG_ERROR, "Invalid SAE anti-clogging token length");
return ESP_FAIL;
}
g_sae_token = wpabuf_alloc_copy(buf + 5, len - 5);
} else {
if (len < 2) {
wpa_printf(MSG_ERROR, "Invalid SAE anti-clogging token length");
return ESP_FAIL;
}
g_sae_token = wpabuf_alloc_copy(buf + 2, len - 2);
}
return ESP_OK;
@@ -389,8 +389,8 @@ static int wps_enrollee_process_msg_frag(struct wpabuf **buf, int tot_len, u8 *f
identifier = sm->current_identifier;
if (*buf == NULL) {
if (0 == (flag & WPS_MSG_FLAG_LEN) || tot_len < frag_len) {
wpa_printf(MSG_ERROR, "WPS: %s: Invalid fragment flag: 0x%02x", __FUNCTION__, flag);
if (frag_len < 0 || tot_len < frag_len) {
wpa_printf(MSG_ERROR, "WPS: Invalid first fragment length");
return ESP_FAIL;
}
@@ -405,9 +405,17 @@ static int wps_enrollee_process_msg_frag(struct wpabuf **buf, int tot_len, u8 *f
if (flag & WPS_MSG_FLAG_LEN) {
wpa_printf(MSG_ERROR, "WPS: %s: Invalid fragment flag: 0x%02x", __func__, flag);
wpabuf_free(*buf);
*buf = NULL;
return ESP_FAIL;
}
if (frag_len < 0 || wpabuf_len(*buf) + frag_len > tot_len) {
wpa_printf(MSG_ERROR, "WPS: Invalid subsequent fragment length");
wpabuf_free(*buf);
*buf = NULL;
return ESP_FAIL;
}
wpabuf_put_data(*buf, frag_data, frag_len);
if (flag & WPS_MSG_FLAG_MORE) {
@@ -445,6 +453,10 @@ static int wps_process_wps_mX_req(u8 *ubuf, int len, enum wps_process_res *res)
return ESP_FAIL;
}
if (len < (int)(sizeof(struct eap_expand) + 1)) {
wpa_printf(MSG_ERROR, "WPS: Truncated EAP-Expanded header");
return ESP_FAIL;
}
expd = (struct eap_expand *) ubuf;
wpa_printf(MSG_DEBUG, "WPS: Processing WSC message (len=%d, total_len=%d)", len, tlen);
@@ -463,7 +475,11 @@ static int wps_process_wps_mX_req(u8 *ubuf, int len, enum wps_process_res *res)
flag = *(u8 *)(ubuf + sizeof(struct eap_expand));
if (flag & WPS_MSG_FLAG_LEN) {
tbuf = ubuf + sizeof(struct eap_expand) + 1 + 2;//two bytes total length
if (len < (int)(sizeof(struct eap_expand) + 1 + 2)) {
wpa_printf(MSG_ERROR, "WPS: Missing total length field");
return ESP_FAIL;
}
tbuf = ubuf + sizeof(struct eap_expand) + 1 + 2; // includes 2-byte total length
frag_len = len - (sizeof(struct eap_expand) + 1 + 2);
be_tot_len = *(u16 *)(ubuf + sizeof(struct eap_expand) + 1);
tlen = ((be_tot_len & 0xff) << 8) | ((be_tot_len >> 8) & 0xff);
@@ -473,6 +489,15 @@ static int wps_process_wps_mX_req(u8 *ubuf, int len, enum wps_process_res *res)
tlen = frag_len;
}
if (frag_len < 0 || tlen < 0 || ((flag & WPS_MSG_FLAG_LEN) && tlen < frag_len)) {
wpa_printf(MSG_ERROR, "WPS: Invalid fragment sizes");
if (wps_buf) {
wpabuf_free(wps_buf);
wps_buf = NULL;
}
return ESP_FAIL;
}
if (tlen > 50000) {
wpa_printf(MSG_ERROR, "WPS: Invalid EAP-WSC message length");
return ESP_FAIL;
@@ -1153,17 +1153,6 @@ void crypto_free_buffer(unsigned char *buf);
*/
int crypto_ec_get_priv_key_der(struct crypto_ec_key *key, unsigned char **key_data, int *key_len);
/**
* crypto_bignum_to_string: get big number in ascii format
* @a: big number
* @buf: buffer in which number will written to
* @buflen: buffer length
* @padlen: padding length
* Return : 0 if success
*/
int crypto_bignum_to_string(const struct crypto_bignum *a,
u8 *buf, size_t buflen, size_t padlen);
struct crypto_ecdh;
void crypto_ecdh_deinit(struct crypto_ecdh *ecdh);