diff options
author | Thomas Haller <thaller@redhat.com> | 2015-02-17 07:53:24 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-02-17 11:38:56 +0100 |
commit | 87517714f1c31d0fe7c668bf689d2b8a0559cb73 (patch) | |
tree | 1a5991ecb2a1098b461242c54947752a247700fa /src/nm-default-route-manager.c | |
parent | 9d6b67012c2bd0cbdcb8af715b5388b17e45d8a2 (diff) | |
download | NetworkManager-87517714f1c31d0fe7c668bf689d2b8a0559cb73.tar.gz |
default-route-manager: avoid crash while disposing of NMDefaultRouteManager
During dipose(), NMDefaultRouteManager unrefed all the source pointers
in its list -- thereby having dangling pointers in the list of entries.
The unrefing can cause the final destruction of the device (during
shutdown), which would again call into NMDefaultRouteManager.
Fix this by ensuring that after disposing starts, all external calls
into NMDefaultRouteManager return early.
#0 0x00007ffff4a2cc60 in g_logv (log_domain=0x535b51 "NetworkManager", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fffffffd530) at gmessages.c:1046
#1 0x00007ffff4a2ce9f in g_log (log_domain=log_domain@entry=0x535b51 "NetworkManager", log_level=log_level@entry=G_LOG_LEVEL_CRITICAL, format=format@entry=0x528f68 "file %s: line %d (%s): should not be reached") at gmessages.c:1079
#2 0x000000000049b83b in _ipx_update_default_route (vtable=vtable@entry=0x7a49c0 <vtable_ip6>, self=0x7d1350 [NMDefaultRouteManager], source=source@entry=0x8b64e0) at nm-default-route-manager.c:659
#3 0x000000000049c652 in nm_default_route_manager_ip6_update_default_route (self=<optimized out>, source=source@entry=0x8b64e0) at nm-default-route-manager.c:819
#4 0x00000000004526a8 in _cleanup_generic_post (self=self@entry=0x8b64e0, deconfigure=deconfigure@entry=0) at devices/nm-device.c:7235
#5 0x0000000000452bc0 in dispose (object=0x8b64e0) at devices/nm-device.c:8324
#6 0x00007ffff4d29cbc in g_object_unref (_object=0x8b64e0) at gobject.c:3133
#7 0x0000000000499091 in _entry_free (entry=0x8bf140) at nm-default-route-manager.c:187
#8 0x00007ffff49fa82b in g_ptr_array_foreach (array=0x81d220, func=0x499080 <_entry_free>, user_data=0x0) at garray.c:1502
#9 0x00007ffff49fa8c0 in ptr_array_free (array=0x81d220, flags=FREE_SEGMENT) at garray.c:1088
#10 0x00007ffff49fa939 in g_ptr_array_free (array=<optimized out>, free_segment=free_segment@entry=1) at garray.c:1075
#11 0x000000000049abcf in dispose (object=0x7d1350 [NMDefaultRouteManager]) at nm-default-route-manager.c:1357
#12 0x00007ffff4d29cbc in g_object_unref (_object=0x7d1350) at gobject.c:3133
#13 0x00007ffff7deb507 in _dl_fini () at dl-fini.c:252
#14 0x00007ffff4658382 in __run_exit_handlers (status=status@entry=0, listp=0x7ffff49d66a0 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true) at exit.c:82
#15 0x00007ffff46583d5 in __GI_exit (status=status@entry=0) at exit.c:104
#16 0x0000000000432fd6 in main (argc=1, argv=0x7fffffffdeb8) at main.c:473
Diffstat (limited to 'src/nm-default-route-manager.c')
-rw-r--r-- | src/nm-default-route-manager.c | 31 |
1 files changed, 25 insertions, 6 deletions
diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c index 73384f25e4..4c1e483899 100644 --- a/src/nm-default-route-manager.c +++ b/src/nm-default-route-manager.c @@ -44,6 +44,14 @@ typedef struct { gboolean has_v4_changes; gboolean has_v6_changes; } resync; + + /* During disposing, we unref the sources of all entries. This happens usually + * during shutdown, which might call the final deletion of the object. That + * again might cause calls back into NMDefaultRouteManager, which finds dangling + * pointers. + * Guard every publicly accessible function to return early if the instance + * is already disposing. */ + gboolean disposed; } NMDefaultRouteManagerPrivate; #define NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEFAULT_ROUTE_MANAGER, NMDefaultRouteManagerPrivate)) @@ -651,6 +659,11 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self, gboolean synced = FALSE; g_return_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self)); + + priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); + if (priv->disposed) + return; + if (NM_IS_DEVICE (source)) device = source; else if (NM_IS_VPN_CONNECTION (source)) @@ -671,8 +684,6 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self, } } - priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); - entries = vtable->get_entries (priv); entry = _entry_find_by_source (entries, source, &entry_idx); @@ -881,6 +892,8 @@ _ipx_get_best_device (const VTableIP *vtable, NMDefaultRouteManager *self, const return NULL; priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); + if (priv->disposed) + return NULL; entries = vtable->get_entries (priv); for (i = 0; i < entries->len; i++) { @@ -935,6 +948,8 @@ _ipx_get_best_activating_device (const VTableIP *vtable, NMDefaultRouteManager * g_return_val_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self), NULL); priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); + if (priv->disposed) + return NULL; best_activated_device = _ipx_get_best_device (vtable, self, devices); @@ -1028,6 +1043,8 @@ _ipx_get_best_config (const VTableIP *vtable, *out_vpn = NULL; priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); + if (priv->disposed) + return NULL; g_return_val_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self), NULL); @@ -1353,6 +1370,12 @@ dispose (GObject *object) NMDefaultRouteManager *self = NM_DEFAULT_ROUTE_MANAGER (object); NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); + priv->disposed = TRUE; + + g_signal_handlers_disconnect_by_data (nm_platform_get (), self); + + _resync_idle_cancel (self); + if (priv->entries_ip4) { g_ptr_array_free (priv->entries_ip4, TRUE); priv->entries_ip4 = NULL; @@ -1362,10 +1385,6 @@ dispose (GObject *object) priv->entries_ip6 = NULL; } - _resync_idle_cancel (self); - - g_signal_handlers_disconnect_by_data (nm_platform_get (), self); - G_OBJECT_CLASS (nm_default_route_manager_parent_class)->dispose (object); } |