From 8a877d8692fdea766880aa1f647ce02a558460f8 Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Fri, 8 Apr 2022 13:18:09 -0500 Subject: [PATCH] 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: 85d9d6461f1f ("network: Hide hidden networks on connection error") --- src/network.c | 6 +++--- src/station.c | 17 +++++++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/network.c b/src/network.c index 65557e41..7bc97121 100644 --- a/src/network.c +++ b/src/network.c @@ -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, diff --git a/src/station.c b/src/station.c index d68175a7..2d85054c 100644 --- a/src/station.c +++ b/src/station.c @@ -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)