station/network: avoid use-after-free

ConnectHiddenNetwork creates a temporary network object and initiates a
connection with it.  If the connection fails (due to an incorrect
passphrase or other reasons), then this temporary object is destroyed.
Delay its destruction until network_disconnected() since
network_connect_failed is called too early.  Also, re-order the sequence
in station_reset_connection_state() in order to avoid using the network
object after it has been freed by network_disconnected().

Fixes: 85d9d6461f ("network: Hide hidden networks on connection error")
This commit is contained in:
Denis Kenzior 2022-04-08 13:18:09 -05:00
parent 867c68c05b
commit 8a877d8692
2 changed files with 14 additions and 9 deletions

View File

@ -198,6 +198,9 @@ void network_disconnected(struct network *network)
network_settings_close(network);
l_queue_clear(network->blacklist, NULL);
if (network->provisioning_hidden)
station_hide_network(network->station, network);
}
/* First 64 entries calculated by 1 / pow(n, 0.3) for n >= 1 */
@ -983,9 +986,6 @@ void network_connect_failed(struct network *network, bool in_handshake)
l_queue_destroy(network->secrets, eap_secret_info_free);
network->secrets = NULL;
if (network->provisioning_hidden)
station_hide_network(network->station, network);
}
static bool hotspot_info_matches(struct network *network,

View File

@ -1616,12 +1616,6 @@ static void station_reset_connection_state(struct station *station)
if (!network)
return;
if (station->state == STATION_STATE_CONNECTED ||
station->state == STATION_STATE_CONNECTING ||
station->state == STATION_STATE_CONNECTING_AUTO ||
station->state == STATION_STATE_ROAMING)
network_disconnected(network);
station_roam_state_clear(station);
/* Refresh the ordered network list */
@ -1639,6 +1633,17 @@ static void station_reset_connection_state(struct station *station)
IWD_NETWORK_INTERFACE, "Connected");
l_dbus_object_remove_interface(dbus, netdev_get_path(station->netdev),
IWD_STATION_DIAGNOSTIC_INTERFACE);
/*
* Perform this step last since calling network_disconnected() might
* result in the removal of the network (for example if provisioning
* a new hidden network fails with an incorrect pasword).
*/
if (station->state == STATION_STATE_CONNECTED ||
station->state == STATION_STATE_CONNECTING ||
station->state == STATION_STATE_CONNECTING_AUTO ||
station->state == STATION_STATE_ROAMING)
network_disconnected(network);
}
static void station_disassociated(struct station *station)