summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorJukka Rissanen <jukka.rissanen@linux.intel.com>2012-02-03 13:31:28 +0200
committerSamuel Ortiz <sameo@linux.intel.com>2012-02-04 01:15:35 +0100
commitbc61a82c641955f0926cf7644c1f9bbc22dcf13f (patch)
treeb10007f16dce66fbe8ed4d3a49e53e3b1cc0c891 /plugins
parentb9290c399cbf0e7e84c39593b2a981dae1a856c9 (diff)
downloadconnman-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.c15
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);