summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-09-20 09:30:18 +0200
committerThomas Haller <thaller@redhat.com>2018-09-20 09:48:26 +0200
commit29c95cd98adfd9fa0aa71b4958d14b77b5a90e9d (patch)
tree690a32f0f85929a6109b560c44bdd3b12793ffd0
parent793afb7d955ae0e13faa865bc654d81de0143ea2 (diff)
downloadNetworkManager-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.c22
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;
}