summaryrefslogtreecommitdiffstats
path: root/meta
diff options
context:
space:
mode:
authorPeter Marko <peter.marko@siemens.com>2024-06-09 00:16:33 +0200
committerSteve Sakoman <steve@sakoman.com>2024-06-26 05:04:39 -0700
commitf27a1997b6f48f77c5085ce9b6572494e7dd864e (patch)
treee45622fee6af51e3be072d8dec9c4844f28df167 /meta
parent35a517b7bd56a60acb85604fa335b5c6a21a698f (diff)
downloadpoky-f27a1997b6f48f77c5085ce9b6572494e7dd864e.tar.gz
glib-2.0: patch CVE-2024-34397
This is taken from https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4047 That MR was not merged as 2.72 is inactive branch now. But it can be used by distributions, like Ubuntu did under https://git.launchpad.net/ubuntu/+source/glib2.0/commit/?h=applied/ubuntu/jammy-security&id=94425c909b037c63c9dbbf72015f628ed4ad4aea (From OE-Core rev: 95e8507848e3143eca83621f6572439e22f60bd4) Signed-off-by: Peter Marko <peter.marko@siemens.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
Diffstat (limited to 'meta')
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_01.patch129
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_02.patch62
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_03.patch985
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_04.patch253
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_05.patch88
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_06.patch263
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_07.patch45
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_08.patch168
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_09.patch81
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_10.patch108
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_11.patch133
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_12.patch173
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_13.patch513
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_14.patch75
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_15.patch47
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_16.patch62
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_17.patch121
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_18.patch50
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb18
19 files changed, 3374 insertions, 0 deletions
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_01.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_01.patch
new file mode 100644
index 0000000000..6a476fe307
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_01.patch
@@ -0,0 +1,129 @@
1From c4e3022918565253ffad52449dd0e648b6d772c7 Mon Sep 17 00:00:00 2001
2From: Philip Withnall <pwithnall@gnome.org>
3Date: Tue, 28 Nov 2023 12:58:20 +0000
4Subject: [PATCH 01/18] gdbusmessage: Cache the arg0 value
5MIME-Version: 1.0
6Content-Type: text/plain; charset=UTF-8
7Content-Transfer-Encoding: 8bit
8
9Technically we can’t rely on it being kept alive by the `message->body`
10pointer, unless we can guarantee that the `GVariant` is always
11serialised. That’s not necessarily the case, so keep a separate ref on
12the arg0 value at all times.
13
14This avoids a potential use-after-free.
15
16Spotted by Thomas Haller in
17https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3720#note_1924707.
18
19[This is a prerequisite for having tests pass after fixing the
20vulnerability described in glib#3268, because after fixing that
21vulnerability, the use-after-free genuinely does happen during
22regression testing. -smcv]
23
24Signed-off-by: Philip Withnall <pwithnall@gnome.org>
25
26Helps: #3183, #3268
27(cherry picked from commit 10e9a917be7fb92b6b27837ef7a7f1d0be6095d5)
28
29CVE: CVE-2024-34397
30Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/c4e3022918565253ffad52449dd0e648b6d772c7]
31Signed-off-by: Peter Marko <peter.marko@siemens.com>
32---
33 gio/gdbusmessage.c | 35 ++++++++++++++++++++++-------------
34 1 file changed, 22 insertions(+), 13 deletions(-)
35
36diff --git a/gio/gdbusmessage.c b/gio/gdbusmessage.c
37index ecef6cd3c..3fd1151ca 100644
38--- a/gio/gdbusmessage.c
39+++ b/gio/gdbusmessage.c
40@@ -506,6 +506,7 @@ struct _GDBusMessage
41 guint32 serial;
42 GHashTable *headers;
43 GVariant *body;
44+ GVariant *arg0_cache; /* (nullable) (owned) */
45 #ifdef G_OS_UNIX
46 GUnixFDList *fd_list;
47 #endif
48@@ -528,6 +529,7 @@ g_dbus_message_finalize (GObject *object)
49 g_hash_table_unref (message->headers);
50 if (message->body != NULL)
51 g_variant_unref (message->body);
52+ g_clear_pointer (&message->arg0_cache, g_variant_unref);
53 #ifdef G_OS_UNIX
54 if (message->fd_list != NULL)
55 g_object_unref (message->fd_list);
56@@ -1163,6 +1165,7 @@ g_dbus_message_set_body (GDBusMessage *message,
57 if (body == NULL)
58 {
59 message->body = NULL;
60+ message->arg0_cache = NULL;
61 g_dbus_message_set_signature (message, NULL);
62 }
63 else
64@@ -1173,6 +1176,12 @@ g_dbus_message_set_body (GDBusMessage *message,
65
66 message->body = g_variant_ref_sink (body);
67
68+ if (g_variant_is_of_type (message->body, G_VARIANT_TYPE_TUPLE) &&
69+ g_variant_n_children (message->body) > 0)
70+ message->arg0_cache = g_variant_get_child_value (message->body, 0);
71+ else
72+ message->arg0_cache = NULL;
73+
74 type_string = g_variant_get_type_string (body);
75 type_string_len = strlen (type_string);
76 g_assert (type_string_len >= 2);
77@@ -2325,6 +2334,14 @@ g_dbus_message_new_from_blob (guchar *blob,
78 2,
79 &local_error);
80 g_variant_type_free (variant_type);
81+
82+ if (message->body != NULL &&
83+ g_variant_is_of_type (message->body, G_VARIANT_TYPE_TUPLE) &&
84+ g_variant_n_children (message->body) > 0)
85+ message->arg0_cache = g_variant_get_child_value (message->body, 0);
86+ else
87+ message->arg0_cache = NULL;
88+
89 if (message->body == NULL)
90 goto fail;
91 }
92@@ -3364,22 +3381,13 @@ g_dbus_message_set_signature (GDBusMessage *message,
93 const gchar *
94 g_dbus_message_get_arg0 (GDBusMessage *message)
95 {
96- const gchar *ret;
97-
98 g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
99
100- ret = NULL;
101+ if (message->arg0_cache != NULL &&
102+ g_variant_is_of_type (message->arg0_cache, G_VARIANT_TYPE_STRING))
103+ return g_variant_get_string (message->arg0_cache, NULL);
104
105- if (message->body != NULL && g_variant_is_of_type (message->body, G_VARIANT_TYPE_TUPLE))
106- {
107- GVariant *item;
108- item = g_variant_get_child_value (message->body, 0);
109- if (g_variant_is_of_type (item, G_VARIANT_TYPE_STRING))
110- ret = g_variant_get_string (item, NULL);
111- g_variant_unref (item);
112- }
113-
114- return ret;
115+ return NULL;
116 }
117
118 /* ---------------------------------------------------------------------------------------------------- */
119@@ -3822,6 +3830,7 @@ g_dbus_message_copy (GDBusMessage *message,
120 * to just ref (as opposed to deep-copying) the GVariant instances
121 */
122 ret->body = message->body != NULL ? g_variant_ref (message->body) : NULL;
123+ ret->arg0_cache = message->arg0_cache != NULL ? g_variant_ref (message->arg0_cache) : NULL;
124 g_hash_table_iter_init (&iter, message->headers);
125 while (g_hash_table_iter_next (&iter, &header_key, (gpointer) &header_value))
126 g_hash_table_insert (ret->headers, header_key, g_variant_ref (header_value));
127--
1282.30.2
129
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_02.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_02.patch
new file mode 100644
index 0000000000..aecc1686d5
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_02.patch
@@ -0,0 +1,62 @@
1From c805fd3862baaa114d1cceee27cc931264894c98 Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@collabora.com>
3Date: Wed, 1 May 2024 15:51:42 +0100
4Subject: [PATCH 02/18] gdbusconnection: Make a backport of g_set_str()
5 available
6
7A subsequent commit will need this. Copying all of g_set_str() into a
8private header seems cleaner than replacing the call to it.
9
10Helps: GNOME/glib#3268
11Signed-off-by: Simon McVittie <smcv@collabora.com>
12
13CVE: CVE-2024-34397
14Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/c805fd3862baaa114d1cceee27cc931264894c98]
15Signed-off-by: Peter Marko <peter.marko@siemens.com>
16---
17 gio/gdbusconnection.c | 1 +
18 glib/glib-private.h | 18 ++++++++++++++++++
19 2 files changed, 19 insertions(+)
20
21diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
22index 1159c2db4..82a68437b 100644
23--- a/gio/gdbusconnection.c
24+++ b/gio/gdbusconnection.c
25@@ -95,6 +95,7 @@
26 #include <stdlib.h>
27 #include <string.h>
28
29+#include "glib-private.h"
30 #include "gdbusauth.h"
31 #include "gdbusutils.h"
32 #include "gdbusaddress.h"
33diff --git a/glib/glib-private.h b/glib/glib-private.h
34index 943252f1b..f02828ff5 100644
35--- a/glib/glib-private.h
36+++ b/glib/glib-private.h
37@@ -201,4 +201,22 @@ GLibPrivateVTable *glib__private__ (void);
38 # define GLIB_DEFAULT_LOCALE ""
39 #endif
40
41+/* Backported from GLib 2.78.x, where it is public API in gstrfuncs.h */
42+static inline gboolean
43+g_set_str (char **str_pointer,
44+ const char *new_str)
45+{
46+ char *copy;
47+
48+ if (*str_pointer == new_str ||
49+ (*str_pointer && new_str && strcmp (*str_pointer, new_str) == 0))
50+ return FALSE;
51+
52+ copy = g_strdup (new_str);
53+ g_free (*str_pointer);
54+ *str_pointer = copy;
55+
56+ return TRUE;
57+}
58+
59 #endif /* __GLIB_PRIVATE_H__ */
60--
612.30.2
62
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_03.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_03.patch
new file mode 100644
index 0000000000..833e2b51a4
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_03.patch
@@ -0,0 +1,985 @@
1From 8b1d90457e2e72f1d7db7cb77b74754af3a5c4ef Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@collabora.com>
3Date: Fri, 8 Mar 2024 14:19:46 +0000
4Subject: [PATCH 03/18] tests: Add a data-driven test for signal subscriptions
5
6This somewhat duplicates test_connection_signals(), but is easier to
7extend to cover different scenarios.
8
9Each scenario is tested three times: once with lower-level
10GDBusConnection APIs, once with the higher-level GDBusProxy (which
11cannot implement all of the subscription scenarios, so some message
12counts are lower), and once with both (to check that delivery of the
13same message to multiple destinations is handled appropriately).
14
15[Backported to glib-2-74, resolving conflicts in gio/tests/meson.build]
16Signed-off-by: Simon McVittie <smcv@collabora.com>
17
18CVE: CVE-2024-34397
19Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/8b1d90457e2e72f1d7db7cb77b74754af3a5c4ef]
20Signed-off-by: Peter Marko <peter.marko@siemens.com>
21---
22 gio/tests/gdbus-subscribe.c | 938 ++++++++++++++++++++++++++++++++++++
23 gio/tests/meson.build | 1 +
24 2 files changed, 939 insertions(+)
25 create mode 100644 gio/tests/gdbus-subscribe.c
26
27diff --git a/gio/tests/gdbus-subscribe.c b/gio/tests/gdbus-subscribe.c
28new file mode 100644
29index 000000000..3f53e1d7f
30--- /dev/null
31+++ b/gio/tests/gdbus-subscribe.c
32@@ -0,0 +1,938 @@
33+/*
34+ * Copyright 2024 Collabora Ltd.
35+ * SPDX-License-Identifier: LGPL-2.1-or-later
36+ */
37+
38+#include <gio/gio.h>
39+
40+#include "gdbus-tests.h"
41+
42+#define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
43+#define DBUS_PATH_DBUS "/org/freedesktop/DBus"
44+#define DBUS_INTERFACE_DBUS DBUS_SERVICE_DBUS
45+
46+/* A signal that each connection emits to indicate that it has finished
47+ * emitting other signals */
48+#define FINISHED_PATH "/org/gtk/Test/Finished"
49+#define FINISHED_INTERFACE "org.gtk.Test.Finished"
50+#define FINISHED_SIGNAL "Finished"
51+
52+/* A signal emitted during testing */
53+#define EXAMPLE_PATH "/org/gtk/GDBus/ExampleInterface"
54+#define EXAMPLE_INTERFACE "org.gtk.GDBus.ExampleInterface"
55+#define FOO_SIGNAL "Foo"
56+
57+/* Log @s in a debug message. */
58+static inline const char *
59+nonnull (const char *s,
60+ const char *if_null)
61+{
62+ return (s == NULL) ? if_null : s;
63+}
64+
65+typedef enum
66+{
67+ TEST_CONN_NONE,
68+ TEST_CONN_FIRST,
69+ /* A connection that subscribes to signals */
70+ TEST_CONN_SUBSCRIBER = TEST_CONN_FIRST,
71+ /* A mockup of a legitimate service */
72+ TEST_CONN_SERVICE,
73+ /* A mockup of a second legitimate service */
74+ TEST_CONN_SERVICE2,
75+ /* A connection that tries to trick @subscriber into processing its signals
76+ * as if they came from @service */
77+ TEST_CONN_ATTACKER,
78+ NUM_TEST_CONNS
79+} TestConn;
80+
81+static const char * const test_conn_descriptions[NUM_TEST_CONNS] =
82+{
83+ "(unused)",
84+ "subscriber",
85+ "service",
86+ "service 2",
87+ "attacker"
88+};
89+
90+typedef enum
91+{
92+ SUBSCRIPTION_MODE_CONN,
93+ SUBSCRIPTION_MODE_PROXY,
94+ SUBSCRIPTION_MODE_PARALLEL
95+} SubscriptionMode;
96+
97+typedef struct
98+{
99+ GDBusProxy *received_by_proxy;
100+ TestConn sender;
101+ char *path;
102+ char *iface;
103+ char *member;
104+ GVariant *parameters;
105+ char *arg0;
106+ guint32 step;
107+} ReceivedMessage;
108+
109+static void
110+received_message_free (ReceivedMessage *self)
111+{
112+
113+ g_clear_object (&self->received_by_proxy);
114+ g_free (self->path);
115+ g_free (self->iface);
116+ g_free (self->member);
117+ g_clear_pointer (&self->parameters, g_variant_unref);
118+ g_free (self->arg0);
119+ g_free (self);
120+}
121+
122+typedef struct
123+{
124+ TestConn sender;
125+ TestConn unicast_to;
126+ const char *path;
127+ const char *iface;
128+ const char *member;
129+ const char *arg0;
130+ guint received_by_conn;
131+ guint received_by_proxy;
132+} TestEmitSignal;
133+
134+typedef struct
135+{
136+ TestConn sender;
137+ const char *path;
138+ const char *iface;
139+ const char *member;
140+ const char *arg0;
141+ GDBusSignalFlags flags;
142+} TestSubscribe;
143+
144+typedef enum
145+{
146+ TEST_ACTION_NONE = 0,
147+ TEST_ACTION_SUBSCRIBE,
148+ TEST_ACTION_EMIT_SIGNAL,
149+} TestAction;
150+
151+typedef struct
152+{
153+ TestAction action;
154+ union {
155+ TestEmitSignal signal;
156+ TestSubscribe subscribe;
157+ } u;
158+} TestStep;
159+
160+/* Arbitrary, extend as necessary to accommodate the longest test */
161+#define MAX_TEST_STEPS 10
162+
163+typedef struct
164+{
165+ const char *description;
166+ TestStep steps[MAX_TEST_STEPS];
167+} TestPlan;
168+
169+static const TestPlan plan_simple =
170+{
171+ .description = "A broadcast is only received after subscribing to it",
172+ .steps = {
173+ {
174+ /* We don't receive a signal if we haven't subscribed yet */
175+ .action = TEST_ACTION_EMIT_SIGNAL,
176+ .u.signal = {
177+ .sender = TEST_CONN_SERVICE,
178+ .path = EXAMPLE_PATH,
179+ .iface = EXAMPLE_INTERFACE,
180+ .member = FOO_SIGNAL,
181+ .received_by_conn = 0,
182+ .received_by_proxy = 0
183+ },
184+ },
185+ {
186+ .action = TEST_ACTION_SUBSCRIBE,
187+ .u.subscribe = {
188+ .path = EXAMPLE_PATH,
189+ .iface = EXAMPLE_INTERFACE,
190+ },
191+ },
192+ {
193+ /* Now it works */
194+ .action = TEST_ACTION_EMIT_SIGNAL,
195+ .u.signal = {
196+ .sender = TEST_CONN_SERVICE,
197+ .path = EXAMPLE_PATH,
198+ .iface = EXAMPLE_INTERFACE,
199+ .member = FOO_SIGNAL,
200+ .received_by_conn = 1,
201+ /* The proxy can't be used in this case, because it needs
202+ * a bus name to subscribe to */
203+ .received_by_proxy = 0
204+ },
205+ },
206+ },
207+};
208+
209+static const TestPlan plan_broadcast_from_anyone =
210+{
211+ .description = "A subscription with NULL sender accepts broadcast and unicast",
212+ .steps = {
213+ {
214+ /* Subscriber wants to receive signals from anyone */
215+ .action = TEST_ACTION_SUBSCRIBE,
216+ .u.subscribe = {
217+ .path = EXAMPLE_PATH,
218+ .iface = EXAMPLE_INTERFACE,
219+ },
220+ },
221+ {
222+ /* First service sends a broadcast */
223+ .action = TEST_ACTION_EMIT_SIGNAL,
224+ .u.signal = {
225+ .sender = TEST_CONN_SERVICE,
226+ .path = EXAMPLE_PATH,
227+ .iface = EXAMPLE_INTERFACE,
228+ .member = FOO_SIGNAL,
229+ .received_by_conn = 1,
230+ .received_by_proxy = 0
231+ },
232+ },
233+ {
234+ /* Second service also sends a broadcast */
235+ .action = TEST_ACTION_EMIT_SIGNAL,
236+ .u.signal = {
237+ .sender = TEST_CONN_SERVICE2,
238+ .path = EXAMPLE_PATH,
239+ .iface = EXAMPLE_INTERFACE,
240+ .member = FOO_SIGNAL,
241+ .received_by_conn = 1,
242+ .received_by_proxy = 0
243+ },
244+ },
245+ {
246+ /* First service sends a unicast signal */
247+ .action = TEST_ACTION_EMIT_SIGNAL,
248+ .u.signal = {
249+ .sender = TEST_CONN_SERVICE,
250+ .unicast_to = TEST_CONN_SUBSCRIBER,
251+ .path = EXAMPLE_PATH,
252+ .iface = EXAMPLE_INTERFACE,
253+ .member = FOO_SIGNAL,
254+ .received_by_conn = 1,
255+ .received_by_proxy = 0
256+ },
257+ },
258+ {
259+ /* Second service also sends a unicast signal */
260+ .action = TEST_ACTION_EMIT_SIGNAL,
261+ .u.signal = {
262+ .sender = TEST_CONN_SERVICE2,
263+ .unicast_to = TEST_CONN_SUBSCRIBER,
264+ .path = EXAMPLE_PATH,
265+ .iface = EXAMPLE_INTERFACE,
266+ .member = FOO_SIGNAL,
267+ .received_by_conn = 1,
268+ .received_by_proxy = 0
269+ },
270+ },
271+ },
272+};
273+
274+static const TestPlan plan_match_twice =
275+{
276+ .description = "A message matching more than one subscription is received "
277+ "once per subscription",
278+ .steps = {
279+ {
280+ .action = TEST_ACTION_SUBSCRIBE,
281+ .u.subscribe = {
282+ .sender = TEST_CONN_SERVICE,
283+ .path = EXAMPLE_PATH,
284+ .iface = EXAMPLE_INTERFACE,
285+ },
286+ },
287+ {
288+ .action = TEST_ACTION_SUBSCRIBE,
289+ .u.subscribe = {
290+ .path = EXAMPLE_PATH,
291+ },
292+ },
293+ {
294+ .action = TEST_ACTION_SUBSCRIBE,
295+ .u.subscribe = {
296+ .iface = EXAMPLE_INTERFACE,
297+ },
298+ },
299+ {
300+ .action = TEST_ACTION_SUBSCRIBE,
301+ .u.subscribe = {
302+ .sender = TEST_CONN_SERVICE,
303+ .path = EXAMPLE_PATH,
304+ .iface = EXAMPLE_INTERFACE,
305+ },
306+ },
307+ {
308+ .action = TEST_ACTION_EMIT_SIGNAL,
309+ .u.signal = {
310+ .sender = TEST_CONN_SERVICE,
311+ .path = EXAMPLE_PATH,
312+ .iface = EXAMPLE_INTERFACE,
313+ .member = FOO_SIGNAL,
314+ .received_by_conn = 4,
315+ /* Only the first and last work with GDBusProxy */
316+ .received_by_proxy = 2
317+ },
318+ },
319+ },
320+};
321+
322+static const TestPlan plan_limit_by_unique_name =
323+{
324+ .description = "A subscription via a unique name only accepts messages "
325+ "sent by that same unique name",
326+ .steps = {
327+ {
328+ /* Subscriber wants to receive signals from service */
329+ .action = TEST_ACTION_SUBSCRIBE,
330+ .u.subscribe = {
331+ .sender = TEST_CONN_SERVICE,
332+ .path = EXAMPLE_PATH,
333+ .iface = EXAMPLE_INTERFACE,
334+ },
335+ },
336+ {
337+ /* Attacker wants to trick subscriber into thinking that service
338+ * sent a signal */
339+ .action = TEST_ACTION_EMIT_SIGNAL,
340+ .u.signal = {
341+ .sender = TEST_CONN_ATTACKER,
342+ .path = EXAMPLE_PATH,
343+ .iface = EXAMPLE_INTERFACE,
344+ .member = FOO_SIGNAL,
345+ .received_by_conn = 0,
346+ .received_by_proxy = 0
347+ },
348+ },
349+ {
350+ /* Attacker tries harder, by sending a signal unicast directly to
351+ * the subscriber */
352+ .action = TEST_ACTION_EMIT_SIGNAL,
353+ .u.signal = {
354+ .sender = TEST_CONN_ATTACKER,
355+ .unicast_to = TEST_CONN_SUBSCRIBER,
356+ .path = EXAMPLE_PATH,
357+ .iface = EXAMPLE_INTERFACE,
358+ .member = FOO_SIGNAL,
359+ .received_by_conn = 0,
360+ .received_by_proxy = 0
361+ },
362+ },
363+ {
364+ /* When the real service sends a signal, it should still get through */
365+ .action = TEST_ACTION_EMIT_SIGNAL,
366+ .u.signal = {
367+ .sender = TEST_CONN_SERVICE,
368+ .path = EXAMPLE_PATH,
369+ .iface = EXAMPLE_INTERFACE,
370+ .member = FOO_SIGNAL,
371+ .received_by_conn = 1,
372+ .received_by_proxy = 1
373+ },
374+ },
375+ },
376+};
377+
378+typedef struct
379+{
380+ const TestPlan *plan;
381+ SubscriptionMode mode;
382+ GError *error;
383+ /* (element-type ReceivedMessage) */
384+ GPtrArray *received;
385+ /* conns[TEST_CONN_NONE] is unused and remains NULL */
386+ GDBusConnection *conns[NUM_TEST_CONNS];
387+ /* Proxies on conns[TEST_CONN_SUBSCRIBER] */
388+ GPtrArray *proxies;
389+ /* unique_names[TEST_CONN_NONE] is unused and remains NULL */
390+ const char *unique_names[NUM_TEST_CONNS];
391+ /* finished[TEST_CONN_NONE] is unused and remains FALSE */
392+ gboolean finished[NUM_TEST_CONNS];
393+ /* Remains 0 for any step that is not a subscription */
394+ guint subscriptions[MAX_TEST_STEPS];
395+ /* Number of times the signal from step n was received */
396+ guint received_by_conn[MAX_TEST_STEPS];
397+ /* Number of times the signal from step n was received */
398+ guint received_by_proxy[MAX_TEST_STEPS];
399+ guint finished_subscription;
400+} Fixture;
401+
402+/* Wait for asynchronous messages from @conn to have been processed
403+ * by the message bus, as a sequence point so that we can make
404+ * "happens before" and "happens after" assertions relative to this.
405+ * The easiest way to achieve this is to call a message bus method that has
406+ * no arguments and wait for it to return: because the message bus processes
407+ * messages in-order, anything we sent before this must have been processed
408+ * by the time this call arrives. */
409+static void
410+connection_wait_for_bus (GDBusConnection *conn)
411+{
412+ GError *error = NULL;
413+ GVariant *call_result;
414+
415+ call_result = g_dbus_connection_call_sync (conn,
416+ DBUS_SERVICE_DBUS,
417+ DBUS_PATH_DBUS,
418+ DBUS_INTERFACE_DBUS,
419+ "GetId",
420+ NULL, /* arguments */
421+ NULL, /* result type */
422+ G_DBUS_CALL_FLAGS_NONE,
423+ -1,
424+ NULL,
425+ &error);
426+ g_assert_no_error (error);
427+ g_assert_nonnull (call_result);
428+ g_variant_unref (call_result);
429+}
430+
431+/*
432+ * Called when the subscriber receives a message from any connection
433+ * announcing that it has emitted all the signals that it plans to emit.
434+ */
435+static void
436+subscriber_finished_cb (GDBusConnection *conn,
437+ const char *sender_name,
438+ const char *path,
439+ const char *iface,
440+ const char *member,
441+ GVariant *parameters,
442+ void *user_data)
443+{
444+ Fixture *f = user_data;
445+ GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER];
446+ guint i;
447+
448+ g_assert_true (conn == subscriber);
449+
450+ for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++)
451+ {
452+ if (g_str_equal (sender_name, f->unique_names[i]))
453+ {
454+ g_assert_false (f->finished[i]);
455+ f->finished[i] = TRUE;
456+
457+ g_test_message ("Received Finished signal from %s %s",
458+ test_conn_descriptions[i], sender_name);
459+ return;
460+ }
461+ }
462+
463+ g_error ("Received Finished signal from unknown sender %s", sender_name);
464+}
465+
466+/*
467+ * Called when we receive a signal, either via the GDBusProxy (proxy != NULL)
468+ * or via the GDBusConnection (proxy == NULL).
469+ */
470+static void
471+fixture_received_signal (Fixture *f,
472+ GDBusProxy *proxy,
473+ const char *sender_name,
474+ const char *path,
475+ const char *iface,
476+ const char *member,
477+ GVariant *parameters)
478+{
479+ guint i;
480+ ReceivedMessage *received;
481+
482+ /* Ignore the Finished signal if it matches a wildcard subscription */
483+ if (g_str_equal (member, FINISHED_SIGNAL))
484+ return;
485+
486+ received = g_new0 (ReceivedMessage, 1);
487+
488+ if (proxy != NULL)
489+ received->received_by_proxy = g_object_ref (proxy);
490+ else
491+ received->received_by_proxy = NULL;
492+
493+ received->path = g_strdup (path);
494+ received->iface = g_strdup (iface);
495+ received->member = g_strdup (member);
496+ received->parameters = g_variant_ref (parameters);
497+
498+ for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++)
499+ {
500+ if (g_str_equal (sender_name, f->unique_names[i]))
501+ {
502+ received->sender = i;
503+ g_assert_false (f->finished[i]);
504+ break;
505+ }
506+ }
507+
508+ g_assert_cmpint (received->sender, !=, TEST_CONN_NONE);
509+
510+ g_test_message ("Signal received from %s %s via %s",
511+ test_conn_descriptions[received->sender],
512+ sender_name,
513+ proxy != NULL ? "proxy" : "connection");
514+ g_test_message ("\tPath: %s", path);
515+ g_test_message ("\tInterface: %s", iface);
516+ g_test_message ("\tMember: %s", member);
517+
518+ if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(su)")))
519+ {
520+ g_variant_get (parameters, "(su)", &received->arg0, &received->step);
521+ g_test_message ("\tString argument 0: %s", received->arg0);
522+ g_test_message ("\tSent in step: %u", received->step);
523+ }
524+ else
525+ {
526+ g_assert_cmpstr (g_variant_get_type_string (parameters), ==, "(uu)");
527+ g_variant_get (parameters, "(uu)", NULL, &received->step);
528+ g_test_message ("\tArgument 0: (not a string)");
529+ g_test_message ("\tSent in step: %u", received->step);
530+ }
531+
532+ g_ptr_array_add (f->received, g_steal_pointer (&received));
533+}
534+
535+static void
536+proxy_signal_cb (GDBusProxy *proxy,
537+ const char *sender_name,
538+ const char *member,
539+ GVariant *parameters,
540+ void *user_data)
541+{
542+ Fixture *f = user_data;
543+
544+ fixture_received_signal (f, proxy, sender_name,
545+ g_dbus_proxy_get_object_path (proxy),
546+ g_dbus_proxy_get_interface_name (proxy),
547+ member, parameters);
548+}
549+
550+static void
551+subscribed_signal_cb (GDBusConnection *conn,
552+ const char *sender_name,
553+ const char *path,
554+ const char *iface,
555+ const char *member,
556+ GVariant *parameters,
557+ void *user_data)
558+{
559+ Fixture *f = user_data;
560+ GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER];
561+
562+ g_assert_true (conn == subscriber);
563+
564+ fixture_received_signal (f, NULL, sender_name, path, iface, member, parameters);
565+}
566+
567+static void
568+fixture_subscribe (Fixture *f,
569+ const TestSubscribe *subscribe,
570+ guint step_number)
571+{
572+ GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER];
573+ const char *sender;
574+
575+ if (subscribe->sender != TEST_CONN_NONE)
576+ {
577+ sender = f->unique_names[subscribe->sender];
578+ g_test_message ("\tSender: %s %s",
579+ test_conn_descriptions[subscribe->sender],
580+ sender);
581+ }
582+ else
583+ {
584+ sender = NULL;
585+ g_test_message ("\tSender: (any)");
586+ }
587+
588+ g_test_message ("\tPath: %s", nonnull (subscribe->path, "(any)"));
589+ g_test_message ("\tInterface: %s",
590+ nonnull (subscribe->iface, "(any)"));
591+ g_test_message ("\tMember: %s",
592+ nonnull (subscribe->member, "(any)"));
593+ g_test_message ("\tString argument 0: %s",
594+ nonnull (subscribe->arg0, "(any)"));
595+ g_test_message ("\tFlags: %x", subscribe->flags);
596+
597+ if (f->mode != SUBSCRIPTION_MODE_PROXY)
598+ {
599+ /* CONN or PARALLEL */
600+ guint id;
601+
602+ g_test_message ("\tSubscribing via connection");
603+ id = g_dbus_connection_signal_subscribe (subscriber,
604+ sender,
605+ subscribe->iface,
606+ subscribe->member,
607+ subscribe->path,
608+ subscribe->arg0,
609+ subscribe->flags,
610+ subscribed_signal_cb,
611+ f, NULL);
612+ g_assert_cmpuint (id, !=, 0);
613+ f->subscriptions[step_number] = id;
614+ }
615+
616+ if (f->mode != SUBSCRIPTION_MODE_CONN)
617+ {
618+ /* PROXY or PARALLEL */
619+
620+ if (sender == NULL)
621+ {
622+ g_test_message ("\tCannot subscribe via proxy: no bus name");
623+ }
624+ else if (subscribe->path == NULL)
625+ {
626+ g_test_message ("\tCannot subscribe via proxy: no path");
627+ }
628+ else if (subscribe->iface == NULL)
629+ {
630+ g_test_message ("\tCannot subscribe via proxy: no interface");
631+ }
632+ else
633+ {
634+ GDBusProxy *proxy;
635+
636+ g_test_message ("\tSubscribing via proxy");
637+ proxy = g_dbus_proxy_new_sync (subscriber,
638+ (G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
639+ | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START),
640+ NULL, /* GDBusInterfaceInfo */
641+ sender,
642+ subscribe->path,
643+ subscribe->iface,
644+ NULL, /* GCancellable */
645+ &f->error);
646+ g_assert_no_error (f->error);
647+ g_assert_nonnull (proxy);
648+ g_signal_connect (proxy, "g-signal", G_CALLBACK (proxy_signal_cb), f);
649+ g_ptr_array_add (f->proxies, g_steal_pointer (&proxy));
650+ }
651+ }
652+
653+ /* As in setup(), we need to wait for AddMatch to happen. */
654+ g_test_message ("Waiting for AddMatch to be processed");
655+ connection_wait_for_bus (subscriber);
656+}
657+
658+static void
659+fixture_emit_signal (Fixture *f,
660+ const TestEmitSignal *signal,
661+ guint step_number)
662+{
663+ GVariant *body;
664+ const char *destination;
665+ gboolean ok;
666+
667+ g_test_message ("\tSender: %s",
668+ test_conn_descriptions[signal->sender]);
669+
670+ if (signal->unicast_to != TEST_CONN_NONE)
671+ {
672+ destination = f->unique_names[signal->unicast_to];
673+ g_test_message ("\tDestination: %s %s",
674+ test_conn_descriptions[signal->unicast_to],
675+ destination);
676+ }
677+ else
678+ {
679+ destination = NULL;
680+ g_test_message ("\tDestination: (broadcast)");
681+ }
682+
683+ g_assert_nonnull (signal->path);
684+ g_test_message ("\tPath: %s", signal->path);
685+ g_assert_nonnull (signal->iface);
686+ g_test_message ("\tInterface: %s", signal->iface);
687+ g_assert_nonnull (signal->member);
688+ g_test_message ("\tMember: %s", signal->member);
689+
690+ /* If arg0 is non-NULL, put it in the message's argument 0.
691+ * Otherwise put something that will not match any arg0.
692+ * Either way, put the sequence number in argument 1 so we can
693+ * correlate sent messages with received messages later. */
694+ if (signal->arg0 != NULL)
695+ {
696+ g_test_message ("\tString argument 0: %s", signal->arg0);
697+ /* floating */
698+ body = g_variant_new ("(su)", signal->arg0, (guint32) step_number);
699+ }
700+ else
701+ {
702+ g_test_message ("\tArgument 0: (not a string)");
703+ body = g_variant_new ("(uu)", (guint32) 0, (guint32) step_number);
704+ }
705+
706+ ok = g_dbus_connection_emit_signal (f->conns[signal->sender],
707+ destination,
708+ signal->path,
709+ signal->iface,
710+ signal->member,
711+ /* steals floating reference */
712+ g_steal_pointer (&body),
713+ &f->error);
714+ g_assert_no_error (f->error);
715+ g_assert_true (ok);
716+
717+ /* Emitting the signal is asynchronous, so if we want subsequent steps
718+ * to be guaranteed to happen after the signal from the message bus's
719+ * perspective, we have to do a round-trip to the message bus to sync up. */
720+ g_test_message ("Waiting for signal to reach message bus");
721+ connection_wait_for_bus (f->conns[signal->sender]);
722+}
723+
724+static void
725+fixture_run_plan (Fixture *f,
726+ const TestPlan *plan,
727+ SubscriptionMode mode)
728+{
729+ guint i;
730+
731+ G_STATIC_ASSERT (G_N_ELEMENTS (plan->steps) == G_N_ELEMENTS (f->subscriptions));
732+ G_STATIC_ASSERT (G_N_ELEMENTS (plan->steps) == G_N_ELEMENTS (f->received_by_conn));
733+ G_STATIC_ASSERT (G_N_ELEMENTS (plan->steps) == G_N_ELEMENTS (f->received_by_proxy));
734+
735+ f->mode = mode;
736+ f->plan = plan;
737+
738+ g_test_summary (plan->description);
739+
740+ for (i = 0; i < G_N_ELEMENTS (plan->steps); i++)
741+ {
742+ const TestStep *step = &plan->steps[i];
743+
744+ switch (step->action)
745+ {
746+ case TEST_ACTION_SUBSCRIBE:
747+ g_test_message ("Step %u: adding subscription", i);
748+ fixture_subscribe (f, &step->u.subscribe, i);
749+ break;
750+
751+ case TEST_ACTION_EMIT_SIGNAL:
752+ g_test_message ("Step %u: emitting signal", i);
753+ fixture_emit_signal (f, &step->u.signal, i);
754+ break;
755+
756+ case TEST_ACTION_NONE:
757+ /* Padding to fill the rest of the array, do nothing */
758+ break;
759+
760+ default:
761+ g_return_if_reached ();
762+ }
763+ }
764+
765+ /* Now that we have done everything we wanted to do, emit Finished
766+ * from each connection. */
767+ for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++)
768+ {
769+ gboolean ok;
770+
771+ ok = g_dbus_connection_emit_signal (f->conns[i],
772+ NULL,
773+ FINISHED_PATH,
774+ FINISHED_INTERFACE,
775+ FINISHED_SIGNAL,
776+ NULL,
777+ &f->error);
778+ g_assert_no_error (f->error);
779+ g_assert_true (ok);
780+ }
781+
782+ /* Wait until we have seen the Finished signal from each sender */
783+ while (TRUE)
784+ {
785+ gboolean all_finished = TRUE;
786+
787+ for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++)
788+ all_finished = all_finished && f->finished[i];
789+
790+ if (all_finished)
791+ break;
792+
793+ g_main_context_iteration (NULL, TRUE);
794+ }
795+
796+ /* Assert that the correct things happened before each Finished signal */
797+ for (i = 0; i < f->received->len; i++)
798+ {
799+ const ReceivedMessage *received = g_ptr_array_index (f->received, i);
800+
801+ g_assert_cmpuint (received->step, <, G_N_ELEMENTS (f->received_by_conn));
802+ g_assert_cmpuint (received->step, <, G_N_ELEMENTS (f->received_by_proxy));
803+ g_assert_cmpint (plan->steps[received->step].action,
804+ ==, TEST_ACTION_EMIT_SIGNAL);
805+
806+ if (received->received_by_proxy != NULL)
807+ f->received_by_proxy[received->step] += 1;
808+ else
809+ f->received_by_conn[received->step] += 1;
810+ }
811+
812+ for (i = 0; i < G_N_ELEMENTS (plan->steps); i++)
813+ {
814+ const TestStep *step = &plan->steps[i];
815+
816+ if (step->action == TEST_ACTION_EMIT_SIGNAL)
817+ {
818+ const TestEmitSignal *signal = &plan->steps[i].u.signal;
819+
820+ if (mode != SUBSCRIPTION_MODE_PROXY)
821+ {
822+ g_test_message ("Signal from step %u was received %u times by "
823+ "GDBusConnection, expected %u",
824+ i, f->received_by_conn[i], signal->received_by_conn);
825+ g_assert_cmpuint (f->received_by_conn[i], ==, signal->received_by_conn);
826+ }
827+ else
828+ {
829+ g_assert_cmpuint (f->received_by_conn[i], ==, 0);
830+ }
831+
832+ if (mode != SUBSCRIPTION_MODE_CONN)
833+ {
834+ g_test_message ("Signal from step %u was received %u times by "
835+ "GDBusProxy, expected %u",
836+ i, f->received_by_proxy[i], signal->received_by_proxy);
837+ g_assert_cmpuint (f->received_by_proxy[i], ==, signal->received_by_proxy);
838+ }
839+ else
840+ {
841+ g_assert_cmpuint (f->received_by_proxy[i], ==, 0);
842+ }
843+ }
844+ }
845+}
846+
847+static void
848+setup (Fixture *f,
849+ G_GNUC_UNUSED const void *context)
850+{
851+ GDBusConnection *subscriber;
852+ guint i;
853+
854+ session_bus_up ();
855+
856+ f->proxies = g_ptr_array_new_full (MAX_TEST_STEPS, g_object_unref);
857+ f->received = g_ptr_array_new_full (MAX_TEST_STEPS,
858+ (GDestroyNotify) received_message_free);
859+
860+ for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++)
861+ {
862+ f->conns[i] = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, &f->error);
863+ g_assert_no_error (f->error);
864+ g_assert_nonnull (f->conns[i]);
865+
866+ f->unique_names[i] = g_dbus_connection_get_unique_name (f->conns[i]);
867+ g_assert_nonnull (f->unique_names[i]);
868+ g_test_message ("%s is %s",
869+ test_conn_descriptions[i],
870+ f->unique_names[i]);
871+ }
872+
873+ subscriber = f->conns[TEST_CONN_SUBSCRIBER];
874+
875+ /* Used to wait for all connections to finish sending whatever they
876+ * wanted to send */
877+ f->finished_subscription = g_dbus_connection_signal_subscribe (subscriber,
878+ NULL,
879+ FINISHED_INTERFACE,
880+ FINISHED_SIGNAL,
881+ FINISHED_PATH,
882+ NULL,
883+ G_DBUS_SIGNAL_FLAGS_NONE,
884+ subscriber_finished_cb,
885+ f, NULL);
886+ /* AddMatch is sent asynchronously, so we don't know how
887+ * soon it will be processed. Before emitting signals, we
888+ * need to wait for the message bus to get as far as processing
889+ * AddMatch. */
890+ g_test_message ("Waiting for AddMatch to be processed");
891+ connection_wait_for_bus (subscriber);
892+}
893+
894+static void
895+test_conn_subscribe (Fixture *f,
896+ const void *context)
897+{
898+ fixture_run_plan (f, context, SUBSCRIPTION_MODE_CONN);
899+}
900+
901+static void
902+test_proxy_subscribe (Fixture *f,
903+ const void *context)
904+{
905+ fixture_run_plan (f, context, SUBSCRIPTION_MODE_PROXY);
906+}
907+
908+static void
909+test_parallel_subscribe (Fixture *f,
910+ const void *context)
911+{
912+ fixture_run_plan (f, context, SUBSCRIPTION_MODE_PARALLEL);
913+}
914+
915+static void
916+teardown (Fixture *f,
917+ G_GNUC_UNUSED const void *context)
918+{
919+ GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER];
920+ guint i;
921+
922+ g_ptr_array_unref (f->proxies);
923+
924+ if (f->finished_subscription != 0)
925+ g_dbus_connection_signal_unsubscribe (subscriber, f->finished_subscription);
926+
927+ for (i = 0; i < G_N_ELEMENTS (f->subscriptions); i++)
928+ {
929+ if (f->subscriptions[i] != 0)
930+ g_dbus_connection_signal_unsubscribe (subscriber, f->subscriptions[i]);
931+ }
932+
933+ g_ptr_array_unref (f->received);
934+
935+ for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++)
936+ g_clear_object (&f->conns[i]);
937+
938+ g_clear_error (&f->error);
939+
940+ session_bus_down ();
941+}
942+
943+int
944+main (int argc,
945+ char *argv[])
946+{
947+ g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
948+
949+ g_test_dbus_unset ();
950+
951+#define ADD_SUBSCRIBE_TEST(name) \
952+ do { \
953+ g_test_add ("/gdbus/subscribe/conn/" #name, \
954+ Fixture, &plan_ ## name, \
955+ setup, test_conn_subscribe, teardown); \
956+ g_test_add ("/gdbus/subscribe/proxy/" #name, \
957+ Fixture, &plan_ ## name, \
958+ setup, test_proxy_subscribe, teardown); \
959+ g_test_add ("/gdbus/subscribe/parallel/" #name, \
960+ Fixture, &plan_ ## name, \
961+ setup, test_parallel_subscribe, teardown); \
962+ } while (0)
963+
964+ ADD_SUBSCRIBE_TEST (simple);
965+ ADD_SUBSCRIBE_TEST (broadcast_from_anyone);
966+ ADD_SUBSCRIBE_TEST (match_twice);
967+ ADD_SUBSCRIBE_TEST (limit_by_unique_name);
968+
969+ return g_test_run();
970+}
971diff --git a/gio/tests/meson.build b/gio/tests/meson.build
972index 383d84319..a1551aa53 100644
973--- a/gio/tests/meson.build
974+++ b/gio/tests/meson.build
975@@ -354,6 +354,7 @@ if host_machine.system() != 'windows'
976 },
977 'gdbus-proxy-unique-name' : {'extra_sources' : extra_sources},
978 'gdbus-proxy-well-known-name' : {'extra_sources' : extra_sources},
979+ 'gdbus-subscribe' : {'extra_sources' : extra_sources},
980 'gdbus-test-codegen' : {
981 'extra_sources' : [extra_sources, gdbus_test_codegen_generated, gdbus_test_codegen_generated_interface_info],
982 'c_args' : ['-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_32'],
983--
9842.30.2
985
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_04.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_04.patch
new file mode 100644
index 0000000000..144afd0d51
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_04.patch
@@ -0,0 +1,253 @@
1From a87931c257a6bb1b7c104623beadd9b14d766ca6 Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@collabora.com>
3Date: Fri, 8 Mar 2024 19:28:15 +0000
4Subject: [PATCH 04/18] tests: Add support for subscribing to signals from a
5 well-known name
6
7Signed-off-by: Simon McVittie <smcv@collabora.com>
8
9CVE: CVE-2024-34397
10Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/a87931c257a6bb1b7c104623beadd9b14d766ca6]
11Signed-off-by: Peter Marko <peter.marko@siemens.com>
12---
13 gio/tests/gdbus-subscribe.c | 133 ++++++++++++++++++++++++++++++++++--
14 1 file changed, 126 insertions(+), 7 deletions(-)
15
16diff --git a/gio/tests/gdbus-subscribe.c b/gio/tests/gdbus-subscribe.c
17index 3f53e1d7f..3d2a14e03 100644
18--- a/gio/tests/gdbus-subscribe.c
19+++ b/gio/tests/gdbus-subscribe.c
20@@ -7,6 +7,9 @@
21
22 #include "gdbus-tests.h"
23
24+/* From the D-Bus Specification */
25+#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1
26+
27 #define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
28 #define DBUS_PATH_DBUS "/org/freedesktop/DBus"
29 #define DBUS_INTERFACE_DBUS DBUS_SERVICE_DBUS
30@@ -22,6 +25,9 @@
31 #define EXAMPLE_INTERFACE "org.gtk.GDBus.ExampleInterface"
32 #define FOO_SIGNAL "Foo"
33
34+#define ALREADY_OWNED_NAME "org.gtk.Test.AlreadyOwned"
35+#define OWNED_LATER_NAME "org.gtk.Test.OwnedLater"
36+
37 /* Log @s in a debug message. */
38 static inline const char *
39 nonnull (const char *s,
40@@ -101,7 +107,8 @@ typedef struct
41
42 typedef struct
43 {
44- TestConn sender;
45+ const char *string_sender;
46+ TestConn unique_sender;
47 const char *path;
48 const char *iface;
49 const char *member;
50@@ -109,11 +116,18 @@ typedef struct
51 GDBusSignalFlags flags;
52 } TestSubscribe;
53
54+typedef struct
55+{
56+ const char *name;
57+ TestConn owner;
58+} TestOwnName;
59+
60 typedef enum
61 {
62 TEST_ACTION_NONE = 0,
63 TEST_ACTION_SUBSCRIBE,
64 TEST_ACTION_EMIT_SIGNAL,
65+ TEST_ACTION_OWN_NAME,
66 } TestAction;
67
68 typedef struct
69@@ -122,6 +136,7 @@ typedef struct
70 union {
71 TestEmitSignal signal;
72 TestSubscribe subscribe;
73+ TestOwnName own_name;
74 } u;
75 } TestStep;
76
77@@ -247,7 +262,7 @@ static const TestPlan plan_match_twice =
78 {
79 .action = TEST_ACTION_SUBSCRIBE,
80 .u.subscribe = {
81- .sender = TEST_CONN_SERVICE,
82+ .unique_sender = TEST_CONN_SERVICE,
83 .path = EXAMPLE_PATH,
84 .iface = EXAMPLE_INTERFACE,
85 },
86@@ -267,7 +282,7 @@ static const TestPlan plan_match_twice =
87 {
88 .action = TEST_ACTION_SUBSCRIBE,
89 .u.subscribe = {
90- .sender = TEST_CONN_SERVICE,
91+ .unique_sender = TEST_CONN_SERVICE,
92 .path = EXAMPLE_PATH,
93 .iface = EXAMPLE_INTERFACE,
94 },
95@@ -296,7 +311,7 @@ static const TestPlan plan_limit_by_unique_name =
96 /* Subscriber wants to receive signals from service */
97 .action = TEST_ACTION_SUBSCRIBE,
98 .u.subscribe = {
99- .sender = TEST_CONN_SERVICE,
100+ .unique_sender = TEST_CONN_SERVICE,
101 .path = EXAMPLE_PATH,
102 .iface = EXAMPLE_INTERFACE,
103 },
104@@ -343,6 +358,62 @@ static const TestPlan plan_limit_by_unique_name =
105 },
106 };
107
108+static const TestPlan plan_limit_by_well_known_name =
109+{
110+ .description = "A subscription via a well-known name only accepts messages "
111+ "sent by the owner of that well-known name",
112+ .steps = {
113+ {
114+ /* Service already owns one name */
115+ .action = TEST_ACTION_OWN_NAME,
116+ .u.own_name = {
117+ .name = ALREADY_OWNED_NAME,
118+ .owner = TEST_CONN_SERVICE
119+ },
120+ },
121+ {
122+ /* Subscriber wants to receive signals from service */
123+ .action = TEST_ACTION_SUBSCRIBE,
124+ .u.subscribe = {
125+ .string_sender = ALREADY_OWNED_NAME,
126+ .path = EXAMPLE_PATH,
127+ .iface = EXAMPLE_INTERFACE,
128+ },
129+ },
130+ {
131+ /* Subscriber wants to receive signals from service by another name */
132+ .action = TEST_ACTION_SUBSCRIBE,
133+ .u.subscribe = {
134+ .string_sender = OWNED_LATER_NAME,
135+ .path = EXAMPLE_PATH,
136+ .iface = EXAMPLE_INTERFACE,
137+ },
138+ },
139+ {
140+ /* Service claims another name */
141+ .action = TEST_ACTION_OWN_NAME,
142+ .u.own_name = {
143+ .name = OWNED_LATER_NAME,
144+ .owner = TEST_CONN_SERVICE
145+ },
146+ },
147+ {
148+ /* Now the subscriber gets this signal twice, once for each
149+ * subscription; and similarly each of the two proxies gets this
150+ * signal twice */
151+ .action = TEST_ACTION_EMIT_SIGNAL,
152+ .u.signal = {
153+ .sender = TEST_CONN_SERVICE,
154+ .path = EXAMPLE_PATH,
155+ .iface = EXAMPLE_INTERFACE,
156+ .member = FOO_SIGNAL,
157+ .received_by_conn = 2,
158+ .received_by_proxy = 2
159+ },
160+ },
161+ },
162+};
163+
164 typedef struct
165 {
166 const TestPlan *plan;
167@@ -540,11 +611,16 @@ fixture_subscribe (Fixture *f,
168 GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER];
169 const char *sender;
170
171- if (subscribe->sender != TEST_CONN_NONE)
172+ if (subscribe->string_sender != NULL)
173 {
174- sender = f->unique_names[subscribe->sender];
175+ sender = subscribe->string_sender;
176+ g_test_message ("\tSender: %s", sender);
177+ }
178+ else if (subscribe->unique_sender != TEST_CONN_NONE)
179+ {
180+ sender = f->unique_names[subscribe->unique_sender];
181 g_test_message ("\tSender: %s %s",
182- test_conn_descriptions[subscribe->sender],
183+ test_conn_descriptions[subscribe->unique_sender],
184 sender);
185 }
186 else
187@@ -689,6 +765,43 @@ fixture_emit_signal (Fixture *f,
188 connection_wait_for_bus (f->conns[signal->sender]);
189 }
190
191+static void
192+fixture_own_name (Fixture *f,
193+ const TestOwnName *own_name)
194+{
195+ GVariant *call_result;
196+ guint32 flags;
197+ guint32 result_code;
198+
199+ g_test_message ("\tName: %s", own_name->name);
200+ g_test_message ("\tOwner: %s",
201+ test_conn_descriptions[own_name->owner]);
202+
203+ /* For simplicity, we do this via a direct bus call rather than
204+ * using g_bus_own_name_on_connection(). The flags in
205+ * GBusNameOwnerFlags are numerically equal to those in the
206+ * D-Bus wire protocol. */
207+ flags = G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE;
208+ call_result = g_dbus_connection_call_sync (f->conns[own_name->owner],
209+ DBUS_SERVICE_DBUS,
210+ DBUS_PATH_DBUS,
211+ DBUS_INTERFACE_DBUS,
212+ "RequestName",
213+ g_variant_new ("(su)",
214+ own_name->name,
215+ flags),
216+ G_VARIANT_TYPE ("(u)"),
217+ G_DBUS_CALL_FLAGS_NONE,
218+ -1,
219+ NULL,
220+ &f->error);
221+ g_assert_no_error (f->error);
222+ g_assert_nonnull (call_result);
223+ g_variant_get (call_result, "(u)", &result_code);
224+ g_assert_cmpuint (result_code, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
225+ g_variant_unref (call_result);
226+}
227+
228 static void
229 fixture_run_plan (Fixture *f,
230 const TestPlan *plan,
231@@ -721,6 +834,11 @@ fixture_run_plan (Fixture *f,
232 fixture_emit_signal (f, &step->u.signal, i);
233 break;
234
235+ case TEST_ACTION_OWN_NAME:
236+ g_test_message ("Step %u: claiming bus name", i);
237+ fixture_own_name (f, &step->u.own_name);
238+ break;
239+
240 case TEST_ACTION_NONE:
241 /* Padding to fill the rest of the array, do nothing */
242 break;
243@@ -933,6 +1051,7 @@ main (int argc,
244 ADD_SUBSCRIBE_TEST (broadcast_from_anyone);
245 ADD_SUBSCRIBE_TEST (match_twice);
246 ADD_SUBSCRIBE_TEST (limit_by_unique_name);
247+ ADD_SUBSCRIBE_TEST (limit_by_well_known_name);
248
249 return g_test_run();
250 }
251--
2522.30.2
253
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_05.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_05.patch
new file mode 100644
index 0000000000..7d929b579a
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_05.patch
@@ -0,0 +1,88 @@
1From 4d4c40e858cb71a229b19f89196e6e02e235eb5b Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@collabora.com>
3Date: Fri, 8 Mar 2024 19:44:03 +0000
4Subject: [PATCH 05/18] tests: Add a test-case for what happens if a unique
5 name doesn't exist
6
7On GNOME/glib#3268 there was some concern about whether this would
8allow an attacker to send signals and have them be matched to a
9GDBusProxy in this situation, but it seems that was a false alarm.
10
11Signed-off-by: Simon McVittie <smcv@collabora.com>
12
13CVE: CVE-2024-34397
14Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/4d4c40e858cb71a229b19f89196e6e02e235eb5b]
15Signed-off-by: Peter Marko <peter.marko@siemens.com>
16---
17 gio/tests/gdbus-subscribe.c | 48 +++++++++++++++++++++++++++++++++++++
18 1 file changed, 48 insertions(+)
19
20diff --git a/gio/tests/gdbus-subscribe.c b/gio/tests/gdbus-subscribe.c
21index 3d2a14e03..350ec9f52 100644
22--- a/gio/tests/gdbus-subscribe.c
23+++ b/gio/tests/gdbus-subscribe.c
24@@ -358,6 +358,53 @@ static const TestPlan plan_limit_by_unique_name =
25 },
26 };
27
28+static const TestPlan plan_nonexistent_unique_name =
29+{
30+ .description = "A subscription via a unique name that doesn't exist "
31+ "accepts no messages",
32+ .steps = {
33+ {
34+ /* Subscriber wants to receive signals from service */
35+ .action = TEST_ACTION_SUBSCRIBE,
36+ .u.subscribe = {
37+ /* This relies on the implementation detail that the dbus-daemon
38+ * (and presumably other bus implementations) never actually generates
39+ * a unique name in this format */
40+ .string_sender = ":0.this.had.better.not.exist",
41+ .path = EXAMPLE_PATH,
42+ .iface = EXAMPLE_INTERFACE,
43+ },
44+ },
45+ {
46+ /* Attacker wants to trick subscriber into thinking that service
47+ * sent a signal */
48+ .action = TEST_ACTION_EMIT_SIGNAL,
49+ .u.signal = {
50+ .sender = TEST_CONN_ATTACKER,
51+ .path = EXAMPLE_PATH,
52+ .iface = EXAMPLE_INTERFACE,
53+ .member = FOO_SIGNAL,
54+ .received_by_conn = 0,
55+ .received_by_proxy = 0
56+ },
57+ },
58+ {
59+ /* Attacker tries harder, by sending a signal unicast directly to
60+ * the subscriber */
61+ .action = TEST_ACTION_EMIT_SIGNAL,
62+ .u.signal = {
63+ .sender = TEST_CONN_ATTACKER,
64+ .unicast_to = TEST_CONN_SUBSCRIBER,
65+ .path = EXAMPLE_PATH,
66+ .iface = EXAMPLE_INTERFACE,
67+ .member = FOO_SIGNAL,
68+ .received_by_conn = 0,
69+ .received_by_proxy = 0
70+ },
71+ },
72+ },
73+};
74+
75 static const TestPlan plan_limit_by_well_known_name =
76 {
77 .description = "A subscription via a well-known name only accepts messages "
78@@ -1051,6 +1098,7 @@ main (int argc,
79 ADD_SUBSCRIBE_TEST (broadcast_from_anyone);
80 ADD_SUBSCRIBE_TEST (match_twice);
81 ADD_SUBSCRIBE_TEST (limit_by_unique_name);
82+ ADD_SUBSCRIBE_TEST (nonexistent_unique_name);
83 ADD_SUBSCRIBE_TEST (limit_by_well_known_name);
84
85 return g_test_run();
86--
872.30.2
88
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_06.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_06.patch
new file mode 100644
index 0000000000..ec79bda045
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_06.patch
@@ -0,0 +1,263 @@
1From 4d8106ba534c7f3c2037cca4c654fd13ce0b93d9 Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@collabora.com>
3Date: Fri, 8 Mar 2024 20:10:29 +0000
4Subject: [PATCH 06/18] tests: Add test coverage for signals that match the
5 message bus's name
6
7This is a special case of unique names, even though it's syntactically
8a well-known name.
9
10Signed-off-by: Simon McVittie <smcv@collabora.com>
11
12CVE: CVE-2024-34397
13Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/4d8106ba534c7f3c2037cca4c654fd13ce0b93d9]
14Signed-off-by: Peter Marko <peter.marko@siemens.com>
15---
16 gio/tests/gdbus-subscribe.c | 161 ++++++++++++++++++++++++++++++++++--
17 1 file changed, 154 insertions(+), 7 deletions(-)
18
19diff --git a/gio/tests/gdbus-subscribe.c b/gio/tests/gdbus-subscribe.c
20index 350ec9f52..af100de7d 100644
21--- a/gio/tests/gdbus-subscribe.c
22+++ b/gio/tests/gdbus-subscribe.c
23@@ -13,6 +13,7 @@
24 #define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
25 #define DBUS_PATH_DBUS "/org/freedesktop/DBus"
26 #define DBUS_INTERFACE_DBUS DBUS_SERVICE_DBUS
27+#define NAME_OWNER_CHANGED "NameOwnerChanged"
28
29 /* A signal that each connection emits to indicate that it has finished
30 * emitting other signals */
31@@ -101,6 +102,7 @@ typedef struct
32 const char *iface;
33 const char *member;
34 const char *arg0;
35+ const char *args;
36 guint received_by_conn;
37 guint received_by_proxy;
38 } TestEmitSignal;
39@@ -120,6 +122,8 @@ typedef struct
40 {
41 const char *name;
42 TestConn owner;
43+ guint received_by_conn;
44+ guint received_by_proxy;
45 } TestOwnName;
46
47 typedef enum
48@@ -461,6 +465,63 @@ static const TestPlan plan_limit_by_well_known_name =
49 },
50 };
51
52+static const TestPlan plan_limit_to_message_bus =
53+{
54+ .description = "A subscription to the message bus only accepts messages "
55+ "from the message bus",
56+ .steps = {
57+ {
58+ /* Subscriber wants to receive signals from the message bus itself */
59+ .action = TEST_ACTION_SUBSCRIBE,
60+ .u.subscribe = {
61+ .string_sender = DBUS_SERVICE_DBUS,
62+ .path = DBUS_PATH_DBUS,
63+ .iface = DBUS_INTERFACE_DBUS,
64+ },
65+ },
66+ {
67+ /* Attacker wants to trick subscriber into thinking that the message
68+ * bus sent a signal */
69+ .action = TEST_ACTION_EMIT_SIGNAL,
70+ .u.signal = {
71+ .sender = TEST_CONN_ATTACKER,
72+ .path = DBUS_PATH_DBUS,
73+ .iface = DBUS_INTERFACE_DBUS,
74+ .member = NAME_OWNER_CHANGED,
75+ .arg0 = "would I lie to you?",
76+ .received_by_conn = 0,
77+ .received_by_proxy = 0
78+ },
79+ },
80+ {
81+ /* Attacker tries harder, by sending a signal unicast directly to
82+ * the subscriber, and using more realistic arguments */
83+ .action = TEST_ACTION_EMIT_SIGNAL,
84+ .u.signal = {
85+ .unicast_to = TEST_CONN_SUBSCRIBER,
86+ .sender = TEST_CONN_ATTACKER,
87+ .path = DBUS_PATH_DBUS,
88+ .iface = DBUS_INTERFACE_DBUS,
89+ .member = NAME_OWNER_CHANGED,
90+ .args = "('com.example.Name', '', ':1.12')",
91+ .received_by_conn = 0,
92+ .received_by_proxy = 0
93+ },
94+ },
95+ {
96+ /* When the message bus sends a signal (in this case triggered by
97+ * owning a name), it should still get through */
98+ .action = TEST_ACTION_OWN_NAME,
99+ .u.own_name = {
100+ .name = OWNED_LATER_NAME,
101+ .owner = TEST_CONN_SERVICE,
102+ .received_by_conn = 1,
103+ .received_by_proxy = 1
104+ },
105+ },
106+ },
107+};
108+
109 typedef struct
110 {
111 const TestPlan *plan;
112@@ -591,7 +652,18 @@ fixture_received_signal (Fixture *f,
113 }
114 }
115
116- g_assert_cmpint (received->sender, !=, TEST_CONN_NONE);
117+ if (g_str_equal (sender_name, DBUS_SERVICE_DBUS))
118+ {
119+ g_test_message ("Signal received from message bus %s",
120+ sender_name);
121+ }
122+ else
123+ {
124+ g_test_message ("Signal received from %s %s",
125+ test_conn_descriptions[received->sender],
126+ sender_name);
127+ g_assert_cmpint (received->sender, !=, TEST_CONN_NONE);
128+ }
129
130 g_test_message ("Signal received from %s %s via %s",
131 test_conn_descriptions[received->sender],
132@@ -607,13 +679,56 @@ fixture_received_signal (Fixture *f,
133 g_test_message ("\tString argument 0: %s", received->arg0);
134 g_test_message ("\tSent in step: %u", received->step);
135 }
136- else
137+ else if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(uu)")))
138 {
139- g_assert_cmpstr (g_variant_get_type_string (parameters), ==, "(uu)");
140 g_variant_get (parameters, "(uu)", NULL, &received->step);
141 g_test_message ("\tArgument 0: (not a string)");
142 g_test_message ("\tSent in step: %u", received->step);
143 }
144+ else if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sss)")))
145+ {
146+ const char *name;
147+ const char *old_owner;
148+ const char *new_owner;
149+
150+ /* The only signal of this signature that we legitimately receive
151+ * during this test is NameOwnerChanged, so just assert that it
152+ * is from the message bus and can be matched to a plausible step.
153+ * (This is less thorough than the above, and will not work if we
154+ * add a test scenario where a name's ownership is repeatedly
155+ * changed while watching NameOwnerChanged - so don't do that.) */
156+ g_assert_cmpstr (sender_name, ==, DBUS_SERVICE_DBUS);
157+ g_assert_cmpstr (path, ==, DBUS_PATH_DBUS);
158+ g_assert_cmpstr (iface, ==, DBUS_INTERFACE_DBUS);
159+ g_assert_cmpstr (member, ==, NAME_OWNER_CHANGED);
160+
161+ g_variant_get (parameters, "(&s&s&s)", &name, &old_owner, &new_owner);
162+
163+ for (i = 0; i < G_N_ELEMENTS (f->plan->steps); i++)
164+ {
165+ const TestStep *step = &f->plan->steps[i];
166+
167+ if (step->action == TEST_ACTION_OWN_NAME)
168+ {
169+ const TestOwnName *own_name = &step->u.own_name;
170+
171+ if (g_str_equal (name, own_name->name)
172+ && g_str_equal (new_owner, f->unique_names[own_name->owner])
173+ && own_name->received_by_conn > 0)
174+ {
175+ received->step = i;
176+ break;
177+ }
178+ }
179+
180+ if (i >= G_N_ELEMENTS (f->plan->steps))
181+ g_error ("Could not match message to a test step");
182+ }
183+ }
184+ else
185+ {
186+ g_error ("Unexpected message received");
187+ }
188
189 g_ptr_array_add (f->received, g_steal_pointer (&received));
190 }
191@@ -782,10 +897,15 @@ fixture_emit_signal (Fixture *f,
192 * Otherwise put something that will not match any arg0.
193 * Either way, put the sequence number in argument 1 so we can
194 * correlate sent messages with received messages later. */
195- if (signal->arg0 != NULL)
196+ if (signal->args != NULL)
197 {
198- g_test_message ("\tString argument 0: %s", signal->arg0);
199 /* floating */
200+ body = g_variant_new_parsed (signal->args);
201+ g_assert_nonnull (body);
202+ }
203+ else if (signal->arg0 != NULL)
204+ {
205+ g_test_message ("\tString argument 0: %s", signal->arg0);
206 body = g_variant_new ("(su)", signal->arg0, (guint32) step_number);
207 }
208 else
209@@ -933,8 +1053,6 @@ fixture_run_plan (Fixture *f,
210
211 g_assert_cmpuint (received->step, <, G_N_ELEMENTS (f->received_by_conn));
212 g_assert_cmpuint (received->step, <, G_N_ELEMENTS (f->received_by_proxy));
213- g_assert_cmpint (plan->steps[received->step].action,
214- ==, TEST_ACTION_EMIT_SIGNAL);
215
216 if (received->received_by_proxy != NULL)
217 f->received_by_proxy[received->step] += 1;
218@@ -974,6 +1092,34 @@ fixture_run_plan (Fixture *f,
219 g_assert_cmpuint (f->received_by_proxy[i], ==, 0);
220 }
221 }
222+ else if (step->action == TEST_ACTION_OWN_NAME)
223+ {
224+ const TestOwnName *own_name = &plan->steps[i].u.own_name;
225+
226+ if (mode != SUBSCRIPTION_MODE_PROXY)
227+ {
228+ g_test_message ("NameOwnerChanged from step %u was received %u "
229+ "times by GDBusConnection, expected %u",
230+ i, f->received_by_conn[i], own_name->received_by_conn);
231+ g_assert_cmpuint (f->received_by_conn[i], ==, own_name->received_by_conn);
232+ }
233+ else
234+ {
235+ g_assert_cmpuint (f->received_by_conn[i], ==, 0);
236+ }
237+
238+ if (mode != SUBSCRIPTION_MODE_CONN)
239+ {
240+ g_test_message ("NameOwnerChanged from step %u was received %u "
241+ "times by GDBusProxy, expected %u",
242+ i, f->received_by_proxy[i], own_name->received_by_proxy);
243+ g_assert_cmpuint (f->received_by_proxy[i], ==, own_name->received_by_proxy);
244+ }
245+ else
246+ {
247+ g_assert_cmpuint (f->received_by_proxy[i], ==, 0);
248+ }
249+ }
250 }
251 }
252
253@@ -1100,6 +1246,7 @@ main (int argc,
254 ADD_SUBSCRIBE_TEST (limit_by_unique_name);
255 ADD_SUBSCRIBE_TEST (nonexistent_unique_name);
256 ADD_SUBSCRIBE_TEST (limit_by_well_known_name);
257+ ADD_SUBSCRIBE_TEST (limit_to_message_bus);
258
259 return g_test_run();
260 }
261--
2622.30.2
263
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_07.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_07.patch
new file mode 100644
index 0000000000..f19846761a
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_07.patch
@@ -0,0 +1,45 @@
1From 5057b6a0e488af6495146cfe96e93eb5e7beb66b Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@collabora.com>
3Date: Thu, 14 Mar 2024 19:18:15 +0000
4Subject: [PATCH 07/18] gdbusprivate: Add symbolic constants for the message
5 bus itself
6
7Using these is a bit more clearly correct than repeating them everywhere.
8To avoid excessive diffstat in a branch for a bug fix, I'm not
9immediately replacing all existing occurrences of the same literals with
10these names.
11
12The names of these constants are chosen to be consistent with libdbus,
13despite using somewhat outdated terminology (D-Bus now uses the term
14"well-known bus name" for what used to be called a service name,
15reserving the word "service" to mean specifically the programs that
16have .service files and participate in service activation).
17
18Signed-off-by: Simon McVittie <smcv@collabora.com>
19
20CVE: CVE-2024-34397
21Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/5057b6a0e488af6495146cfe96e93eb5e7beb66b]
22Signed-off-by: Peter Marko <peter.marko@siemens.com>
23---
24 gio/gdbusprivate.h | 5 +++++
25 1 file changed, 5 insertions(+)
26
27diff --git a/gio/gdbusprivate.h b/gio/gdbusprivate.h
28index 72d2c32a9..ac737bd7a 100644
29--- a/gio/gdbusprivate.h
30+++ b/gio/gdbusprivate.h
31@@ -29,6 +29,11 @@
32
33 G_BEGIN_DECLS
34
35+/* Bus name, interface and object path of the message bus itself */
36+#define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
37+#define DBUS_INTERFACE_DBUS DBUS_SERVICE_DBUS
38+#define DBUS_PATH_DBUS "/org/freedesktop/DBus"
39+
40 /* ---------------------------------------------------------------------------------------------------- */
41
42 typedef struct GDBusWorker GDBusWorker;
43--
442.30.2
45
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_08.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_08.patch
new file mode 100644
index 0000000000..cd367478ff
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_08.patch
@@ -0,0 +1,168 @@
1From 467ff27a5a08c21705e20da70a988a55b9f15513 Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@collabora.com>
3Date: Thu, 14 Mar 2024 19:24:24 +0000
4Subject: [PATCH 08/18] gdbusconnection: Move SignalData, SignalSubscriber
5 higher up
6
7Subsequent changes will need to access these data structures from
8on_worker_message_received(). No functional change here, only moving
9code around.
10
11Signed-off-by: Simon McVittie <smcv@collabora.com>
12
13CVE: CVE-2024-34397
14Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/467ff27a5a08c21705e20da70a988a55b9f15513]
15Signed-off-by: Peter Marko <peter.marko@siemens.com>
16---
17 gio/gdbusconnection.c | 128 +++++++++++++++++++++---------------------
18 1 file changed, 65 insertions(+), 63 deletions(-)
19
20diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
21index 82a68437b..4f31e8502 100644
22--- a/gio/gdbusconnection.c
23+++ b/gio/gdbusconnection.c
24@@ -283,6 +283,71 @@ call_destroy_notify (GMainContext *context,
25
26 /* ---------------------------------------------------------------------------------------------------- */
27
28+typedef struct
29+{
30+ /* All fields are immutable after construction. */
31+ gatomicrefcount ref_count;
32+ GDBusSignalCallback callback;
33+ gpointer user_data;
34+ GDestroyNotify user_data_free_func;
35+ guint id;
36+ GMainContext *context;
37+} SignalSubscriber;
38+
39+static SignalSubscriber *
40+signal_subscriber_ref (SignalSubscriber *subscriber)
41+{
42+ g_atomic_ref_count_inc (&subscriber->ref_count);
43+ return subscriber;
44+}
45+
46+static void
47+signal_subscriber_unref (SignalSubscriber *subscriber)
48+{
49+ if (g_atomic_ref_count_dec (&subscriber->ref_count))
50+ {
51+ /* Destroy the user data. It doesn’t matter which thread
52+ * signal_subscriber_unref() is called in (or whether it’s called with a
53+ * lock held), as call_destroy_notify() always defers to the next
54+ * #GMainContext iteration. */
55+ call_destroy_notify (subscriber->context,
56+ subscriber->user_data_free_func,
57+ subscriber->user_data);
58+
59+ g_main_context_unref (subscriber->context);
60+ g_free (subscriber);
61+ }
62+}
63+
64+typedef struct
65+{
66+ gchar *rule;
67+ gchar *sender;
68+ gchar *sender_unique_name; /* if sender is unique or org.freedesktop.DBus, then that name... otherwise blank */
69+ gchar *interface_name;
70+ gchar *member;
71+ gchar *object_path;
72+ gchar *arg0;
73+ GDBusSignalFlags flags;
74+ GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */
75+} SignalData;
76+
77+static void
78+signal_data_free (SignalData *signal_data)
79+{
80+ g_free (signal_data->rule);
81+ g_free (signal_data->sender);
82+ g_free (signal_data->sender_unique_name);
83+ g_free (signal_data->interface_name);
84+ g_free (signal_data->member);
85+ g_free (signal_data->object_path);
86+ g_free (signal_data->arg0);
87+ g_ptr_array_unref (signal_data->subscribers);
88+ g_free (signal_data);
89+}
90+
91+/* ---------------------------------------------------------------------------------------------------- */
92+
93 #ifdef G_OS_WIN32
94 #define CONNECTION_ENSURE_LOCK(obj) do { ; } while (FALSE)
95 #else
96@@ -3238,69 +3303,6 @@ g_dbus_connection_remove_filter (GDBusConnection *connection,
97
98 /* ---------------------------------------------------------------------------------------------------- */
99
100-typedef struct
101-{
102- gchar *rule;
103- gchar *sender;
104- gchar *sender_unique_name; /* if sender is unique or org.freedesktop.DBus, then that name... otherwise blank */
105- gchar *interface_name;
106- gchar *member;
107- gchar *object_path;
108- gchar *arg0;
109- GDBusSignalFlags flags;
110- GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */
111-} SignalData;
112-
113-static void
114-signal_data_free (SignalData *signal_data)
115-{
116- g_free (signal_data->rule);
117- g_free (signal_data->sender);
118- g_free (signal_data->sender_unique_name);
119- g_free (signal_data->interface_name);
120- g_free (signal_data->member);
121- g_free (signal_data->object_path);
122- g_free (signal_data->arg0);
123- g_ptr_array_unref (signal_data->subscribers);
124- g_free (signal_data);
125-}
126-
127-typedef struct
128-{
129- /* All fields are immutable after construction. */
130- gatomicrefcount ref_count;
131- GDBusSignalCallback callback;
132- gpointer user_data;
133- GDestroyNotify user_data_free_func;
134- guint id;
135- GMainContext *context;
136-} SignalSubscriber;
137-
138-static SignalSubscriber *
139-signal_subscriber_ref (SignalSubscriber *subscriber)
140-{
141- g_atomic_ref_count_inc (&subscriber->ref_count);
142- return subscriber;
143-}
144-
145-static void
146-signal_subscriber_unref (SignalSubscriber *subscriber)
147-{
148- if (g_atomic_ref_count_dec (&subscriber->ref_count))
149- {
150- /* Destroy the user data. It doesn’t matter which thread
151- * signal_subscriber_unref() is called in (or whether it’s called with a
152- * lock held), as call_destroy_notify() always defers to the next
153- * #GMainContext iteration. */
154- call_destroy_notify (subscriber->context,
155- subscriber->user_data_free_func,
156- subscriber->user_data);
157-
158- g_main_context_unref (subscriber->context);
159- g_free (subscriber);
160- }
161-}
162-
163 static gchar *
164 args_to_rule (const gchar *sender,
165 const gchar *interface_name,
166--
1672.30.2
168
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_09.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_09.patch
new file mode 100644
index 0000000000..581aa04983
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_09.patch
@@ -0,0 +1,81 @@
1From f75e2d73645598e5f3aa064adfece95da435525f Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@collabora.com>
3Date: Thu, 14 Mar 2024 19:30:12 +0000
4Subject: [PATCH 09/18] gdbusconnection: Factor out signal_data_new_take()
5
6No functional changes, except that the implicit ownership-transfer
7for the rule field becomes explicit (the local variable is set to NULL
8afterwards).
9
10Signed-off-by: Simon McVittie <smcv@collabora.com>
11
12CVE: CVE-2024-34397
13Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/f75e2d73645598e5f3aa064adfece95da435525f]
14Signed-off-by: Peter Marko <peter.marko@siemens.com>
15---
16 gio/gdbusconnection.c | 42 ++++++++++++++++++++++++++++++++----------
17 1 file changed, 32 insertions(+), 10 deletions(-)
18
19diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
20index 4f31e8502..b8fd920d9 100644
21--- a/gio/gdbusconnection.c
22+++ b/gio/gdbusconnection.c
23@@ -332,6 +332,30 @@ typedef struct
24 GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */
25 } SignalData;
26
27+static SignalData *
28+signal_data_new_take (gchar *rule,
29+ gchar *sender,
30+ gchar *sender_unique_name,
31+ gchar *interface_name,
32+ gchar *member,
33+ gchar *object_path,
34+ gchar *arg0,
35+ GDBusSignalFlags flags)
36+{
37+ SignalData *signal_data = g_new0 (SignalData, 1);
38+
39+ signal_data->rule = rule;
40+ signal_data->sender = sender;
41+ signal_data->sender_unique_name = sender_unique_name;
42+ signal_data->interface_name = interface_name;
43+ signal_data->member = member;
44+ signal_data->object_path = object_path;
45+ signal_data->arg0 = arg0;
46+ signal_data->flags = flags;
47+ signal_data->subscribers = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref);
48+ return g_steal_pointer (&signal_data);
49+}
50+
51 static void
52 signal_data_free (SignalData *signal_data)
53 {
54@@ -3569,16 +3593,14 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
55 goto out;
56 }
57
58- signal_data = g_new0 (SignalData, 1);
59- signal_data->rule = rule;
60- signal_data->sender = g_strdup (sender);
61- signal_data->sender_unique_name = g_strdup (sender_unique_name);
62- signal_data->interface_name = g_strdup (interface_name);
63- signal_data->member = g_strdup (member);
64- signal_data->object_path = g_strdup (object_path);
65- signal_data->arg0 = g_strdup (arg0);
66- signal_data->flags = flags;
67- signal_data->subscribers = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref);
68+ signal_data = signal_data_new_take (g_steal_pointer (&rule),
69+ g_strdup (sender),
70+ g_strdup (sender_unique_name),
71+ g_strdup (interface_name),
72+ g_strdup (member),
73+ g_strdup (object_path),
74+ g_strdup (arg0),
75+ flags);
76 g_ptr_array_add (signal_data->subscribers, subscriber);
77
78 g_hash_table_insert (connection->map_rule_to_signal_data,
79--
802.30.2
81
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_10.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_10.patch
new file mode 100644
index 0000000000..37b261eccd
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_10.patch
@@ -0,0 +1,108 @@
1From 7f8b44ecdf5bc02e132de4c3242e961f8f27e9f2 Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@collabora.com>
3Date: Tue, 23 Apr 2024 20:31:57 +0100
4Subject: [PATCH 10/18] gdbusconnection: Factor out add_signal_data()
5
6No functional changes.
7
8Signed-off-by: Simon McVittie <smcv@collabora.com>
9
10CVE: CVE-2024-34397
11Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/7f8b44ecdf5bc02e132de4c3242e961f8f27e9f2]
12Signed-off-by: Peter Marko <peter.marko@siemens.com>
13---
14 gio/gdbusconnection.c | 64 +++++++++++++++++++++++++------------------
15 1 file changed, 37 insertions(+), 27 deletions(-)
16
17diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
18index b8fd920d9..3b170845c 100644
19--- a/gio/gdbusconnection.c
20+++ b/gio/gdbusconnection.c
21@@ -3447,6 +3447,42 @@ is_signal_data_for_name_lost_or_acquired (SignalData *signal_data)
22
23 /* ---------------------------------------------------------------------------------------------------- */
24
25+/* called in any thread, connection lock is held */
26+static void
27+add_signal_data (GDBusConnection *connection,
28+ SignalData *signal_data)
29+{
30+ GPtrArray *signal_data_array;
31+
32+ g_hash_table_insert (connection->map_rule_to_signal_data,
33+ signal_data->rule,
34+ signal_data);
35+
36+ /* Add the match rule to the bus...
37+ *
38+ * Avoid adding match rules for NameLost and NameAcquired messages - the bus will
39+ * always send such messages to us.
40+ */
41+ if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
42+ {
43+ if (!is_signal_data_for_name_lost_or_acquired (signal_data))
44+ add_match_rule (connection, signal_data->rule);
45+ }
46+
47+ signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array,
48+ signal_data->sender_unique_name);
49+ if (signal_data_array == NULL)
50+ {
51+ signal_data_array = g_ptr_array_new ();
52+ g_hash_table_insert (connection->map_sender_unique_name_to_signal_data_array,
53+ g_strdup (signal_data->sender_unique_name),
54+ signal_data_array);
55+ }
56+ g_ptr_array_add (signal_data_array, signal_data);
57+}
58+
59+/* ---------------------------------------------------------------------------------------------------- */
60+
61 /**
62 * g_dbus_connection_signal_subscribe:
63 * @connection: a #GDBusConnection
64@@ -3536,7 +3572,6 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
65 gchar *rule;
66 SignalData *signal_data;
67 SignalSubscriber *subscriber;
68- GPtrArray *signal_data_array;
69 const gchar *sender_unique_name;
70
71 /* Right now we abort if AddMatch() fails since it can only fail with the bus being in
72@@ -3602,32 +3637,7 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
73 g_strdup (arg0),
74 flags);
75 g_ptr_array_add (signal_data->subscribers, subscriber);
76-
77- g_hash_table_insert (connection->map_rule_to_signal_data,
78- signal_data->rule,
79- signal_data);
80-
81- /* Add the match rule to the bus...
82- *
83- * Avoid adding match rules for NameLost and NameAcquired messages - the bus will
84- * always send such messages to us.
85- */
86- if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
87- {
88- if (!is_signal_data_for_name_lost_or_acquired (signal_data))
89- add_match_rule (connection, signal_data->rule);
90- }
91-
92- signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array,
93- signal_data->sender_unique_name);
94- if (signal_data_array == NULL)
95- {
96- signal_data_array = g_ptr_array_new ();
97- g_hash_table_insert (connection->map_sender_unique_name_to_signal_data_array,
98- g_strdup (signal_data->sender_unique_name),
99- signal_data_array);
100- }
101- g_ptr_array_add (signal_data_array, signal_data);
102+ add_signal_data (connection, signal_data);
103
104 out:
105 g_hash_table_insert (connection->map_id_to_signal_data,
106--
1072.30.2
108
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_11.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_11.patch
new file mode 100644
index 0000000000..aa5c3ceaf5
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_11.patch
@@ -0,0 +1,133 @@
1From 1704bc6a70c0dcdc5555f23ebab8e3e7ed697998 Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@collabora.com>
3Date: Thu, 14 Mar 2024 19:51:59 +0000
4Subject: [PATCH 11/18] gdbusconnection: Factor out
5 remove_signal_data_if_unused
6
7No functional change, just removing some nesting. The check for whether
8signal_data->subscribers is empty changes from a conditional that tests
9whether it is into an early-return if it isn't.
10
11A subsequent commit will add additional conditions that make us consider
12a SignalData to be still in use and therefore not eligible to be removed.
13
14Signed-off-by: Simon McVittie <smcv@collabora.com>
15
16CVE: CVE-2024-34397
17Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/1704bc6a70c0dcdc5555f23ebab8e3e7ed697998]
18Signed-off-by: Peter Marko <peter.marko@siemens.com>
19---
20 gio/gdbusconnection.c | 83 +++++++++++++++++++++++++------------------
21 1 file changed, 48 insertions(+), 35 deletions(-)
22
23diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
24index 3b170845c..114cdde29 100644
25--- a/gio/gdbusconnection.c
26+++ b/gio/gdbusconnection.c
27@@ -3651,6 +3651,52 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
28
29 /* ---------------------------------------------------------------------------------------------------- */
30
31+/*
32+ * Called in any thread.
33+ * Must hold the connection lock when calling this, unless
34+ * connection->finalizing is TRUE.
35+ * May free signal_data, so do not dereference it after this.
36+ */
37+static void
38+remove_signal_data_if_unused (GDBusConnection *connection,
39+ SignalData *signal_data)
40+{
41+ GPtrArray *signal_data_array;
42+
43+ if (signal_data->subscribers->len != 0)
44+ return;
45+
46+ g_warn_if_fail (g_hash_table_remove (connection->map_rule_to_signal_data, signal_data->rule));
47+
48+ signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array,
49+ signal_data->sender_unique_name);
50+ g_warn_if_fail (signal_data_array != NULL);
51+ g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data));
52+
53+ if (signal_data_array->len == 0)
54+ {
55+ g_warn_if_fail (g_hash_table_remove (connection->map_sender_unique_name_to_signal_data_array,
56+ signal_data->sender_unique_name));
57+ }
58+
59+ /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */
60+ if ((connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) &&
61+ !is_signal_data_for_name_lost_or_acquired (signal_data) &&
62+ !g_dbus_connection_is_closed (connection) &&
63+ !connection->finalizing)
64+ {
65+ /* The check for g_dbus_connection_is_closed() means that
66+ * sending the RemoveMatch message can't fail with
67+ * G_IO_ERROR_CLOSED, because we're holding the lock,
68+ * so on_worker_closed() can't happen between the check we just
69+ * did, and releasing the lock later.
70+ */
71+ remove_match_rule (connection, signal_data->rule);
72+ }
73+
74+ signal_data_free (signal_data);
75+}
76+
77 /* called in any thread */
78 /* must hold lock when calling this (except if connection->finalizing is TRUE)
79 * returns the number of removed subscribers */
80@@ -3659,7 +3705,6 @@ unsubscribe_id_internal (GDBusConnection *connection,
81 guint subscription_id)
82 {
83 SignalData *signal_data;
84- GPtrArray *signal_data_array;
85 guint n;
86 guint n_removed = 0;
87
88@@ -3686,40 +3731,8 @@ unsubscribe_id_internal (GDBusConnection *connection,
89 GUINT_TO_POINTER (subscription_id)));
90 n_removed++;
91 g_ptr_array_remove_index_fast (signal_data->subscribers, n);
92-
93- if (signal_data->subscribers->len == 0)
94- {
95- g_warn_if_fail (g_hash_table_remove (connection->map_rule_to_signal_data, signal_data->rule));
96-
97- signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array,
98- signal_data->sender_unique_name);
99- g_warn_if_fail (signal_data_array != NULL);
100- g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data));
101-
102- if (signal_data_array->len == 0)
103- {
104- g_warn_if_fail (g_hash_table_remove (connection->map_sender_unique_name_to_signal_data_array,
105- signal_data->sender_unique_name));
106- }
107-
108- /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */
109- if ((connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) &&
110- !is_signal_data_for_name_lost_or_acquired (signal_data) &&
111- !g_dbus_connection_is_closed (connection) &&
112- !connection->finalizing)
113- {
114- /* The check for g_dbus_connection_is_closed() means that
115- * sending the RemoveMatch message can't fail with
116- * G_IO_ERROR_CLOSED, because we're holding the lock,
117- * so on_worker_closed() can't happen between the check we just
118- * did, and releasing the lock later.
119- */
120- remove_match_rule (connection, signal_data->rule);
121- }
122-
123- signal_data_free (signal_data);
124- }
125-
126+ /* May free signal_data */
127+ remove_signal_data_if_unused (connection, signal_data);
128 goto out;
129 }
130
131--
1322.30.2
133
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_12.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_12.patch
new file mode 100644
index 0000000000..281143554f
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_12.patch
@@ -0,0 +1,173 @@
1From 5377b4d9061b73bb47af85cc99253a18dc58e83e Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@collabora.com>
3Date: Tue, 23 Apr 2024 20:39:05 +0100
4Subject: [PATCH 12/18] gdbusconnection: Stop storing sender_unique_name in
5 SignalData
6
7This will become confusing when we start tracking the owner of a
8well-known-name sender, and it's redundant anyway. Instead, track the
91 bit of data that we actually need: whether it's a well-known name.
10
11Strictly speaking this too is redundant, because it's syntactically
12derivable from the sender, but only via extra string operations.
13A subsequent commit will add a data structure to keep track of the
14owner of a well-known-name sender, at which point this boolean will
15be replaced by the presence or absence of that data structure.
16
17Signed-off-by: Simon McVittie <smcv@collabora.com>
18
19CVE: CVE-2024-34397
20Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/5377b4d9061b73bb47af85cc99253a18dc58e83e]
21Signed-off-by: Peter Marko <peter.marko@siemens.com>
22---
23 gio/gdbusconnection.c | 36 ++++++++++++++++++++++++------------
24 1 file changed, 24 insertions(+), 12 deletions(-)
25
26diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
27index 114cdde29..8c1d77b62 100644
28--- a/gio/gdbusconnection.c
29+++ b/gio/gdbusconnection.c
30@@ -323,19 +323,19 @@ typedef struct
31 {
32 gchar *rule;
33 gchar *sender;
34- gchar *sender_unique_name; /* if sender is unique or org.freedesktop.DBus, then that name... otherwise blank */
35 gchar *interface_name;
36 gchar *member;
37 gchar *object_path;
38 gchar *arg0;
39 GDBusSignalFlags flags;
40 GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */
41+ gboolean sender_is_its_own_owner;
42 } SignalData;
43
44 static SignalData *
45 signal_data_new_take (gchar *rule,
46 gchar *sender,
47- gchar *sender_unique_name,
48+ gboolean sender_is_its_own_owner,
49 gchar *interface_name,
50 gchar *member,
51 gchar *object_path,
52@@ -346,7 +346,7 @@ signal_data_new_take (gchar *rule,
53
54 signal_data->rule = rule;
55 signal_data->sender = sender;
56- signal_data->sender_unique_name = sender_unique_name;
57+ signal_data->sender_is_its_own_owner = sender_is_its_own_owner;
58 signal_data->interface_name = interface_name;
59 signal_data->member = member;
60 signal_data->object_path = object_path;
61@@ -361,7 +361,6 @@ signal_data_free (SignalData *signal_data)
62 {
63 g_free (signal_data->rule);
64 g_free (signal_data->sender);
65- g_free (signal_data->sender_unique_name);
66 g_free (signal_data->interface_name);
67 g_free (signal_data->member);
68 g_free (signal_data->object_path);
69@@ -3438,7 +3437,7 @@ remove_match_rule (GDBusConnection *connection,
70 static gboolean
71 is_signal_data_for_name_lost_or_acquired (SignalData *signal_data)
72 {
73- return g_strcmp0 (signal_data->sender_unique_name, "org.freedesktop.DBus") == 0 &&
74+ return g_strcmp0 (signal_data->sender, "org.freedesktop.DBus") == 0 &&
75 g_strcmp0 (signal_data->interface_name, "org.freedesktop.DBus") == 0 &&
76 g_strcmp0 (signal_data->object_path, "/org/freedesktop/DBus") == 0 &&
77 (g_strcmp0 (signal_data->member, "NameLost") == 0 ||
78@@ -3450,7 +3449,8 @@ is_signal_data_for_name_lost_or_acquired (SignalData *signal_data)
79 /* called in any thread, connection lock is held */
80 static void
81 add_signal_data (GDBusConnection *connection,
82- SignalData *signal_data)
83+ SignalData *signal_data,
84+ const char *sender_unique_name)
85 {
86 GPtrArray *signal_data_array;
87
88@@ -3470,12 +3470,12 @@ add_signal_data (GDBusConnection *connection,
89 }
90
91 signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array,
92- signal_data->sender_unique_name);
93+ sender_unique_name);
94 if (signal_data_array == NULL)
95 {
96 signal_data_array = g_ptr_array_new ();
97 g_hash_table_insert (connection->map_sender_unique_name_to_signal_data_array,
98- g_strdup (signal_data->sender_unique_name),
99+ g_strdup (sender_unique_name),
100 signal_data_array);
101 }
102 g_ptr_array_add (signal_data_array, signal_data);
103@@ -3572,6 +3572,7 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
104 gchar *rule;
105 SignalData *signal_data;
106 SignalSubscriber *subscriber;
107+ gboolean sender_is_its_own_owner;
108 const gchar *sender_unique_name;
109
110 /* Right now we abort if AddMatch() fails since it can only fail with the bus being in
111@@ -3607,6 +3608,11 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
112 rule = args_to_rule (sender, interface_name, member, object_path, arg0, flags);
113
114 if (sender != NULL && (g_dbus_is_unique_name (sender) || g_strcmp0 (sender, "org.freedesktop.DBus") == 0))
115+ sender_is_its_own_owner = TRUE;
116+ else
117+ sender_is_its_own_owner = FALSE;
118+
119+ if (sender_is_its_own_owner)
120 sender_unique_name = sender;
121 else
122 sender_unique_name = "";
123@@ -3630,14 +3636,14 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
124
125 signal_data = signal_data_new_take (g_steal_pointer (&rule),
126 g_strdup (sender),
127- g_strdup (sender_unique_name),
128+ sender_is_its_own_owner,
129 g_strdup (interface_name),
130 g_strdup (member),
131 g_strdup (object_path),
132 g_strdup (arg0),
133 flags);
134 g_ptr_array_add (signal_data->subscribers, subscriber);
135- add_signal_data (connection, signal_data);
136+ add_signal_data (connection, signal_data, sender_unique_name);
137
138 out:
139 g_hash_table_insert (connection->map_id_to_signal_data,
140@@ -3661,22 +3667,28 @@ static void
141 remove_signal_data_if_unused (GDBusConnection *connection,
142 SignalData *signal_data)
143 {
144+ const gchar *sender_unique_name;
145 GPtrArray *signal_data_array;
146
147 if (signal_data->subscribers->len != 0)
148 return;
149
150+ if (signal_data->sender_is_its_own_owner)
151+ sender_unique_name = signal_data->sender;
152+ else
153+ sender_unique_name = "";
154+
155 g_warn_if_fail (g_hash_table_remove (connection->map_rule_to_signal_data, signal_data->rule));
156
157 signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array,
158- signal_data->sender_unique_name);
159+ sender_unique_name);
160 g_warn_if_fail (signal_data_array != NULL);
161 g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data));
162
163 if (signal_data_array->len == 0)
164 {
165 g_warn_if_fail (g_hash_table_remove (connection->map_sender_unique_name_to_signal_data_array,
166- signal_data->sender_unique_name));
167+ sender_unique_name));
168 }
169
170 /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */
171--
1722.30.2
173
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_13.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_13.patch
new file mode 100644
index 0000000000..aaa7cf8589
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_13.patch
@@ -0,0 +1,513 @@
1From 9114439d886137cfb903e109b612869535aa05b6 Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@collabora.com>
3Date: Wed, 1 May 2024 15:43:09 +0100
4Subject: [PATCH 13/18] gdbus: Track name owners for signal subscriptions
5
6We will use this in a subsequent commit to prevent signals from an
7impostor from being delivered to a subscriber.
8
9To avoid message reordering leading to misleading situations, this does
10not use the existing mechanism for watching bus name ownership, which
11delivers the ownership changes to other main-contexts. Instead, it all
12happens on the single thread used by the GDBusWorker, so the order in
13which messages are received is the order in which they are processed.
14
15[Backported to glib-2-74, resolving minor conflicts]
16Signed-off-by: Simon McVittie <smcv@collabora.com>
17
18CVE: CVE-2024-34397
19Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/9114439d886137cfb903e109b612869535aa05b6]
20Signed-off-by: Peter Marko <peter.marko@siemens.com>
21---
22 gio/gdbusconnection.c | 350 +++++++++++++++++++++++++++++++++++++++++-
23 1 file changed, 343 insertions(+), 7 deletions(-)
24
25diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
26index 8c1d77b62..1ac120bc5 100644
27--- a/gio/gdbusconnection.c
28+++ b/gio/gdbusconnection.c
29@@ -320,6 +320,31 @@ signal_subscriber_unref (SignalSubscriber *subscriber)
30 }
31
32 typedef struct
33+{
34+ /*
35+ * 1 reference while waiting for GetNameOwner() to finish
36+ * 1 reference for each SignalData that points to this one as its
37+ * shared_name_watcher
38+ */
39+ grefcount ref_count;
40+
41+ gchar *owner;
42+ guint32 get_name_owner_serial;
43+} WatchedName;
44+
45+static WatchedName *
46+watched_name_new (void)
47+{
48+ WatchedName *watched_name = g_new0 (WatchedName, 1);
49+
50+ g_ref_count_init (&watched_name->ref_count);
51+ watched_name->owner = NULL;
52+ return g_steal_pointer (&watched_name);
53+}
54+
55+typedef struct SignalData SignalData;
56+
57+struct SignalData
58 {
59 gchar *rule;
60 gchar *sender;
61@@ -329,13 +354,36 @@ typedef struct
62 gchar *arg0;
63 GDBusSignalFlags flags;
64 GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */
65- gboolean sender_is_its_own_owner;
66-} SignalData;
67+
68+ /*
69+ * If the sender is a well-known name, this is an unowned SignalData
70+ * representing the NameOwnerChanged signal that tracks its owner.
71+ * NULL if sender is NULL.
72+ * NULL if sender is its own owner (a unique name or DBUS_SERVICE_DBUS).
73+ *
74+ * Invariants: if not NULL, then
75+ * shared_name_watcher->sender == DBUS_SERVICE_DBUS
76+ * shared_name_watcher->interface_name == DBUS_INTERFACE_DBUS
77+ * shared_name_watcher->member == "NameOwnerChanged"
78+ * shared_name_watcher->object_path == DBUS_PATH_DBUS
79+ * shared_name_watcher->arg0 == sender
80+ * shared_name_watcher->flags == NONE
81+ * shared_name_watcher->watched_name == NULL
82+ */
83+ SignalData *shared_name_watcher;
84+
85+ /*
86+ * Non-NULL if this SignalData is another SignalData's shared_name_watcher.
87+ * One reference for each SignalData that has this one as its
88+ * shared_name_watcher.
89+ * Otherwise NULL.
90+ */
91+ WatchedName *watched_name;
92+};
93
94 static SignalData *
95 signal_data_new_take (gchar *rule,
96 gchar *sender,
97- gboolean sender_is_its_own_owner,
98 gchar *interface_name,
99 gchar *member,
100 gchar *object_path,
101@@ -346,7 +394,6 @@ signal_data_new_take (gchar *rule,
102
103 signal_data->rule = rule;
104 signal_data->sender = sender;
105- signal_data->sender_is_its_own_owner = sender_is_its_own_owner;
106 signal_data->interface_name = interface_name;
107 signal_data->member = member;
108 signal_data->object_path = object_path;
109@@ -359,6 +406,17 @@ signal_data_new_take (gchar *rule,
110 static void
111 signal_data_free (SignalData *signal_data)
112 {
113+ /* The SignalData should not be freed while it still has subscribers */
114+ g_assert (signal_data->subscribers->len == 0);
115+
116+ /* The SignalData should not be freed while it is watching for
117+ * NameOwnerChanged on behalf of another SignalData */
118+ g_assert (signal_data->watched_name == NULL);
119+
120+ /* The SignalData should be detached from its name watcher, if any,
121+ * before it is freed */
122+ g_assert (signal_data->shared_name_watcher == NULL);
123+
124 g_free (signal_data->rule);
125 g_free (signal_data->sender);
126 g_free (signal_data->interface_name);
127@@ -366,6 +424,7 @@ signal_data_free (SignalData *signal_data)
128 g_free (signal_data->object_path);
129 g_free (signal_data->arg0);
130 g_ptr_array_unref (signal_data->subscribers);
131+
132 g_free (signal_data);
133 }
134
135@@ -497,6 +556,7 @@ struct _GDBusConnection
136
137 /* Map used for managing method replies, protected by @lock */
138 GHashTable *map_method_serial_to_task; /* guint32 -> GTask* */
139+ GHashTable *map_method_serial_to_name_watcher; /* guint32 -> unowned SignalData* */
140
141 /* Maps used for managing signal subscription, protected by @lock */
142 GHashTable *map_rule_to_signal_data; /* match rule (gchar*) -> SignalData */
143@@ -745,6 +805,7 @@ g_dbus_connection_finalize (GObject *object)
144 g_error_free (connection->initialization_error);
145
146 g_hash_table_unref (connection->map_method_serial_to_task);
147+ g_hash_table_unref (connection->map_method_serial_to_name_watcher);
148
149 g_hash_table_unref (connection->map_rule_to_signal_data);
150 g_hash_table_unref (connection->map_id_to_signal_data);
151@@ -1149,6 +1210,7 @@ g_dbus_connection_init (GDBusConnection *connection)
152 g_mutex_init (&connection->init_lock);
153
154 connection->map_method_serial_to_task = g_hash_table_new (g_direct_hash, g_direct_equal);
155+ connection->map_method_serial_to_name_watcher = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
156
157 connection->map_rule_to_signal_data = g_hash_table_new (g_str_hash,
158 g_str_equal);
159@@ -2266,6 +2328,191 @@ g_dbus_connection_send_message_with_reply_sync (GDBusConnection *connecti
160
161 /* ---------------------------------------------------------------------------------------------------- */
162
163+/*
164+ * Called in any thread.
165+ * Must hold the connection lock when calling this, unless
166+ * connection->finalizing is TRUE.
167+ */
168+static void
169+name_watcher_unref_watched_name (GDBusConnection *connection,
170+ SignalData *name_watcher)
171+{
172+ WatchedName *watched_name = name_watcher->watched_name;
173+
174+ g_assert (watched_name != NULL);
175+
176+ if (!g_ref_count_dec (&watched_name->ref_count))
177+ return;
178+
179+ /* Removing watched_name from the name_watcher may result in
180+ * name_watcher being freed, so we must make sure name_watcher is no
181+ * longer in map_method_serial_to_name_watcher.
182+ *
183+ * If we stop watching the name while our GetNameOwner call was still
184+ * in-flight, then when the reply eventually arrives, we will not find
185+ * its serial number in the map and harmlessly ignore it as a result. */
186+ if (watched_name->get_name_owner_serial != 0)
187+ g_hash_table_remove (connection->map_method_serial_to_name_watcher,
188+ GUINT_TO_POINTER (watched_name->get_name_owner_serial));
189+
190+ name_watcher->watched_name = NULL;
191+ g_free (watched_name->owner);
192+ g_free (watched_name);
193+}
194+
195+/* called in GDBusWorker thread with lock held */
196+static void
197+name_watcher_set_name_owner_unlocked (SignalData *name_watcher,
198+ const char *new_owner)
199+{
200+ if (new_owner != NULL && new_owner[0] == '\0')
201+ new_owner = NULL;
202+
203+ g_assert (name_watcher->watched_name != NULL);
204+ g_set_str (&name_watcher->watched_name->owner, new_owner);
205+}
206+
207+/* called in GDBusWorker thread with lock held */
208+static void
209+name_watcher_deliver_name_owner_changed_unlocked (SignalData *name_watcher,
210+ GDBusMessage *message)
211+{
212+ GVariant *body;
213+
214+ body = g_dbus_message_get_body (message);
215+
216+ if (G_LIKELY (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(sss)"))))
217+ {
218+ const char *name;
219+ const char *new_owner;
220+
221+ g_variant_get (body, "(&s&s&s)", &name, NULL, &new_owner);
222+
223+ /* Our caller already checked this */
224+ g_assert (g_strcmp0 (name_watcher->arg0, name) == 0);
225+
226+ if (G_LIKELY (new_owner[0] == '\0' || g_dbus_is_unique_name (new_owner)))
227+ name_watcher_set_name_owner_unlocked (name_watcher, new_owner);
228+ else
229+ g_warning ("Received NameOwnerChanged signal with invalid owner \"%s\" for \"%s\"",
230+ new_owner, name);
231+ }
232+ else
233+ {
234+ g_warning ("Received NameOwnerChanged signal with unexpected "
235+ "signature %s",
236+ body == NULL ? "()" : g_variant_get_type_string (body));
237+
238+ }
239+}
240+
241+/* called in GDBusWorker thread with lock held */
242+static void
243+name_watcher_deliver_get_name_owner_reply_unlocked (SignalData *name_watcher,
244+ GDBusConnection *connection,
245+ GDBusMessage *message)
246+{
247+ GDBusMessageType type;
248+ GVariant *body;
249+ WatchedName *watched_name;
250+
251+ watched_name = name_watcher->watched_name;
252+ g_assert (watched_name != NULL);
253+ g_assert (watched_name->get_name_owner_serial != 0);
254+
255+ type = g_dbus_message_get_message_type (message);
256+ body = g_dbus_message_get_body (message);
257+
258+ if (type == G_DBUS_MESSAGE_TYPE_ERROR)
259+ {
260+ if (g_strcmp0 (g_dbus_message_get_error_name (message),
261+ "org.freedesktop.DBus.Error.NameHasNoOwner"))
262+ name_watcher_set_name_owner_unlocked (name_watcher, NULL);
263+ /* else it's something like NoReply or AccessDenied, which tells
264+ * us nothing - leave the owner set to whatever we most recently
265+ * learned from NameOwnerChanged, or NULL */
266+ }
267+ else if (type != G_DBUS_MESSAGE_TYPE_METHOD_RETURN)
268+ {
269+ g_warning ("Received GetNameOwner reply with unexpected type %d",
270+ type);
271+ }
272+ else if (G_LIKELY (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)"))))
273+ {
274+ const char *new_owner;
275+
276+ g_variant_get (body, "(&s)", &new_owner);
277+
278+ if (G_LIKELY (g_dbus_is_unique_name (new_owner)))
279+ name_watcher_set_name_owner_unlocked (name_watcher, new_owner);
280+ else
281+ g_warning ("Received GetNameOwner reply with invalid owner \"%s\" for \"%s\"",
282+ new_owner, name_watcher->arg0);
283+ }
284+ else
285+ {
286+ g_warning ("Received GetNameOwner reply with unexpected signature %s",
287+ body == NULL ? "()" : g_variant_get_type_string (body));
288+ }
289+
290+ g_hash_table_remove (connection->map_method_serial_to_name_watcher,
291+ GUINT_TO_POINTER (watched_name->get_name_owner_serial));
292+ watched_name->get_name_owner_serial = 0;
293+}
294+
295+/* Called in a user thread, lock is held */
296+static void
297+name_watcher_call_get_name_owner_unlocked (GDBusConnection *connection,
298+ SignalData *name_watcher)
299+{
300+ GDBusMessage *message;
301+ GError *local_error = NULL;
302+ WatchedName *watched_name;
303+
304+ g_assert (g_strcmp0 (name_watcher->sender, DBUS_SERVICE_DBUS) == 0);
305+ g_assert (g_strcmp0 (name_watcher->interface_name, DBUS_INTERFACE_DBUS) == 0);
306+ g_assert (g_strcmp0 (name_watcher->member, "NameOwnerChanged") == 0);
307+ g_assert (g_strcmp0 (name_watcher->object_path, DBUS_PATH_DBUS) == 0);
308+ /* arg0 of the NameOwnerChanged message is the well-known name whose owner
309+ * we are interested in */
310+ g_assert (g_dbus_is_name (name_watcher->arg0));
311+ g_assert (name_watcher->flags == G_DBUS_SIGNAL_FLAGS_NONE);
312+
313+ watched_name = name_watcher->watched_name;
314+ g_assert (watched_name != NULL);
315+ g_assert (watched_name->owner == NULL);
316+ g_assert (watched_name->get_name_owner_serial == 0);
317+ g_assert (name_watcher->shared_name_watcher == NULL);
318+
319+ message = g_dbus_message_new_method_call (DBUS_SERVICE_DBUS,
320+ DBUS_PATH_DBUS,
321+ DBUS_INTERFACE_DBUS,
322+ "GetNameOwner");
323+ g_dbus_message_set_body (message, g_variant_new ("(s)", name_watcher->arg0));
324+
325+ if (g_dbus_connection_send_message_unlocked (connection, message,
326+ G_DBUS_SEND_MESSAGE_FLAGS_NONE,
327+ &watched_name->get_name_owner_serial,
328+ &local_error))
329+ {
330+ g_assert (watched_name->get_name_owner_serial != 0);
331+ g_hash_table_insert (connection->map_method_serial_to_name_watcher,
332+ GUINT_TO_POINTER (watched_name->get_name_owner_serial),
333+ name_watcher);
334+ }
335+ else
336+ {
337+ g_critical ("Error while sending GetNameOwner() message: %s",
338+ local_error->message);
339+ g_clear_error (&local_error);
340+ g_assert (watched_name->get_name_owner_serial == 0);
341+ }
342+
343+ g_object_unref (message);
344+}
345+
346+/* ---------------------------------------------------------------------------------------------------- */
347+
348 typedef struct
349 {
350 guint id;
351@@ -2389,6 +2636,7 @@ on_worker_message_received (GDBusWorker *worker,
352 {
353 guint32 reply_serial;
354 GTask *task;
355+ SignalData *name_watcher;
356
357 reply_serial = g_dbus_message_get_reply_serial (message);
358 CONNECTION_LOCK (connection);
359@@ -2404,6 +2652,19 @@ on_worker_message_received (GDBusWorker *worker,
360 {
361 //g_debug ("message reply/error for serial %d but no SendMessageData found for %p", reply_serial, connection);
362 }
363+
364+ name_watcher = g_hash_table_lookup (connection->map_method_serial_to_name_watcher,
365+ GUINT_TO_POINTER (reply_serial));
366+
367+ if (name_watcher != NULL)
368+ {
369+ g_assert (name_watcher->watched_name != NULL);
370+ g_assert (name_watcher->watched_name->get_name_owner_serial == reply_serial);
371+ name_watcher_deliver_get_name_owner_reply_unlocked (name_watcher,
372+ connection,
373+ message);
374+ }
375+
376 CONNECTION_UNLOCK (connection);
377 }
378 else if (message_type == G_DBUS_MESSAGE_TYPE_SIGNAL)
379@@ -3571,6 +3832,7 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
380 {
381 gchar *rule;
382 SignalData *signal_data;
383+ SignalData *name_watcher = NULL;
384 SignalSubscriber *subscriber;
385 gboolean sender_is_its_own_owner;
386 const gchar *sender_unique_name;
387@@ -3636,13 +3898,59 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
388
389 signal_data = signal_data_new_take (g_steal_pointer (&rule),
390 g_strdup (sender),
391- sender_is_its_own_owner,
392 g_strdup (interface_name),
393 g_strdup (member),
394 g_strdup (object_path),
395 g_strdup (arg0),
396 flags);
397 g_ptr_array_add (signal_data->subscribers, subscriber);
398+
399+ /* If subscribing to a signal from a specific sender with a well-known
400+ * name, we must first subscribe to NameOwnerChanged signals for that
401+ * well-known name, so that we can match the current owner of the name
402+ * against the sender of each signal. */
403+ if (sender != NULL && !sender_is_its_own_owner)
404+ {
405+ gchar *name_owner_rule = NULL;
406+
407+ /* We already checked that sender != NULL implies MESSAGE_BUS_CONNECTION */
408+ g_assert (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION);
409+
410+ name_owner_rule = args_to_rule (DBUS_SERVICE_DBUS,
411+ DBUS_INTERFACE_DBUS,
412+ "NameOwnerChanged",
413+ DBUS_PATH_DBUS,
414+ sender,
415+ G_DBUS_SIGNAL_FLAGS_NONE);
416+ name_watcher = g_hash_table_lookup (connection->map_rule_to_signal_data, name_owner_rule);
417+
418+ if (name_watcher == NULL)
419+ {
420+ name_watcher = signal_data_new_take (g_steal_pointer (&name_owner_rule),
421+ g_strdup (DBUS_SERVICE_DBUS),
422+ g_strdup (DBUS_INTERFACE_DBUS),
423+ g_strdup ("NameOwnerChanged"),
424+ g_strdup (DBUS_PATH_DBUS),
425+ g_strdup (sender),
426+ G_DBUS_SIGNAL_FLAGS_NONE);
427+ add_signal_data (connection, name_watcher, DBUS_SERVICE_DBUS);
428+ }
429+
430+ if (name_watcher->watched_name == NULL)
431+ {
432+ name_watcher->watched_name = watched_name_new ();
433+ name_watcher_call_get_name_owner_unlocked (connection, name_watcher);
434+ }
435+ else
436+ {
437+ g_ref_count_inc (&name_watcher->watched_name->ref_count);
438+ }
439+
440+ signal_data->shared_name_watcher = name_watcher;
441+
442+ g_clear_pointer (&name_owner_rule, g_free);
443+ }
444+
445 add_signal_data (connection, signal_data, sender_unique_name);
446
447 out:
448@@ -3670,10 +3978,18 @@ remove_signal_data_if_unused (GDBusConnection *connection,
449 const gchar *sender_unique_name;
450 GPtrArray *signal_data_array;
451
452+ /* Cannot remove while there are still subscribers */
453 if (signal_data->subscribers->len != 0)
454 return;
455
456- if (signal_data->sender_is_its_own_owner)
457+ /* Cannot remove while another SignalData is still using this one
458+ * as its shared_name_watcher, which holds watched_name->ref_count > 0 */
459+ if (signal_data->watched_name != NULL)
460+ return;
461+
462+ /* Point of no return: we have committed to removing it */
463+
464+ if (signal_data->sender != NULL && signal_data->shared_name_watcher == NULL)
465 sender_unique_name = signal_data->sender;
466 else
467 sender_unique_name = "";
468@@ -3706,6 +4022,15 @@ remove_signal_data_if_unused (GDBusConnection *connection,
469 remove_match_rule (connection, signal_data->rule);
470 }
471
472+ if (signal_data->shared_name_watcher != NULL)
473+ {
474+ SignalData *name_watcher = g_steal_pointer (&signal_data->shared_name_watcher);
475+
476+ name_watcher_unref_watched_name (connection, name_watcher);
477+ /* May free signal_data */
478+ remove_signal_data_if_unused (connection, name_watcher);
479+ }
480+
481 signal_data_free (signal_data);
482 }
483
484@@ -3978,6 +4303,17 @@ schedule_callbacks (GDBusConnection *connection,
485 continue;
486 }
487
488+ if (signal_data->watched_name != NULL)
489+ {
490+ /* Invariant: SignalData should only have a watched_name if it
491+ * represents the NameOwnerChanged signal */
492+ g_assert (g_strcmp0 (sender, DBUS_SERVICE_DBUS) == 0);
493+ g_assert (g_strcmp0 (interface, DBUS_INTERFACE_DBUS) == 0);
494+ g_assert (g_strcmp0 (path, DBUS_PATH_DBUS) == 0);
495+ g_assert (g_strcmp0 (member, "NameOwnerChanged") == 0);
496+ name_watcher_deliver_name_owner_changed_unlocked (signal_data, message);
497+ }
498+
499 for (m = 0; m < signal_data->subscribers->len; m++)
500 {
501 SignalSubscriber *subscriber = signal_data->subscribers->pdata[m];
502@@ -4039,7 +4375,7 @@ distribute_signals (GDBusConnection *connection,
503 schedule_callbacks (connection, signal_data_array, message, sender);
504 }
505
506- /* collect subscribers not matching on sender */
507+ /* collect subscribers not matching on sender, or matching a well-known name */
508 signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, "");
509 if (signal_data_array != NULL)
510 schedule_callbacks (connection, signal_data_array, message, sender);
511--
5122.30.2
513
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_14.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_14.patch
new file mode 100644
index 0000000000..ab6c049da7
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_14.patch
@@ -0,0 +1,75 @@
1From 69799764cb40a2842d4891d4e1d72c3ce73964ed Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@collabora.com>
3Date: Thu, 14 Mar 2024 20:42:41 +0000
4Subject: [PATCH 14/18] gdbusconnection: Don't deliver signals if the sender
5 doesn't match
6
7Otherwise a malicious connection on a shared bus, especially the system
8bus, could trick GDBus clients into processing signals sent by the
9malicious connection as though they had come from the real owner of a
10well-known service name.
11
12Resolves: https://gitlab.gnome.org/GNOME/glib/-/issues/3268
13Signed-off-by: Simon McVittie <smcv@collabora.com>
14
15CVE: CVE-2024-34397
16Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/69799764cb40a2842d4891d4e1d72c3ce73964ed]
17Signed-off-by: Peter Marko <peter.marko@siemens.com>
18---
19 gio/gdbusconnection.c | 40 ++++++++++++++++++++++++++++++++++++++++
20 1 file changed, 40 insertions(+)
21
22diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
23index 1ac120bc5..7cde0e3bf 100644
24--- a/gio/gdbusconnection.c
25+++ b/gio/gdbusconnection.c
26@@ -4284,6 +4284,46 @@ schedule_callbacks (GDBusConnection *connection,
27 if (signal_data->object_path != NULL && g_strcmp0 (signal_data->object_path, path) != 0)
28 continue;
29
30+ if (signal_data->shared_name_watcher != NULL)
31+ {
32+ /* We want signals from a specified well-known name, which means
33+ * the signal's sender needs to be the unique name that currently
34+ * owns that well-known name, and we will have found this
35+ * SignalData in
36+ * connection->map_sender_unique_name_to_signal_data_array[""]. */
37+ const WatchedName *watched_name;
38+ const char *current_owner;
39+
40+ g_assert (signal_data->sender != NULL);
41+ /* Invariant: We never need to watch for the owner of a unique
42+ * name, or for the owner of DBUS_SERVICE_DBUS, either of which
43+ * is always its own owner */
44+ g_assert (!g_dbus_is_unique_name (signal_data->sender));
45+ g_assert (g_strcmp0 (signal_data->sender, DBUS_SERVICE_DBUS) != 0);
46+
47+ watched_name = signal_data->shared_name_watcher->watched_name;
48+ g_assert (watched_name != NULL);
49+ current_owner = watched_name->owner;
50+
51+ /* Skip the signal if the actual sender is not known to own
52+ * the required name */
53+ if (current_owner == NULL || g_strcmp0 (current_owner, sender) != 0)
54+ continue;
55+ }
56+ else if (signal_data->sender != NULL)
57+ {
58+ /* We want signals from a unique name or o.fd.DBus... */
59+ g_assert (g_dbus_is_unique_name (signal_data->sender)
60+ || g_str_equal (signal_data->sender, DBUS_SERVICE_DBUS));
61+
62+ /* ... which means we must have found this SignalData in
63+ * connection->map_sender_unique_name_to_signal_data_array[signal_data->sender],
64+ * therefore we would only have found it if the signal's
65+ * actual sender matches the required signal_data->sender */
66+ g_assert (g_strcmp0 (signal_data->sender, sender) == 0);
67+ }
68+ /* else the sender is unspecified and we will accept anything */
69+
70 if (signal_data->arg0 != NULL)
71 {
72 if (arg0 == NULL)
73--
742.30.2
75
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_15.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_15.patch
new file mode 100644
index 0000000000..547884b796
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_15.patch
@@ -0,0 +1,47 @@
1From 505e2c644d02a5cf581fb85d145e820d51dc3f1b Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@collabora.com>
3Date: Fri, 8 Mar 2024 19:51:50 +0000
4Subject: [PATCH 15/18] tests: Add a test for matching by two well-known names
5
6The expected result is that because TEST_CONN_SERVICE owns
7ALREADY_OWNED_NAME but not (yet) OWNED_LATER_NAME, the signal will be
8delivered to the subscriber for the former but not the latter.
9Before #3268 was fixed, it was incorrectly delivered to both.
10
11Reproduces: https://gitlab.gnome.org/GNOME/glib/-/issues/3268 (partially)
12Signed-off-by: Simon McVittie <smcv@collabora.com>
13
14CVE: CVE-2024-34397
15Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/505e2c644d02a5cf581fb85d145e820d51dc3f1b]
16Signed-off-by: Peter Marko <peter.marko@siemens.com>
17---
18 gio/tests/gdbus-subscribe.c | 13 +++++++++++++
19 1 file changed, 13 insertions(+)
20
21diff --git a/gio/tests/gdbus-subscribe.c b/gio/tests/gdbus-subscribe.c
22index af100de7d..171d6107d 100644
23--- a/gio/tests/gdbus-subscribe.c
24+++ b/gio/tests/gdbus-subscribe.c
25@@ -440,6 +440,19 @@ static const TestPlan plan_limit_by_well_known_name =
26 .iface = EXAMPLE_INTERFACE,
27 },
28 },
29+ {
30+ /* When the service sends a signal with the name it already owns,
31+ * it should get through */
32+ .action = TEST_ACTION_EMIT_SIGNAL,
33+ .u.signal = {
34+ .sender = TEST_CONN_SERVICE,
35+ .path = EXAMPLE_PATH,
36+ .iface = EXAMPLE_INTERFACE,
37+ .member = FOO_SIGNAL,
38+ .received_by_conn = 1,
39+ .received_by_proxy = 1
40+ },
41+ },
42 {
43 /* Service claims another name */
44 .action = TEST_ACTION_OWN_NAME,
45--
462.30.2
47
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_16.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_16.patch
new file mode 100644
index 0000000000..d582f84a36
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_16.patch
@@ -0,0 +1,62 @@
1From 8338f7ac107f642283437d05d7b4d49ca8968cdf Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@collabora.com>
3Date: Fri, 8 Mar 2024 19:53:22 +0000
4Subject: [PATCH 16/18] tests: Add a test for signal filtering by well-known
5 name
6
7The vulnerability reported as GNOME/glib#3268 can be characterized
8as: these signals from an attacker should not be delivered to either
9the GDBusConnection or the GDBusProxy, but in fact they are (in at
10least some scenarios).
11
12Reproduces: https://gitlab.gnome.org/GNOME/glib/-/issues/3268
13Signed-off-by: Simon McVittie <smcv@collabora.com>
14
15CVE: CVE-2024-34397
16Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/8338f7ac107f642283437d05d7b4d49ca8968cdf]
17Signed-off-by: Peter Marko <peter.marko@siemens.com>
18---
19 gio/tests/gdbus-subscribe.c | 27 +++++++++++++++++++++++++++
20 1 file changed, 27 insertions(+)
21
22diff --git a/gio/tests/gdbus-subscribe.c b/gio/tests/gdbus-subscribe.c
23index 171d6107d..5406ba7e2 100644
24--- a/gio/tests/gdbus-subscribe.c
25+++ b/gio/tests/gdbus-subscribe.c
26@@ -440,6 +440,33 @@ static const TestPlan plan_limit_by_well_known_name =
27 .iface = EXAMPLE_INTERFACE,
28 },
29 },
30+ {
31+ /* Attacker wants to trick subscriber into thinking that service
32+ * sent a signal */
33+ .action = TEST_ACTION_EMIT_SIGNAL,
34+ .u.signal = {
35+ .sender = TEST_CONN_ATTACKER,
36+ .path = EXAMPLE_PATH,
37+ .iface = EXAMPLE_INTERFACE,
38+ .member = FOO_SIGNAL,
39+ .received_by_conn = 0,
40+ .received_by_proxy = 0
41+ },
42+ },
43+ {
44+ /* Attacker tries harder, by sending a signal unicast directly to
45+ * the subscriber */
46+ .action = TEST_ACTION_EMIT_SIGNAL,
47+ .u.signal = {
48+ .sender = TEST_CONN_ATTACKER,
49+ .unicast_to = TEST_CONN_SUBSCRIBER,
50+ .path = EXAMPLE_PATH,
51+ .iface = EXAMPLE_INTERFACE,
52+ .member = FOO_SIGNAL,
53+ .received_by_conn = 0,
54+ .received_by_proxy = 0
55+ },
56+ },
57 {
58 /* When the service sends a signal with the name it already owns,
59 * it should get through */
60--
612.30.2
62
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_17.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_17.patch
new file mode 100644
index 0000000000..7f5776d0c3
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_17.patch
@@ -0,0 +1,121 @@
1From ff467241a37a0119d3c6df53548bb61fe4d4fbf9 Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@collabora.com>
3Date: Tue, 23 Apr 2024 21:39:43 +0100
4Subject: [PATCH 17/18] tests: Ensure that unsubscribing with GetNameOwner
5 in-flight doesn't crash
6
7This was a bug that existed during development of this branch; make sure
8it doesn't come back.
9
10This test fails with a use-after-free and crash if we comment out the
11part of name_watcher_unref_watched_name() that removes the name watcher
12from `map_method_serial_to_name_watcher`.
13
14It would also fail with an assertion failure if we asserted in
15name_watcher_unref_watched_name() that get_name_owner_serial == 0
16(i.e. that GetNameOwner is not in-flight at destruction).
17
18Signed-off-by: Simon McVittie <smcv@collabora.com>
19
20CVE: CVE-2024-34397
21Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/ff467241a37a0119d3c6df53548bb61fe4d4fbf9]
22Signed-off-by: Peter Marko <peter.marko@siemens.com>
23---
24 gio/tests/gdbus-subscribe.c | 52 ++++++++++++++++++++++++++++++++++++-
25 1 file changed, 51 insertions(+), 1 deletion(-)
26
27diff --git a/gio/tests/gdbus-subscribe.c b/gio/tests/gdbus-subscribe.c
28index 5406ba7e2..4cba4f565 100644
29--- a/gio/tests/gdbus-subscribe.c
30+++ b/gio/tests/gdbus-subscribe.c
31@@ -116,6 +116,7 @@ typedef struct
32 const char *member;
33 const char *arg0;
34 GDBusSignalFlags flags;
35+ gboolean unsubscribe_immediately;
36 } TestSubscribe;
37
38 typedef struct
39@@ -141,6 +142,7 @@ typedef struct
40 TestEmitSignal signal;
41 TestSubscribe subscribe;
42 TestOwnName own_name;
43+ guint unsubscribe_undo_step;
44 } u;
45 } TestStep;
46
47@@ -505,6 +507,43 @@ static const TestPlan plan_limit_by_well_known_name =
48 },
49 };
50
51+static const TestPlan plan_unsubscribe_immediately =
52+{
53+ .description = "Unsubscribing before GetNameOwner can return doesn't result in a crash",
54+ .steps = {
55+ {
56+ /* Service already owns one name */
57+ .action = TEST_ACTION_OWN_NAME,
58+ .u.own_name = {
59+ .name = ALREADY_OWNED_NAME,
60+ .owner = TEST_CONN_SERVICE
61+ },
62+ },
63+ {
64+ .action = TEST_ACTION_SUBSCRIBE,
65+ .u.subscribe = {
66+ .string_sender = ALREADY_OWNED_NAME,
67+ .path = EXAMPLE_PATH,
68+ .iface = EXAMPLE_INTERFACE,
69+ .unsubscribe_immediately = TRUE
70+ },
71+ },
72+ {
73+ .action = TEST_ACTION_EMIT_SIGNAL,
74+ .u.signal = {
75+ .sender = TEST_CONN_SERVICE,
76+ .path = EXAMPLE_PATH,
77+ .iface = EXAMPLE_INTERFACE,
78+ .member = FOO_SIGNAL,
79+ .received_by_conn = 0,
80+ /* The proxy can't unsubscribe, except by destroying the proxy
81+ * completely, which we don't currently implement in this test */
82+ .received_by_proxy = 1
83+ },
84+ },
85+ },
86+};
87+
88 static const TestPlan plan_limit_to_message_bus =
89 {
90 .description = "A subscription to the message bus only accepts messages "
91@@ -855,8 +894,18 @@ fixture_subscribe (Fixture *f,
92 subscribe->flags,
93 subscribed_signal_cb,
94 f, NULL);
95+
96 g_assert_cmpuint (id, !=, 0);
97- f->subscriptions[step_number] = id;
98+
99+ if (subscribe->unsubscribe_immediately)
100+ {
101+ g_test_message ("\tImmediately unsubscribing");
102+ g_dbus_connection_signal_unsubscribe (subscriber, id);
103+ }
104+ else
105+ {
106+ f->subscriptions[step_number] = id;
107+ }
108 }
109
110 if (f->mode != SUBSCRIPTION_MODE_CONN)
111@@ -1287,6 +1336,7 @@ main (int argc,
112 ADD_SUBSCRIBE_TEST (nonexistent_unique_name);
113 ADD_SUBSCRIBE_TEST (limit_by_well_known_name);
114 ADD_SUBSCRIBE_TEST (limit_to_message_bus);
115+ ADD_SUBSCRIBE_TEST (unsubscribe_immediately);
116
117 return g_test_run();
118 }
119--
1202.30.2
121
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_18.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_18.patch
new file mode 100644
index 0000000000..a19ce24555
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2024-34397_18.patch
@@ -0,0 +1,50 @@
1From fe11c6a513a1b16462442e361bab753246c8de2e Mon Sep 17 00:00:00 2001
2From: Simon McVittie <smcv@debian.org>
3Date: Mon, 6 May 2024 21:24:53 +0100
4Subject: [PATCH 18/18] gdbus-proxy test: Wait before asserting name owner has
5 gone away
6
7GDBusConnection sends each signal to recipients in a separate idle
8callback, and there's no particular guarantee about the order in which
9they're scheduled or dispatched. For the NameOwnerChanged signal that
10reports the name becoming unowned, it's possible that g_bus_watch_name()
11gets its idle callback called before the GDBusProxy:g-name-owner
12machinery has updated the name owner, in which case the assertion
13will fail.
14
15Fixing GNOME/glib#3268 introduced a new subscription to NameOwnerChanged
16which can alter the order of delivery, particularly in the case where
17G_DBUS_PROXY_FLAGS_NO_MATCH_RULE was used (as tested in
18/gdbus/proxy/no-match-rule). The resulting test failure is intermittent,
19but reliably appears within 100 repetitions of that test.
20
21Fixes: 511c5f5b "tests: Wait for gdbus-testserver to die when killing it"
22Signed-off-by: Simon McVittie <smcv@debian.org>
23
24CVE: CVE-2024-34397
25Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/fe11c6a513a1b16462442e361bab753246c8de2e]
26Signed-off-by: Peter Marko <peter.marko@siemens.com>
27---
28 gio/tests/gdbus-proxy.c | 6 ++++++
29 1 file changed, 6 insertions(+)
30
31diff --git a/gio/tests/gdbus-proxy.c b/gio/tests/gdbus-proxy.c
32index eed75acf4..9303d0088 100644
33--- a/gio/tests/gdbus-proxy.c
34+++ b/gio/tests/gdbus-proxy.c
35@@ -778,6 +778,12 @@ kill_test_service (GDBusConnection *connection)
36 while (!name_disappeared)
37 g_main_context_iteration (NULL, TRUE);
38
39+ /* GDBusConnection doesn't guarantee that different subscriptions to the
40+ * same signal will get their callbacks scheduled in any particular order,
41+ * so make sure they have all happened */
42+ while (g_main_context_iteration (NULL, FALSE))
43+ continue;
44+
45 g_bus_unwatch_name (watch_id);
46 #else
47 g_warning ("Can't kill com.example.TestService");
48--
492.30.2
50
diff --git a/meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb b/meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb
index 24c590a714..35b51a3ec9 100644
--- a/meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb
+++ b/meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb
@@ -31,6 +31,24 @@ SRC_URI = "${GNOME_MIRROR}/glib/${SHRT_VER}/glib-${PV}.tar.xz \
31 file://CVE-2023-32611-0002.patch \ 31 file://CVE-2023-32611-0002.patch \
32 file://CVE-2023-32643.patch \ 32 file://CVE-2023-32643.patch \
33 file://CVE-2023-32636.patch \ 33 file://CVE-2023-32636.patch \
34 file://CVE-2024-34397_01.patch \
35 file://CVE-2024-34397_02.patch \
36 file://CVE-2024-34397_03.patch \
37 file://CVE-2024-34397_04.patch \
38 file://CVE-2024-34397_05.patch \
39 file://CVE-2024-34397_06.patch \
40 file://CVE-2024-34397_07.patch \
41 file://CVE-2024-34397_08.patch \
42 file://CVE-2024-34397_09.patch \
43 file://CVE-2024-34397_10.patch \
44 file://CVE-2024-34397_11.patch \
45 file://CVE-2024-34397_12.patch \
46 file://CVE-2024-34397_13.patch \
47 file://CVE-2024-34397_14.patch \
48 file://CVE-2024-34397_15.patch \
49 file://CVE-2024-34397_16.patch \
50 file://CVE-2024-34397_17.patch \
51 file://CVE-2024-34397_18.patch \
34 " 52 "
35SRC_URI:append:class-native = " file://relocate-modules.patch" 53SRC_URI:append:class-native = " file://relocate-modules.patch"
36 54