summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorBoleslaw Tokarski <boleslaw.tokarski@jolla.com>2020-11-13 13:01:37 +0100
committerDaniel Wagner <wagi@monom.org>2020-12-11 12:29:41 +0100
commit8506b8afc449683ac5534660c9097b3bfde9ba7a (patch)
treebe49bf4db28d523d4d54799df7d3e33104bb8df1 /plugins
parent9aede91e811adc1d57518bd7ef108871acfdcab8 (diff)
downloadconnman-8506b8afc449683ac5534660c9097b3bfde9ba7a.tar.gz
vpn: Secure a race condition with flag
ConnMan crashes happens in cancel_host_resolv in plugins/vpn.c. It seems that the function gets called twice on the same data. cancel_host_resolv is called from 2 places - from remove_result and from connection_destroy. remove_result is called from resolv_result indirectly - through g_timeout_add_seconds(0,...). In connection_destroy it is called directly as part of the cleanup routine. I managed to trigger a situation where remove_result was called and the resolv structure was cleaned and freed, and after that (due to me killing connman-vpnd in an unfortunate moment), connection_destroy kicked in and attempted to access data in resolv (NULL) pointer. To fix the issue, I add a user_data structure element representing the event ID of the scheduled resolv structure removal function. The cancel_host_resolv function would then check if the resolv removal function was scheduled, and would remove it from the loop, so it does not get executed.
Diffstat (limited to 'plugins')
-rw-r--r--plugins/vpn.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/plugins/vpn.c b/plugins/vpn.c
index 5668c004..47458915 100644
--- a/plugins/vpn.c
+++ b/plugins/vpn.c
@@ -94,6 +94,7 @@ struct connection_data {
GResolv *resolv;
guint resolv_id;
+ guint remove_resolv_id;
};
static int set_string(struct connman_provider *provider,
@@ -171,10 +172,15 @@ static char *get_ident(const char *path)
static void cancel_host_resolv(struct connection_data *data)
{
- if (data->resolv_id != 0)
+
+ if (data->remove_resolv_id)
+ g_source_remove(data->remove_resolv_id);
+
+ if (data->resolv && data->resolv_id)
g_resolv_cancel_lookup(data->resolv, data->resolv_id);
data->resolv_id = 0;
+ data->remove_resolv_id = 0;
g_resolv_unref(data->resolv);
data->resolv = NULL;
@@ -206,7 +212,7 @@ static void resolv_result(GResolvResultStatus status,
* We cannot unref the resolver here as resolv struct is manipulated
* by gresolv.c after we return from this callback.
*/
- g_idle_add(remove_resolv, data);
+ data->remove_resolv_id = g_idle_add(remove_resolv, data);
data->resolv_id = 0;
}