From 55e46923c073fc5a38fcf572da05d55c0fc0b71f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 22 Sep 2015 12:44:14 +0200 Subject: [PATCH] systemd/adapt: fix potential crash invoking sd_event_source callbacks It is common that the callbacks unref the event source. Hence we must ensure that the @source stays alive until the callback returns. (cherry picked from commit 9901047ae3464999ab5c52ac408f603c73239597) --- src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c | 32 ++++++++++++++------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c index 1f6038e9c9..67ddc8da1b 100644 --- a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c +++ b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c @@ -91,6 +91,7 @@ static gboolean io_ready (GIOChannel *channel, GIOCondition condition, struct sd_event_source *source) { int r, revents = 0; + gboolean result; if (condition & G_IO_IN) revents |= EPOLLIN; @@ -103,13 +104,18 @@ io_ready (GIOChannel *channel, GIOCondition condition, struct sd_event_source *s if (condition & G_IO_HUP) revents |= EPOLLHUP; - r = source->io_cb (source, g_io_channel_unix_get_fd (channel), revents, source->user_data); - if (r < 0) { - source->id = 0; - return G_SOURCE_REMOVE; - } + source->refcount++; - return G_SOURCE_CONTINUE; + r = source->io_cb (source, g_io_channel_unix_get_fd (channel), revents, source->user_data); + if (r < 0 || source->refcount <= 1) { + source->id = 0; + result = G_SOURCE_REMOVE; + } else + result = G_SOURCE_CONTINUE; + + sd_event_source_unref (source); + + return result; } int @@ -151,14 +157,20 @@ static gboolean time_ready (struct sd_event_source *source) { int r; + gboolean result; + + source->refcount++; r = source->time_cb (source, source->usec, source->user_data); - if (r < 0) { + if (r < 0 || source->refcount <= 1) { source->id = 0; - return G_SOURCE_REMOVE; - } + result = G_SOURCE_REMOVE; + } else + result = G_SOURCE_CONTINUE; - return G_SOURCE_CONTINUE; + sd_event_source_unref (source); + + return result; } int