Fix hostapd initialization error path on allocation failure

If hostapd_alloc_bss_data() failed to allocate the struct hostapd_data
instance, dynamic interface addition path ended up trying to dereference
freed memory due to incorrect cleanup steps. Fix this by decrementing
the interface count when the newly added interface is removed. In
addition, make the setup more robust by clearing all changes within
hostapd_data_alloc() if any of the allocations fails.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2015-01-05 21:57:15 +02:00
parent d58ade2121
commit 2801659268

View file

@ -1872,33 +1872,37 @@ hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
} }
static struct hostapd_iface * hostapd_data_alloc( static int hostapd_data_alloc(struct hostapd_iface *hapd_iface,
struct hapd_interfaces *interfaces, struct hostapd_config *conf) struct hostapd_config *conf)
{ {
size_t i; size_t i;
struct hostapd_iface *hapd_iface =
interfaces->iface[interfaces->count - 1];
struct hostapd_data *hapd; struct hostapd_data *hapd;
hapd_iface->conf = conf;
hapd_iface->num_bss = conf->num_bss;
hapd_iface->bss = os_calloc(conf->num_bss, hapd_iface->bss = os_calloc(conf->num_bss,
sizeof(struct hostapd_data *)); sizeof(struct hostapd_data *));
if (hapd_iface->bss == NULL) if (hapd_iface->bss == NULL)
return NULL; return -1;
for (i = 0; i < conf->num_bss; i++) { for (i = 0; i < conf->num_bss; i++) {
hapd = hapd_iface->bss[i] = hapd = hapd_iface->bss[i] =
hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]); hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]);
if (hapd == NULL) if (hapd == NULL) {
return NULL; while (i > 0) {
i--;
os_free(hapd_iface->bss[i]);
hapd_iface->bss[i] = NULL;
}
os_free(hapd_iface->bss);
hapd_iface->bss = NULL;
return -1;
}
hapd->msg_ctx = hapd; hapd->msg_ctx = hapd;
} }
hapd_iface->interfaces = interfaces; hapd_iface->conf = conf;
hapd_iface->num_bss = conf->num_bss;
return hapd_iface; return 0;
} }
@ -1945,13 +1949,10 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
} }
if (new_iface) { if (new_iface) {
if (interfaces->driver_init(hapd_iface)) { if (interfaces->driver_init(hapd_iface))
interfaces->count--;
goto fail; goto fail;
}
if (hostapd_setup_interface(hapd_iface)) { if (hostapd_setup_interface(hapd_iface)) {
interfaces->count--;
hostapd_deinit_driver( hostapd_deinit_driver(
hapd_iface->bss[0]->driver, hapd_iface->bss[0]->driver,
hapd_iface->bss[0]->drv_priv, hapd_iface->bss[0]->drv_priv,
@ -2005,6 +2006,7 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
"for interface", __func__); "for interface", __func__);
goto fail; goto fail;
} }
new_iface = hapd_iface;
if (conf_file && interfaces->config_read_cb) { if (conf_file && interfaces->config_read_cb) {
conf = interfaces->config_read_cb(conf_file); conf = interfaces->config_read_cb(conf_file);
@ -2019,8 +2021,7 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
goto fail; goto fail;
} }
hapd_iface = hostapd_data_alloc(interfaces, conf); if (hostapd_data_alloc(hapd_iface, conf) < 0) {
if (hapd_iface == NULL) {
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory " wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
"for hostapd", __func__); "for hostapd", __func__);
goto fail; goto fail;
@ -2056,6 +2057,10 @@ fail:
os_free(hapd_iface->bss); os_free(hapd_iface->bss);
hapd_iface->bss = NULL; hapd_iface->bss = NULL;
} }
if (new_iface) {
interfaces->count--;
interfaces->iface[interfaces->count] = NULL;
}
hostapd_cleanup_iface(hapd_iface); hostapd_cleanup_iface(hapd_iface);
} }
return -1; return -1;
@ -2076,6 +2081,7 @@ static int hostapd_remove_bss(struct hostapd_iface *iface, unsigned int idx)
wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)", wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
__func__, hapd, hapd->conf->iface); __func__, hapd, hapd->conf->iface);
hostapd_config_free_bss(hapd->conf); hostapd_config_free_bss(hapd->conf);
hapd->conf = NULL;
os_free(hapd); os_free(hapd);
iface->num_bss--; iface->num_bss--;