From 29c95cd98adfd9fa0aa71b4958d14b77b5a90e9d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 20 Sep 2018 09:30:18 +0200 Subject: [PATCH] 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 = t_node = #1 0x000055c2baff53be in acd_event (source=, condition=, 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 = #2 0x00007eff336238f9 in g_main_context_dispatch (context=0x55c2bc41f480) at gmain.c:3146 dispatch = 0x7eff336688a0 prev_source = 0x0 was_in_call = 0 user_data = 0x55c2bc4a6cf0 callback = 0x55c2baff5310 cb_funcs = 0x7eff338eb920 cb_data = 0x55c2bc558680 need_destroy = source = 0x55c2bc58c160 current = 0x55c2bc43dd10 i = 0 ... While at it, don't return from the events N_ACD_EVENT_DEFENDED, N_ACD_EVENT_CONFLICT, and , but continue popping events. Fixes: d9a4b59c18e36f2b577744b7fe6710d71161ca12 --- src/devices/nm-acd-manager.c | 22 ++++++++++++++++------ 1 file 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; }