Blame SOURCES/0014-rh-1260727-crash-in-internal-dhcp-client.patch

ab7d06
From 0ec47c9b81a6fb6be44ccc852fbc7def22056ef2 Mon Sep 17 00:00:00 2001
ab7d06
From: Thomas Haller <thaller@redhat.com>
ab7d06
Date: Wed, 23 Sep 2015 16:03:41 +0200
ab7d06
Subject: [PATCH 1/7] logging: coerce negative error values to positive errno
ab7d06
ab7d06
Especially systemd, which makes use of the error argument for logging, likes
ab7d06
to represent errors as negative numbers. We hence must invert a negative error
ab7d06
code to get the real errno.
ab7d06
ab7d06
(cherry picked from commit d6370d09e6aa158d4fc7fe1e2ce4c335eed1e017)
ab7d06
(cherry picked from commit 972865bc4ef67557f04fba6b7a92edb70c9d3927)
ab7d06
---
ab7d06
 src/nm-logging.c | 5 ++++-
ab7d06
 1 file changed, 4 insertions(+), 1 deletion(-)
ab7d06
ab7d06
diff --git a/src/nm-logging.c b/src/nm-logging.c
ab7d06
index fa77034..b8433a2 100644
ab7d06
--- a/src/nm-logging.c
ab7d06
+++ b/src/nm-logging.c
ab7d06
@@ -381,8 +381,11 @@ _nm_log_impl (const char *file,
ab7d06
 		return;
ab7d06
 
ab7d06
 	/* Make sure that %m maps to the specified error */
ab7d06
-	if (error != 0)
ab7d06
+	if (error != 0) {
ab7d06
+		if (error < 0)
ab7d06
+			error = -error;
ab7d06
 		errno = error;
ab7d06
+	}
ab7d06
 
ab7d06
 	va_start (args, fmt);
ab7d06
 	msg = g_strdup_vprintf (fmt, args);
ab7d06
-- 
ab7d06
2.4.3
ab7d06
ab7d06
ab7d06
From 0c2078244f101653738460a9d6dd4983d30e08fe Mon Sep 17 00:00:00 2001
ab7d06
From: Thomas Haller <thaller@redhat.com>
ab7d06
Date: Tue, 22 Sep 2015 12:34:37 +0200
ab7d06
Subject: [PATCH 2/7] systemd/adapt: refactor creation of struct
ab7d06
 sd_event_source
ab7d06
ab7d06
(cherry picked from commit 41917a52c085b8699e5b37ef9b574ee265dcd0bf)
ab7d06
(cherry picked from commit 436ed50f4ab5ff152fe946f9ffdf3f2f822d0469)
ab7d06
---
ab7d06
 src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c | 16 ++++++++++++----
ab7d06
 1 file changed, 12 insertions(+), 4 deletions(-)
ab7d06
ab7d06
diff --git a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
ab7d06
index a6d8172..7984dcb 100644
ab7d06
--- a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
ab7d06
+++ b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
ab7d06
@@ -37,6 +37,16 @@ struct sd_event_source {
ab7d06
 	sd_event_time_handler_t time_cb;
ab7d06
 };
ab7d06
 
ab7d06
+static struct sd_event_source *
ab7d06
+source_new (void)
ab7d06
+{
ab7d06
+	struct sd_event_source *source;
ab7d06
+
ab7d06
+	source = g_new0 (struct sd_event_source, 1);
ab7d06
+	source->refcount = 1;
ab7d06
+	return source;
ab7d06
+}
ab7d06
+
ab7d06
 int
ab7d06
 sd_event_source_set_priority (sd_event_source *s, int64_t priority)
ab7d06
 {
ab7d06
@@ -113,8 +123,7 @@ sd_event_add_io (sd_event *e, sd_event_source **s, int fd, uint32_t events, sd_e
ab7d06
 	if (!channel)
ab7d06
 		return -EINVAL;
ab7d06
 
ab7d06
-	source = g_new0 (struct sd_event_source, 1);
ab7d06
-	source->refcount = 1;
ab7d06
+	source = source_new ();
ab7d06
 	source->io_cb = callback;
ab7d06
 	source->user_data = userdata;
ab7d06
 	source->channel = channel;
ab7d06
@@ -158,8 +167,7 @@ sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t us
ab7d06
 	struct sd_event_source *source;
ab7d06
 	uint64_t n = now (clock);
ab7d06
 
ab7d06
-	source = g_new0 (struct sd_event_source, 1);
ab7d06
-	source->refcount = 1;
ab7d06
+	source = source_new ();
ab7d06
 	source->time_cb = callback;
ab7d06
 	source->user_data = userdata;
ab7d06
 	source->usec = usec;
ab7d06
-- 
ab7d06
2.4.3
ab7d06
ab7d06
ab7d06
From f154c9ccef5d20a2aa765e84d9403e66510e9e2f Mon Sep 17 00:00:00 2001
ab7d06
From: Thomas Haller <thaller@redhat.com>
ab7d06
Date: Tue, 22 Sep 2015 12:35:42 +0200
ab7d06
Subject: [PATCH 3/7] systemd/adapt: use slice-allocator for struct
ab7d06
 sd_event_source
ab7d06
ab7d06
(cherry picked from commit fb0e87be394c0fdb4ccf2911bd089bbdf0b19113)
ab7d06
(cherry picked from commit 8c08014f475c4a60e129d4cd755ff30db5eac4bc)
ab7d06
---
ab7d06
 src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c | 4 ++--
ab7d06
 1 file changed, 2 insertions(+), 2 deletions(-)
ab7d06
ab7d06
diff --git a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
ab7d06
index 7984dcb..1f6038e 100644
ab7d06
--- a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
ab7d06
+++ b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
ab7d06
@@ -42,7 +42,7 @@ source_new (void)
ab7d06
 {
ab7d06
 	struct sd_event_source *source;
ab7d06
 
ab7d06
-	source = g_new0 (struct sd_event_source, 1);
ab7d06
+	source = g_slice_new0 (struct sd_event_source);
ab7d06
 	source->refcount = 1;
ab7d06
 	return source;
ab7d06
 }
ab7d06
@@ -72,7 +72,7 @@ sd_event_source_unref (sd_event_source *s)
ab7d06
 			 */
ab7d06
 			g_io_channel_unref (s->channel);
ab7d06
 		}
ab7d06
-		g_free (s);
ab7d06
+		g_slice_free (struct sd_event_source, s);
ab7d06
 	}
ab7d06
 	return NULL;
ab7d06
 }
ab7d06
-- 
ab7d06
2.4.3
ab7d06
ab7d06
ab7d06
From 5d35919178a5a8df7804247da976352244e89cab Mon Sep 17 00:00:00 2001
ab7d06
From: Thomas Haller <thaller@redhat.com>
ab7d06
Date: Tue, 22 Sep 2015 12:44:14 +0200
ab7d06
Subject: [PATCH 4/7] systemd/adapt: fix potential crash invoking
ab7d06
 sd_event_source callbacks
ab7d06
ab7d06
It is common that the callbacks unref the event source. Hence we must
ab7d06
ensure that the @source stays alive until the callback returns.
ab7d06
ab7d06
(cherry picked from commit 9901047ae3464999ab5c52ac408f603c73239597)
ab7d06
(cherry picked from commit 55e46923c073fc5a38fcf572da05d55c0fc0b71f)
ab7d06
---
ab7d06
 src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c | 28 ++++++++++++++++++++--------
ab7d06
 1 file changed, 20 insertions(+), 8 deletions(-)
ab7d06
ab7d06
diff --git a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
ab7d06
index 1f6038e..67ddc8d 100644
ab7d06
--- a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
ab7d06
+++ b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
ab7d06
@@ -91,6 +91,7 @@ static gboolean
ab7d06
 io_ready (GIOChannel *channel, GIOCondition condition, struct sd_event_source *source)
ab7d06
 {
ab7d06
 	int r, revents = 0;
ab7d06
+	gboolean result;
ab7d06
 
ab7d06
 	if (condition & G_IO_IN)
ab7d06
 		revents |= EPOLLIN;
ab7d06
@@ -103,13 +104,18 @@ io_ready (GIOChannel *channel, GIOCondition condition, struct sd_event_source *s
ab7d06
 	if (condition & G_IO_HUP)
ab7d06
 		revents |= EPOLLHUP;
ab7d06
 
ab7d06
+	source->refcount++;
ab7d06
+
ab7d06
 	r = source->io_cb (source, g_io_channel_unix_get_fd (channel), revents, source->user_data);
ab7d06
-	if (r < 0) {
ab7d06
+	if (r < 0 || source->refcount <= 1) {
ab7d06
 		source->id = 0;
ab7d06
-		return G_SOURCE_REMOVE;
ab7d06
-	}
ab7d06
+		result = G_SOURCE_REMOVE;
ab7d06
+	} else
ab7d06
+		result = G_SOURCE_CONTINUE;
ab7d06
+
ab7d06
+	sd_event_source_unref (source);
ab7d06
 
ab7d06
-	return G_SOURCE_CONTINUE;
ab7d06
+	return result;
ab7d06
 }
ab7d06
 
ab7d06
 int
ab7d06
@@ -151,14 +157,20 @@ static gboolean
ab7d06
 time_ready (struct sd_event_source *source)
ab7d06
 {
ab7d06
 	int r;
ab7d06
+	gboolean result;
ab7d06
+
ab7d06
+	source->refcount++;
ab7d06
 
ab7d06
 	r = source->time_cb (source, source->usec, source->user_data);
ab7d06
-	if (r < 0) {
ab7d06
+	if (r < 0 || source->refcount <= 1) {
ab7d06
 		source->id = 0;
ab7d06
-		return G_SOURCE_REMOVE;
ab7d06
-	}
ab7d06
+		result = G_SOURCE_REMOVE;
ab7d06
+	} else
ab7d06
+		result = G_SOURCE_CONTINUE;
ab7d06
+
ab7d06
+	sd_event_source_unref (source);
ab7d06
 
ab7d06
-	return G_SOURCE_CONTINUE;
ab7d06
+	return result;
ab7d06
 }
ab7d06
 
ab7d06
 int
ab7d06
-- 
ab7d06
2.4.3
ab7d06
ab7d06
ab7d06
From bfd1b1daaaed47a7c91c4561c7de29091cdf702d Mon Sep 17 00:00:00 2001
ab7d06
From: Thomas Haller <thaller@redhat.com>
ab7d06
Date: Tue, 22 Sep 2015 13:26:58 +0200
ab7d06
Subject: [PATCH 5/7] systemd/adapt: assert that a @source argument is passed
ab7d06
 to sd_event_add_time()
ab7d06
ab7d06
Systemd supports omitting the output source argument. In this case,
ab7d06
the created event source is floating and the reference count
ab7d06
is handled properly.
ab7d06
ab7d06
We have however no callers that make use of that functionality, so
ab7d06
instead of implementing floating references, assert that we don't
ab7d06
need it.
ab7d06
ab7d06
This isn't a change in behavior, because previously the could would just
ab7d06
SEGFAULT if a caller didn't want to take ownership of the created event.
ab7d06
ab7d06
(cherry picked from commit 02c51d4231da154b624fe5859a1e34f340eecb05)
ab7d06
(cherry picked from commit 11237a0a66df5e2486d961050aa03103578c40d2)
ab7d06
---
ab7d06
 src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c | 8 ++++++++
ab7d06
 1 file changed, 8 insertions(+)
ab7d06
ab7d06
diff --git a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
ab7d06
index 67ddc8d..1f8f2dc 100644
ab7d06
--- a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
ab7d06
+++ b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
ab7d06
@@ -125,6 +125,10 @@ sd_event_add_io (sd_event *e, sd_event_source **s, int fd, uint32_t events, sd_e
ab7d06
 	GIOChannel *channel;
ab7d06
 	GIOCondition condition = 0;
ab7d06
 
ab7d06
+	/* systemd supports floating sd_event_source by omitting the @s argument.
ab7d06
+	 * We don't have such users and don't implement floating references. */
ab7d06
+	g_return_val_if_fail (s, -EINVAL);
ab7d06
+
ab7d06
 	channel = g_io_channel_unix_new (fd);
ab7d06
 	if (!channel)
ab7d06
 		return -EINVAL;
ab7d06
@@ -179,6 +183,10 @@ sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t us
ab7d06
 	struct sd_event_source *source;
ab7d06
 	uint64_t n = now (clock);
ab7d06
 
ab7d06
+	/* systemd supports floating sd_event_source by omitting the @s argument.
ab7d06
+	 * We don't have such users and don't implement floating references. */
ab7d06
+	g_return_val_if_fail (s, -EINVAL);
ab7d06
+
ab7d06
 	source = source_new ();
ab7d06
 	source->time_cb = callback;
ab7d06
 	source->user_data = userdata;
ab7d06
-- 
ab7d06
2.4.3
ab7d06
ab7d06
ab7d06
From 04d5235aa7e7cff5ec6e62e73a8a8d47bd478ab7 Mon Sep 17 00:00:00 2001
ab7d06
From: Thomas Haller <thaller@redhat.com>
ab7d06
Date: Wed, 23 Sep 2015 09:48:00 +0200
ab7d06
Subject: [PATCH 6/7] systemd/adapt: refactor sd_event_source to use a union
ab7d06
 for holding mutually exclusive fields
ab7d06
ab7d06
sd_event_source is either used for sd_event_add_io() or sd_event_add_time().
ab7d06
Depending on the use, different fields of the struct are relevant. Refactor
ab7d06
the struct to have a union.
ab7d06
ab7d06
This reduces the size of the struct, but more importantly, it makes it
ab7d06
clear which fields are used in which context.
ab7d06
ab7d06
(cherry picked from commit 2d2d742cf1787a948a20bf7a12acd17fa62e1dc9)
ab7d06
(cherry picked from commit 0e6a13bccc6503657781f91960b82212af7317f8)
ab7d06
---
ab7d06
 src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c | 22 ++++++++++++++--------
ab7d06
 1 file changed, 14 insertions(+), 8 deletions(-)
ab7d06
ab7d06
diff --git a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
ab7d06
index 1f8f2dc..24b77c5 100644
ab7d06
--- a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
ab7d06
+++ b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
ab7d06
@@ -31,10 +31,16 @@ struct sd_event_source {
ab7d06
 	gpointer user_data;
ab7d06
 
ab7d06
 	GIOChannel *channel;
ab7d06
-	sd_event_io_handler_t io_cb;
ab7d06
 
ab7d06
-	uint64_t usec;
ab7d06
-	sd_event_time_handler_t time_cb;
ab7d06
+	union {
ab7d06
+		struct {
ab7d06
+			sd_event_io_handler_t cb;
ab7d06
+		} io;
ab7d06
+		struct {
ab7d06
+			sd_event_time_handler_t cb;
ab7d06
+			uint64_t usec;
ab7d06
+		} time;
ab7d06
+	};
ab7d06
 };
ab7d06
 
ab7d06
 static struct sd_event_source *
ab7d06
@@ -106,7 +112,7 @@ io_ready (GIOChannel *channel, GIOCondition condition, struct sd_event_source *s
ab7d06
 
ab7d06
 	source->refcount++;
ab7d06
 
ab7d06
-	r = source->io_cb (source, g_io_channel_unix_get_fd (channel), revents, source->user_data);
ab7d06
+	r = source->io.cb (source, g_io_channel_unix_get_fd (channel), revents, source->user_data);
ab7d06
 	if (r < 0 || source->refcount <= 1) {
ab7d06
 		source->id = 0;
ab7d06
 		result = G_SOURCE_REMOVE;
ab7d06
@@ -134,7 +140,7 @@ sd_event_add_io (sd_event *e, sd_event_source **s, int fd, uint32_t events, sd_e
ab7d06
 		return -EINVAL;
ab7d06
 
ab7d06
 	source = source_new ();
ab7d06
-	source->io_cb = callback;
ab7d06
+	source->io.cb = callback;
ab7d06
 	source->user_data = userdata;
ab7d06
 	source->channel = channel;
ab7d06
 
ab7d06
@@ -165,7 +171,7 @@ time_ready (struct sd_event_source *source)
ab7d06
 
ab7d06
 	source->refcount++;
ab7d06
 
ab7d06
-	r = source->time_cb (source, source->usec, source->user_data);
ab7d06
+	r = source->time.cb (source, source->time.usec, source->user_data);
ab7d06
 	if (r < 0 || source->refcount <= 1) {
ab7d06
 		source->id = 0;
ab7d06
 		result = G_SOURCE_REMOVE;
ab7d06
@@ -188,9 +194,9 @@ sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t us
ab7d06
 	g_return_val_if_fail (s, -EINVAL);
ab7d06
 
ab7d06
 	source = source_new ();
ab7d06
-	source->time_cb = callback;
ab7d06
+	source->time.cb = callback;
ab7d06
 	source->user_data = userdata;
ab7d06
-	source->usec = usec;
ab7d06
+	source->time.usec = usec;
ab7d06
 
ab7d06
 	if (usec > 1000)
ab7d06
 		usec = n < usec - 1000 ? usec - n : 1000;
ab7d06
-- 
ab7d06
2.4.3
ab7d06
ab7d06
ab7d06
From 5980ff8b1106f2adb55a9ce6665e76d85d70734d Mon Sep 17 00:00:00 2001
ab7d06
From: Thomas Haller <thaller@redhat.com>
ab7d06
Date: Tue, 22 Sep 2015 14:03:32 +0200
ab7d06
Subject: [PATCH 7/7] systemd: avoid potential crash due to uncanceled timers
ab7d06
 in client_receive_advertise()
ab7d06
ab7d06
Got a crash with unknown reason on nm-1-0 branch. It's unclear why,
ab7d06
but the reason could be that a lease in client_receive_advertise()
ab7d06
was cleared, but not its timers.
ab7d06
ab7d06
Backtrace from nm-1-0 branch (note that the systemd code where the crash
ab7d06
happend is different, but similar):
ab7d06
ab7d06
    #0  sd_event_source_unref (s=0xf5c007e8fb894853) at dhcp-manager/systemd-dhcp/nm-sd-adapt.c:53
ab7d06
    #1  0x0000555555682340 in client_timeout_t1 (s=<optimized out>, usec=<optimized out>, userdata=0x5555559f5240)
ab7d06
        at dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c:451
ab7d06
    #2  0x00005555556a078f in time_ready (source=0x5555559f3c20) at dhcp-manager/systemd-dhcp/nm-sd-adapt.c:146
ab7d06
    #3  0x00007ffff4a481b3 in g_timeout_dispatch () from /lib64/libglib-2.0.so.0
ab7d06
    #4  0x00007ffff4a4779a in g_main_context_dispatch () from /lib64/libglib-2.0.so.0
ab7d06
    #5  0x00007ffff4a47ae8 in g_main_context_iterate.isra.24 () from /lib64/libglib-2.0.so.0
ab7d06
    #6  0x00007ffff4a47dba in g_main_loop_run () from /lib64/libglib-2.0.so.0
ab7d06
    #7  0x0000555555597073 in main (argc=1, argv=0x7fffffffe2b8) at main.c:512
ab7d06
ab7d06
Equivalent upstream systemd patch:
ab7d06
  https://github.com/systemd/systemd/pull/1332
ab7d06
  https://github.com/systemd/systemd/commit/f89087272b5561c9a3fc9d6a4e2a09f75f688fa7
ab7d06
ab7d06
https://bugzilla.redhat.com/show_bug.cgi?id=1260727
ab7d06
(cherry picked from commit 401a2eb834bdddd8931161eb86204eb80d26b2c7)
ab7d06
(cherry picked from commit fe70a87f942fa4a5d509787852185a7168739de6)
ab7d06
---
ab7d06
 .../systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c            | 5 ++++-
ab7d06
 1 file changed, 4 insertions(+), 1 deletion(-)
ab7d06
ab7d06
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c
ab7d06
index 6c5a6ab..8a17a72 100644
ab7d06
--- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c
ab7d06
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c
ab7d06
@@ -828,7 +828,10 @@ static int client_receive_advertise(sd_dhcp6_client *client,
ab7d06
 
ab7d06
         r = dhcp6_lease_get_preference(client->lease, &pref_lease);
ab7d06
         if (!client->lease || r < 0 || pref_advertise > pref_lease) {
ab7d06
-                sd_dhcp6_lease_unref(client->lease);
ab7d06
+                if (client->lease) {
ab7d06
+                        dhcp6_lease_clear_timers(&client->lease->ia);
ab7d06
+                        sd_dhcp6_lease_unref(client->lease);
ab7d06
+                }
ab7d06
                 client->lease = lease;
ab7d06
                 lease = NULL;
ab7d06
                 r = 0;
ab7d06
-- 
ab7d06
2.4.3
ab7d06