diff options
author | Thomas Haller <thaller@redhat.com> | 2018-09-20 09:30:18 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2018-09-20 09:48:26 +0200 |
commit | 29c95cd98adfd9fa0aa71b4958d14b77b5a90e9d (patch) | |
tree | 690a32f0f85929a6109b560c44bdd3b12793ffd0 | |
parent | 793afb7d955ae0e13faa865bc654d81de0143ea2 (diff) | |
download | NetworkManager-29c95cd98adfd9fa0aa71b4958d14b77b5a90e9d.tar.gz |
acd: fix crash in acd-event loop
Don't emit signals while popping acd events. Otherwise, we can get
a crash:
#0 0x000055c2bb094e3b in n_acd_pop_event (acd=0x0, eventp=eventp@entry=0x7ffd47de65b0) at shared/n-acd/src/n-acd.c:846
node = <optimized out>
t_node = <optimized out>
#1 0x000055c2baff53be in acd_event (source=<optimized out>, condition=<optimized out>, data=0x55c2bc4a6cf0) at src/devices/nm-acd-manager.c:180
self = 0x55c2bc4a6cf0
priv = 0x55c2bc4a6d08
__func__ = "acd_event"
event = 0x55c2bc593af0
info = 0x55c2bc4b76c0
address_str = "\000\000\000\000\000\000\000\000\bd\373\272\302U\000"
hwaddr_str = 0x0
r = <optimized out>
#2 0x00007eff336238f9 in g_main_context_dispatch (context=0x55c2bc41f480) at gmain.c:3146
dispatch = 0x7eff336688a0 <g_io_unix_dispatch>
prev_source = 0x0
was_in_call = 0
user_data = 0x55c2bc4a6cf0
callback = 0x55c2baff5310 <acd_event>
cb_funcs = 0x7eff338eb920 <g_source_callback_funcs>
cb_data = 0x55c2bc558680
need_destroy = <optimized out>
source = 0x55c2bc58c160
current = 0x55c2bc43dd10
i = 0
...
While at it, don't return from the events N_ACD_EVENT_DEFENDED,
N_ACD_EVENT_CONFLICT, and <default>, but continue popping events.
Fixes: d9a4b59c18e36f2b577744b7fe6710d71161ca12
-rw-r--r-- | src/devices/nm-acd-manager.c | 22 |
1 files changed, 16 insertions, 6 deletions
diff --git a/src/devices/nm-acd-manager.c b/src/devices/nm-acd-manager.c index 70c17373d2..51ff233f2a 100644 --- a/src/devices/nm-acd-manager.c +++ b/src/devices/nm-acd-manager.c @@ -170,6 +170,7 @@ acd_event (GIOChannel *source, GIOCondition condition, gpointer data) NMAcdManagerPrivate *priv = NM_ACD_MANAGER_GET_PRIVATE (self); NAcdEvent *event; AddressInfo *info; + gboolean emit_probe_terminated = FALSE; char address_str[INET_ADDRSTRLEN]; gs_free char *hwaddr_str = NULL; int r; @@ -177,7 +178,10 @@ acd_event (GIOChannel *source, GIOCondition condition, gpointer data) if (n_acd_dispatch (priv->acd)) return G_SOURCE_CONTINUE; - while (!n_acd_pop_event (priv->acd, &event) && event) { + while ( !n_acd_pop_event (priv->acd, &event) + && event) { + gboolean check_probing_done = FALSE; + switch (event->event) { case N_ACD_EVENT_READY: n_acd_probe_get_userdata (event->ready.probe, (void **) &info); @@ -195,10 +199,12 @@ acd_event (GIOChannel *source, GIOCondition condition, gpointer data) nm_utils_inet4_ntop (info->address, address_str)); } } + check_probing_done = TRUE; break; case N_ACD_EVENT_USED: n_acd_probe_get_userdata (event->used.probe, (void **) &info); info->duplicate = TRUE; + check_probing_done = TRUE; break; case N_ACD_EVENT_DEFENDED: n_acd_probe_get_userdata (event->defended.probe, (void **) &info); @@ -206,7 +212,7 @@ acd_event (GIOChannel *source, GIOCondition condition, gpointer data) nm_utils_inet4_ntop (info->address, address_str), (hwaddr_str = nm_utils_hwaddr_ntoa (event->defended.sender, event->defended.n_sender))); - return G_SOURCE_CONTINUE; + break; case N_ACD_EVENT_CONFLICT: n_acd_probe_get_userdata (event->conflict.probe, (void **) &info); _LOGW ("conflict for address %s detected with host %s on interface '%s'", @@ -214,19 +220,23 @@ acd_event (GIOChannel *source, GIOCondition condition, gpointer data) (hwaddr_str = nm_utils_hwaddr_ntoa (event->defended.sender, event->defended.n_sender)), nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex)); - return G_SOURCE_CONTINUE; + break; default: _LOGD ("unhandled event '%s'", acd_event_to_string (event->event)); - return G_SOURCE_CONTINUE; + break; } - if ( priv->state == STATE_PROBING + if ( check_probing_done + && priv->state == STATE_PROBING && ++priv->completed == g_hash_table_size (priv->addresses)) { priv->state = STATE_PROBE_DONE; - g_signal_emit (self, signals[PROBE_TERMINATED], 0); + emit_probe_terminated = TRUE; } } + if (emit_probe_terminated) + g_signal_emit (self, signals[PROBE_TERMINATED], 0); + return G_SOURCE_CONTINUE; } |