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: d9a4b59c18
This commit is contained in:
Thomas Haller 2018-09-20 09:30:18 +02:00
parent 793afb7d95
commit 29c95cd98a

View file

@ -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;
}