3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-11-29 13:59:24 +01:00

network: Fix a bunch of double-frees

Missing secrets are freed by eap_send_agent_req() even in case of
failure, so it was erroneous to try to free them on error.

==1048== Invalid read of size 8
==1048==    at 0x1603EC: l_queue_clear (queue.c:101)
==1048==    by 0x1603B8: l_queue_destroy (queue.c:82)
==1048==    by 0x135328: network_connect_8021x (network.c:943)
==1048==    by 0x1354C4: network_connect (network.c:987)
==1048==    by 0x178DD2: _dbus_object_tree_dispatch (dbus-service.c:1690)
==1048==    by 0x16D32A: message_read_handler (dbus.c:285)
==1048==    by 0x166EC3: io_callback (io.c:123)
==1048==    by 0x165A1A: l_main_iterate (main.c:376)
==1048==    by 0x165B58: l_main_run (main.c:423)
==1048==    by 0x1102DA: main (main.c:458)
==1048==  Address 0x5461850 is 0 bytes inside a block of size 24 free'd
==1048==    at 0x4C2C13B: free (vg_replace_malloc.c:530)
==1048==    by 0x15ED03: l_free (util.c:136)
==1048==    by 0x1603C4: l_queue_destroy (queue.c:83)
==1048==    by 0x134BD5: eap_secret_request_free (network.c:719)
==1048==    by 0x134EF9: eap_send_agent_req (network.c:817)
==1048==    by 0x1352F7: network_connect_8021x (network.c:936)
==1048==    by 0x1354C4: network_connect (network.c:987)
==1048==    by 0x178DD2: _dbus_object_tree_dispatch (dbus-service.c:1690)
==1048==    by 0x16D32A: message_read_handler (dbus.c:285)
==1048==    by 0x166EC3: io_callback (io.c:123)
==1048==    by 0x165A1A: l_main_iterate (main.c:376)
==1048==    by 0x165B58: l_main_run (main.c:423)
This commit is contained in:
Denis Kenzior 2018-06-14 16:57:51 -05:00
parent 75b492eacc
commit 250568025c
2 changed files with 33 additions and 18 deletions

View File

@ -414,12 +414,30 @@ void eap_secret_info_free(void *data)
l_free(info); l_free(info);
} }
static int eap_setting_exists(struct l_settings *settings,
const char *setting,
struct l_queue *secrets,
struct l_queue *missing)
{
if (l_settings_get_value(settings, "Security", setting))
return 0;
if (l_queue_find(secrets, eap_secret_info_match, setting))
return 0;
if (l_queue_find(missing, eap_secret_info_match, setting))
return 0;
return -ENOENT;
}
int eap_check_settings(struct l_settings *settings, struct l_queue *secrets, int eap_check_settings(struct l_settings *settings, struct l_queue *secrets,
const char *prefix, bool set_key_material, const char *prefix, bool set_key_material,
struct l_queue **out_missing) struct l_queue **out_missing)
{ {
char setting[64]; char setting[64];
const char *method_name; const char *method_name;
struct l_queue *missing = NULL;
const struct l_queue_entry *entry; const struct l_queue_entry *entry;
struct eap_method *method; struct eap_method *method;
int ret = 0; int ret = 0;
@ -429,7 +447,6 @@ int eap_check_settings(struct l_settings *settings, struct l_queue *secrets,
if (!method_name) { if (!method_name) {
l_error("Property %s missing", setting); l_error("Property %s missing", setting);
return -ENOENT; return -ENOENT;
} }
@ -443,7 +460,6 @@ int eap_check_settings(struct l_settings *settings, struct l_queue *secrets,
if (!entry) { if (!entry) {
l_error("EAP method \"%s\" unsupported", method_name); l_error("EAP method \"%s\" unsupported", method_name);
return -ENOTSUP; return -ENOTSUP;
} }
@ -451,36 +467,37 @@ int eap_check_settings(struct l_settings *settings, struct l_queue *secrets,
if (set_key_material && !method->exports_msk) { if (set_key_material && !method->exports_msk) {
l_error("EAP method \"%s\" doesn't export key material", l_error("EAP method \"%s\" doesn't export key material",
method_name); method_name);
return -ENOTSUP; return -ENOTSUP;
} }
if (method->check_settings) if (method->check_settings)
ret = method->check_settings(settings, secrets, ret = method->check_settings(settings, secrets,
prefix, out_missing); prefix, &missing);
if (ret) if (ret)
return ret; goto error;
/* /*
* Methods that provide the get_identity callback are responsible * Methods that provide the get_identity callback are responsible
* for ensuring, inside check_settings(), that they have enough data * for ensuring, inside check_settings(), that they have enough data
* to return the identity after load_settings(). * to return the identity after load_settings().
*/ */
if (method->get_identity) if (!method->get_identity) {
return 0; snprintf(setting, sizeof(setting), "%sIdentity", prefix);
snprintf(setting, sizeof(setting), "%sIdentity", prefix); ret = eap_setting_exists(settings, setting, secrets, missing);
if (!l_settings_get_value(settings, "Security", setting) && if (ret < 0) {
!l_queue_find(secrets, eap_secret_info_match, l_error("Property %s is missing", setting);
setting) && ret = -ENOENT;
!l_queue_find(*out_missing, eap_secret_info_match, goto error;
setting)) { }
l_error("Property %s is missing", setting);
return -ENOENT;
} }
*out_missing = missing;
return 0; return 0;
error:
l_queue_destroy(missing, eap_secret_info_free);
return ret;
} }
bool eap_load_settings(struct eap_state *eap, struct l_settings *settings, bool eap_load_settings(struct eap_state *eap, struct l_settings *settings,

View File

@ -940,8 +940,6 @@ static struct l_dbus_message *network_connect_8021x(struct network *network,
reply = dbus_error_no_agent(message); reply = dbus_error_no_agent(message);
error: error:
l_queue_destroy(missing_secrets, eap_secret_info_free);
network_settings_close(network); network_settings_close(network);
l_queue_destroy(network->secrets, eap_secret_info_free); l_queue_destroy(network->secrets, eap_secret_info_free);