[PATCH 2/3] supplicant: rewrite pending DBus call handling for properties
Property-related D-Bus calls may be pending replies when the related GSupplicantInterface structure is cleaned up. This results in an attempt to access already freed memory when calls complete. Fixed by keeping a list of pending property calls, and canceling the calls related to an interface when the interface is removed. This is a similar change to the one made earlier for pending method calls. --- gsupplicant/dbus.c | 140 ++- gsupplicant/dbus.h | 12 ++-- gsupplicant/supplicant.c | 33 ++- 3 files changed, 116 insertions(+), 69 deletions(-) diff --git a/gsupplicant/dbus.c b/gsupplicant/dbus.c index 5b15bcd..130306e 100644 --- a/gsupplicant/dbus.c +++ b/gsupplicant/dbus.c @@ -59,10 +59,35 @@ static int find_method_call_by_caller(gconstpointer a, gconstpointer b) return method_call->caller != caller; } +static GSList *property_calls; + +struct property_call_data { + gpointer caller; + DBusPendingCall *pending_call; + supplicant_dbus_property_function function; + void *user_data; +}; + +static void property_call_free(void *pointer) +{ + struct property_call_data *property_call = pointer; + property_calls = g_slist_remove(property_calls, property_call); + g_free(property_call); +} + +static int find_property_call_by_caller(gconstpointer a, gconstpointer b) +{ + const struct property_call_data *property_call = a; + gconstpointer caller = b; + + return property_call->caller != caller; +} + void supplicant_dbus_setup(DBusConnection *conn) { connection = conn; method_calls = NULL; + property_calls = NULL; } void supplicant_dbus_array_foreach(DBusMessageIter *iter, @@ -124,14 +149,27 @@ void supplicant_dbus_property_foreach(DBusMessageIter *iter, } } -struct property_get_data { - supplicant_dbus_property_function function; - void *user_data; -}; +void supplicant_dbus_property_call_cancel_all(gpointer caller) +{ + while (property_calls) { + struct property_call_data *property_call; + GSList *elem = g_slist_find_custom(property_calls, caller, + find_property_call_by_caller); + if (!elem) + break; + + property_call = elem->data; + property_calls = g_slist_delete_link(property_calls, elem); + + dbus_pending_call_cancel(property_call->pending_call); + + dbus_pending_call_unref(property_call->pending_call); + } +} static void property_get_all_reply(DBusPendingCall *call, void *user_data) { - struct property_get_data *data = user_data; + struct property_call_data *property_call = user_data; DBusMessage *reply; DBusMessageIter iter; @@ -143,11 +181,11 @@ static void property_get_all_reply(DBusPendingCall *call, void *user_data) if (!dbus_message_iter_init(reply, &iter)) goto done; - supplicant_dbus_property_foreach(&iter, data->function, - data->user_data); + supplicant_dbus_property_foreach(&iter, property_call->function, + property_call->user_data); - if (data->function) - data->function(NULL, NULL, data->user_data); + if (property_call->function) + property_call->function(NULL, NULL, property_call->user_data); done: dbus_message_unref(reply); @@ -157,9 +195,9 @@ done: int supplicant_dbus_property_get_all(const char *path, const char *interface, supplicant_dbus_property_function function, - void *user_data) + void *user_data, gpointer caller) { - struct property_get_data *data; + struct property_call_data *property_call = NULL; DBusMessage *message; DBusPendingCall *call; @@ -169,14 +207,14 @@ int supplicant_dbus_property_get_all(const char *path, const char *interface, if (!path || !interface) return -EINVAL; - data = dbus_malloc0(sizeof(*data)); - if (!data) + property_call = g_try_new0(struct property_call_data, 1); + if (!property_call) return -ENOMEM; message = dbus_message_new_method_call(SUPPLICANT_SERVICE, path, DBUS_INTERFACE_PROPERTIES, "GetAll"); if (!message) { - dbus_free(data); + g_free(property_call); return -ENOMEM; } @@ -187,21 +225,23 @@ int supplicant_dbus_property_get_all(const char *path, const char *interface, if (!dbus_connection_send_with_reply(connection, message, &call, TIMEOUT)) { dbus_message_unref(message); -
[PATCH 2/3] supplicant: rewrite pending DBus call handling for properties
Property-related D-Bus calls may be pending replies when the related GSupplicantInterface structure is cleaned up. This results in an attempt to access already freed memory when calls complete. Fixed by keeping a list of pending property calls, and canceling the calls related to an interface when the interface is removed. This is a similar change to the one made earlier for pending method calls. --- gsupplicant/dbus.c | 140 ++- gsupplicant/dbus.h | 12 ++-- gsupplicant/supplicant.c | 33 ++- 3 files changed, 116 insertions(+), 69 deletions(-) diff --git a/gsupplicant/dbus.c b/gsupplicant/dbus.c index 5b15bcd..130306e 100644 --- a/gsupplicant/dbus.c +++ b/gsupplicant/dbus.c @@ -59,10 +59,35 @@ static int find_method_call_by_caller(gconstpointer a, gconstpointer b) return method_call->caller != caller; } +static GSList *property_calls; + +struct property_call_data { + gpointer caller; + DBusPendingCall *pending_call; + supplicant_dbus_property_function function; + void *user_data; +}; + +static void property_call_free(void *pointer) +{ + struct property_call_data *property_call = pointer; + property_calls = g_slist_remove(property_calls, property_call); + g_free(property_call); +} + +static int find_property_call_by_caller(gconstpointer a, gconstpointer b) +{ + const struct property_call_data *property_call = a; + gconstpointer caller = b; + + return property_call->caller != caller; +} + void supplicant_dbus_setup(DBusConnection *conn) { connection = conn; method_calls = NULL; + property_calls = NULL; } void supplicant_dbus_array_foreach(DBusMessageIter *iter, @@ -124,14 +149,27 @@ void supplicant_dbus_property_foreach(DBusMessageIter *iter, } } -struct property_get_data { - supplicant_dbus_property_function function; - void *user_data; -}; +void supplicant_dbus_property_call_cancel_all(gpointer caller) +{ + while (property_calls) { + struct property_call_data *property_call; + GSList *elem = g_slist_find_custom(property_calls, caller, + find_property_call_by_caller); + if (!elem) + break; + + property_call = elem->data; + property_calls = g_slist_delete_link(property_calls, elem); + + dbus_pending_call_cancel(property_call->pending_call); + + dbus_pending_call_unref(property_call->pending_call); + } +} static void property_get_all_reply(DBusPendingCall *call, void *user_data) { - struct property_get_data *data = user_data; + struct property_call_data *property_call = user_data; DBusMessage *reply; DBusMessageIter iter; @@ -143,11 +181,11 @@ static void property_get_all_reply(DBusPendingCall *call, void *user_data) if (!dbus_message_iter_init(reply, &iter)) goto done; - supplicant_dbus_property_foreach(&iter, data->function, - data->user_data); + supplicant_dbus_property_foreach(&iter, property_call->function, + property_call->user_data); - if (data->function) - data->function(NULL, NULL, data->user_data); + if (property_call->function) + property_call->function(NULL, NULL, property_call->user_data); done: dbus_message_unref(reply); @@ -157,9 +195,9 @@ done: int supplicant_dbus_property_get_all(const char *path, const char *interface, supplicant_dbus_property_function function, - void *user_data) + void *user_data, gpointer caller) { - struct property_get_data *data; + struct property_call_data *property_call = NULL; DBusMessage *message; DBusPendingCall *call; @@ -169,14 +207,14 @@ int supplicant_dbus_property_get_all(const char *path, const char *interface, if (!path || !interface) return -EINVAL; - data = dbus_malloc0(sizeof(*data)); - if (!data) + property_call = g_try_new0(struct property_call_data, 1); + if (!property_call) return -ENOMEM; message = dbus_message_new_method_call(SUPPLICANT_SERVICE, path, DBUS_INTERFACE_PROPERTIES, "GetAll"); if (!message) { - dbus_free(data); + g_free(property_call); return -ENOMEM; } @@ -187,21 +225,23 @@ int supplicant_dbus_property_get_all(const char *path, const char *interface, if (!dbus_connection_send_with_reply(connection, message, &call, TIMEOUT)) { dbus_message_unref(message); -