diff options
author | Jukka Rissanen <jukka.rissanen@linux.intel.com> | 2012-02-03 13:31:28 +0200 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-02-04 01:15:35 +0100 |
commit | bc61a82c641955f0926cf7644c1f9bbc22dcf13f (patch) | |
tree | b10007f16dce66fbe8ed4d3a49e53e3b1cc0c891 /plugins | |
parent | b9290c399cbf0e7e84c39593b2a981dae1a856c9 (diff) | |
download | connman-bc61a82c641955f0926cf7644c1f9bbc22dcf13f.tar.gz connman-bc61a82c641955f0926cf7644c1f9bbc22dcf13f.tar.bz2 connman-bc61a82c641955f0926cf7644c1f9bbc22dcf13f.zip |
vpn: Reference of provider not taken
VPN plugin hooks itself into rtnl newlink watch and gives
provider pointer as user data. We must take reference of the
user data pointer as otherwise we might access invalid pointer
if provider is already removed when rtnl watch is triggered.
This seems to be a rare issue but I had one valgrind crash
because of this.
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/vpn.c | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/plugins/vpn.c b/plugins/vpn.c index a6ac5b90..e103d362 100644 --- a/plugins/vpn.c +++ b/plugins/vpn.c @@ -135,6 +135,7 @@ void vpn_died(struct connman_task *task, int exit_code, void *user_data) stop_vpn(provider); connman_provider_set_data(provider, NULL); + connman_provider_unref(provider); connman_rtnl_remove_watch(data->watch); vpn_exit: @@ -226,6 +227,7 @@ static DBusMessage *vpn_notify(struct connman_task *task, case VPN_STATE_CONNECT: case VPN_STATE_READY: index = connman_provider_get_index(provider); + connman_provider_ref(provider); data->watch = connman_rtnl_add_newlink_watch(index, vpn_newlink, provider); connman_inet_ifup(index); @@ -421,10 +423,12 @@ static int vpn_disconnect(struct connman_provider *provider) if (vpn_driver_data->vpn_driver->disconnect) vpn_driver_data->vpn_driver->disconnect(); - if (data->watch != 0) + if (data->watch != 0) { + connman_provider_unref(provider); connman_rtnl_remove_watch(data->watch); + data->watch = 0; + } - data->watch = 0; data->state = VPN_STATE_DISCONNECT; connman_task_stop(data->task); @@ -439,9 +443,12 @@ static int vpn_remove(struct connman_provider *provider) if (data == NULL) return 0; - if (data->watch != 0) + if (data->watch != 0) { + connman_provider_unref(provider); connman_rtnl_remove_watch(data->watch); - data->watch = 0; + data->watch = 0; + } + connman_task_stop(data->task); g_usleep(G_USEC_PER_SEC); |