diff --git a/lang/php8/Makefile b/lang/php8/Makefile index c85d5bd0cf..50f61eb5b8 100644 --- a/lang/php8/Makefile +++ b/lang/php8/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=php -PKG_VERSION:=8.2.22 +PKG_VERSION:=8.2.23 PKG_RELEASE:=1 PKG_MAINTAINER:=Michael Heimpold @@ -16,7 +16,7 @@ PKG_CPE_ID:=cpe:/a:php:php PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=https://www.php.net/distributions/ -PKG_HASH:=8566229bc88ad1f4aadc10700ab5fbcec81587c748999d985f11cf3b745462df +PKG_HASH:=81c5ae6ba44e262a076349ee54a2e468638a4571085d80bff37f6fd308e1d8d5 PKG_BUILD_PARALLEL:=1 PKG_BUILD_FLAGS:=no-mips16 diff --git a/lang/php8/patches/0007-Add-support-for-use-of-the-system-timezone-database.patch b/lang/php8/patches/0007-Add-support-for-use-of-the-system-timezone-database.patch index ce1ab37ca4..0eaead3455 100644 --- a/lang/php8/patches/0007-Add-support-for-use-of-the-system-timezone-database.patch +++ b/lang/php8/patches/0007-Add-support-for-use-of-the-system-timezone-database.patch @@ -62,9 +62,9 @@ r1: initial revision + fi +fi + - PHP_DATE_CFLAGS="-Wno-implicit-fallthrough -I@ext_builddir@/lib -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DHAVE_TIMELIB_CONFIG_H=1" - timelib_sources="lib/astro.c lib/dow.c lib/parse_date.c lib/parse_tz.c lib/parse_posix.c - lib/timelib.c lib/tm2unixtime.c lib/unixtime2tm.c lib/parse_iso_intervals.c lib/interval.c" + AX_CHECK_COMPILE_FLAG([-Wno-implicit-fallthrough], + [PHP_DATE_CFLAGS="$PHP_DATE_CFLAGS -Wno-implicit-fallthrough"],, + [-Werror]) --- a/ext/date/lib/parse_tz.c +++ b/ext/date/lib/parse_tz.c @@ -26,9 +26,22 @@ diff --git a/libs/glib2/Makefile b/libs/glib2/Makefile index 5ded2fbddf..37c64dd6a8 100644 --- a/libs/glib2/Makefile +++ b/libs/glib2/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=glib2 -PKG_VERSION:=2.74.0 -PKG_RELEASE:=5 +PKG_VERSION:=2.74.7 +PKG_RELEASE:=1 PKG_SOURCE:=glib-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=@GNOME/glib/$(basename $(PKG_VERSION)) -PKG_HASH:=3652c7f072d7b031a6b5edd623f77ebc5dcd2ae698598abcc89ff39ca75add30 +PKG_HASH:=196ab86c27127a61b7a70c3ba6af7b97bdc01c07cd3b21abd5e778b955eccb1b PKG_MAINTAINER:=Peter Wagner PKG_LICENSE:=LGPL-2.1-or-later diff --git a/libs/glib2/patches/006-c99.patch b/libs/glib2/patches/006-c99.patch index de348d3850..b6d160737a 100644 --- a/libs/glib2/patches/006-c99.patch +++ b/libs/glib2/patches/006-c99.patch @@ -1,6 +1,6 @@ --- a/meson.build +++ b/meson.build -@@ -1045,7 +1045,7 @@ if host_system == 'windows' and (cc.get_ +@@ -1062,7 +1062,7 @@ if host_system == 'windows' and (cc.get_ glib_conf.set('HAVE_C99_SNPRINTF', false) glib_conf.set('HAVE_C99_VSNPRINTF', false) glib_conf.set('HAVE_UNIX98_PRINTF', false) diff --git a/libs/glib2/patches/010-pcre.patch b/libs/glib2/patches/010-pcre.patch index 87b32e73e9..4682134f11 100644 --- a/libs/glib2/patches/010-pcre.patch +++ b/libs/glib2/patches/010-pcre.patch @@ -1,6 +1,6 @@ --- a/glib/meson.build +++ b/glib/meson.build -@@ -365,6 +365,7 @@ pcre2_static_args = [] +@@ -366,6 +366,7 @@ pcre2_static_args = [] if use_pcre2_static_flag pcre2_static_args = ['-DPCRE2_STATIC'] diff --git a/libs/glib2/patches/020-locale.patch b/libs/glib2/patches/020-locale.patch index e171d58e13..9451634cb4 100644 --- a/libs/glib2/patches/020-locale.patch +++ b/libs/glib2/patches/020-locale.patch @@ -12,9 +12,9 @@ https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2797 --- a/gobject/glib-mkenums.in +++ b/gobject/glib-mkenums.in -@@ -19,6 +19,9 @@ import errno - import codecs - import locale +@@ -22,6 +22,9 @@ import locale + # Non-english locale systems might complain to unrecognized character + sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='utf-8') +# Non-english locale systems might complain to unrecognized character +sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='utf-8') diff --git a/libs/glib2/patches/100-CVE-2024-34397-gdbusmessage-Cache-the-arg0-value.patch b/libs/glib2/patches/100-CVE-2024-34397-gdbusmessage-Cache-the-arg0-value.patch new file mode 100644 index 0000000000..1746b7c759 --- /dev/null +++ b/libs/glib2/patches/100-CVE-2024-34397-gdbusmessage-Cache-the-arg0-value.patch @@ -0,0 +1,120 @@ +From: Philip Withnall +Date: Tue, 28 Nov 2023 12:58:20 +0000 +Subject: gdbusmessage: Cache the arg0 value +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 8bit + +Technically we can’t rely on it being kept alive by the `message->body` +pointer, unless we can guarantee that the `GVariant` is always +serialised. That’s not necessarily the case, so keep a separate ref on +the arg0 value at all times. + +This avoids a potential use-after-free. + +Spotted by Thomas Haller in +https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3720#note_1924707. + +[This is a prerequisite for having tests pass after fixing the +vulnerability described in glib#3268, because after fixing that +vulnerability, the use-after-free genuinely does happen during +regression testing. -smcv] + +Signed-off-by: Philip Withnall + +Helps: #3183, #3268 +(cherry picked from commit 10e9a917be7fb92b6b27837ef7a7f1d0be6095d5) +Origin: upstream, commit:https://gitlab.gnome.org/GNOME/glib/-/commit/10e9a917be7fb92b6b27837ef7a7f1d0be6095d5 +--- + gio/gdbusmessage.c | 35 ++++++++++++++++++++++------------- + 1 file changed, 22 insertions(+), 13 deletions(-) + +--- a/gio/gdbusmessage.c ++++ b/gio/gdbusmessage.c +@@ -508,6 +508,7 @@ struct _GDBusMessage + guint32 serial; + GHashTable *headers; + GVariant *body; ++ GVariant *arg0_cache; /* (nullable) (owned) */ + #ifdef G_OS_UNIX + GUnixFDList *fd_list; + #endif +@@ -530,6 +531,7 @@ g_dbus_message_finalize (GObject *object + g_hash_table_unref (message->headers); + if (message->body != NULL) + g_variant_unref (message->body); ++ g_clear_pointer (&message->arg0_cache, g_variant_unref); + #ifdef G_OS_UNIX + if (message->fd_list != NULL) + g_object_unref (message->fd_list); +@@ -1165,6 +1167,7 @@ g_dbus_message_set_body (GDBusMessage * + if (body == NULL) + { + message->body = NULL; ++ message->arg0_cache = NULL; + g_dbus_message_set_signature (message, NULL); + } + else +@@ -1175,6 +1178,12 @@ g_dbus_message_set_body (GDBusMessage * + + message->body = g_variant_ref_sink (body); + ++ if (g_variant_is_of_type (message->body, G_VARIANT_TYPE_TUPLE) && ++ g_variant_n_children (message->body) > 0) ++ message->arg0_cache = g_variant_get_child_value (message->body, 0); ++ else ++ message->arg0_cache = NULL; ++ + type_string = g_variant_get_type_string (body); + type_string_len = strlen (type_string); + g_assert (type_string_len >= 2); +@@ -2327,6 +2336,14 @@ g_dbus_message_new_from_blob (guchar + 2, + &local_error); + g_variant_type_free (variant_type); ++ ++ if (message->body != NULL && ++ g_variant_is_of_type (message->body, G_VARIANT_TYPE_TUPLE) && ++ g_variant_n_children (message->body) > 0) ++ message->arg0_cache = g_variant_get_child_value (message->body, 0); ++ else ++ message->arg0_cache = NULL; ++ + if (message->body == NULL) + goto fail; + } +@@ -3366,22 +3383,13 @@ g_dbus_message_set_signature (GDBusMessa + const gchar * + g_dbus_message_get_arg0 (GDBusMessage *message) + { +- const gchar *ret; +- + g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL); + +- ret = NULL; ++ if (message->arg0_cache != NULL && ++ g_variant_is_of_type (message->arg0_cache, G_VARIANT_TYPE_STRING)) ++ return g_variant_get_string (message->arg0_cache, NULL); + +- if (message->body != NULL && g_variant_is_of_type (message->body, G_VARIANT_TYPE_TUPLE)) +- { +- GVariant *item; +- item = g_variant_get_child_value (message->body, 0); +- if (g_variant_is_of_type (item, G_VARIANT_TYPE_STRING)) +- ret = g_variant_get_string (item, NULL); +- g_variant_unref (item); +- } +- +- return ret; ++ return NULL; + } + + /* ---------------------------------------------------------------------------------------------------- */ +@@ -3824,6 +3832,7 @@ g_dbus_message_copy (GDBusMessage *mess + * to just ref (as opposed to deep-copying) the GVariant instances + */ + ret->body = message->body != NULL ? g_variant_ref (message->body) : NULL; ++ ret->arg0_cache = message->arg0_cache != NULL ? g_variant_ref (message->arg0_cache) : NULL; + g_hash_table_iter_init (&iter, message->headers); + while (g_hash_table_iter_next (&iter, &header_key, (gpointer) &header_value)) + g_hash_table_insert (ret->headers, header_key, g_variant_ref (header_value)); diff --git a/libs/glib2/patches/101-CVE-2024-34397-gdbusconnection-Make-a-backport-of-g_set_str-available.patch b/libs/glib2/patches/101-CVE-2024-34397-gdbusconnection-Make-a-backport-of-g_set_str-available.patch new file mode 100644 index 0000000000..1859e0871a --- /dev/null +++ b/libs/glib2/patches/101-CVE-2024-34397-gdbusconnection-Make-a-backport-of-g_set_str-available.patch @@ -0,0 +1,50 @@ +From: Simon McVittie +Date: Wed, 1 May 2024 15:51:42 +0100 +Subject: gdbusconnection: Make a backport of g_set_str() available + +A subsequent commit will need this. Copying all of g_set_str() into a +private header seems cleaner than replacing the call to it. + +Helps: GNOME/glib#3268 +Signed-off-by: Simon McVittie +Origin: upstream, https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +--- + gio/gdbusconnection.c | 1 + + glib/glib-private.h | 18 ++++++++++++++++++ + 2 files changed, 19 insertions(+) + +--- a/gio/gdbusconnection.c ++++ b/gio/gdbusconnection.c +@@ -97,6 +97,7 @@ + #include + #include + ++#include "glib-private.h" + #include "gdbusauth.h" + #include "gdbusutils.h" + #include "gdbusaddress.h" +--- a/glib/glib-private.h ++++ b/glib/glib-private.h +@@ -210,4 +210,22 @@ GLibPrivateVTable *glib__private__ (void + # define GLIB_DEFAULT_LOCALE "" + #endif + ++/* Backported from GLib 2.78.x, where it is public API in gstrfuncs.h */ ++static inline gboolean ++g_set_str (char **str_pointer, ++ const char *new_str) ++{ ++ char *copy; ++ ++ if (*str_pointer == new_str || ++ (*str_pointer && new_str && strcmp (*str_pointer, new_str) == 0)) ++ return FALSE; ++ ++ copy = g_strdup (new_str); ++ g_free (*str_pointer); ++ *str_pointer = copy; ++ ++ return TRUE; ++} ++ + #endif /* __GLIB_PRIVATE_H__ */ diff --git a/libs/glib2/patches/102-CVE-2024-34397-tests-Add-a-data-driven-test-for-signal-subscriptions.patch b/libs/glib2/patches/102-CVE-2024-34397-tests-Add-a-data-driven-test-for-signal-subscriptions.patch new file mode 100644 index 0000000000..468ff63dee --- /dev/null +++ b/libs/glib2/patches/102-CVE-2024-34397-tests-Add-a-data-driven-test-for-signal-subscriptions.patch @@ -0,0 +1,973 @@ +From: Simon McVittie +Date: Fri, 8 Mar 2024 14:19:46 +0000 +Subject: tests: Add a data-driven test for signal subscriptions + +This somewhat duplicates test_connection_signals(), but is easier to +extend to cover different scenarios. + +Each scenario is tested three times: once with lower-level +GDBusConnection APIs, once with the higher-level GDBusProxy (which +cannot implement all of the subscription scenarios, so some message +counts are lower), and once with both (to check that delivery of the +same message to multiple destinations is handled appropriately). + +[Backported to glib-2-74, resolving conflicts in gio/tests/meson.build] +Signed-off-by: Simon McVittie +Origin: upstream, https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +--- + gio/tests/gdbus-subscribe.c | 938 ++++++++++++++++++++++++++++++++++++++++++++ + gio/tests/meson.build | 1 + + 2 files changed, 939 insertions(+) + create mode 100644 gio/tests/gdbus-subscribe.c + +--- /dev/null ++++ b/gio/tests/gdbus-subscribe.c +@@ -0,0 +1,938 @@ ++/* ++ * Copyright 2024 Collabora Ltd. ++ * SPDX-License-Identifier: LGPL-2.1-or-later ++ */ ++ ++#include ++ ++#include "gdbus-tests.h" ++ ++#define DBUS_SERVICE_DBUS "org.freedesktop.DBus" ++#define DBUS_PATH_DBUS "/org/freedesktop/DBus" ++#define DBUS_INTERFACE_DBUS DBUS_SERVICE_DBUS ++ ++/* A signal that each connection emits to indicate that it has finished ++ * emitting other signals */ ++#define FINISHED_PATH "/org/gtk/Test/Finished" ++#define FINISHED_INTERFACE "org.gtk.Test.Finished" ++#define FINISHED_SIGNAL "Finished" ++ ++/* A signal emitted during testing */ ++#define EXAMPLE_PATH "/org/gtk/GDBus/ExampleInterface" ++#define EXAMPLE_INTERFACE "org.gtk.GDBus.ExampleInterface" ++#define FOO_SIGNAL "Foo" ++ ++/* Log @s in a debug message. */ ++static inline const char * ++nonnull (const char *s, ++ const char *if_null) ++{ ++ return (s == NULL) ? if_null : s; ++} ++ ++typedef enum ++{ ++ TEST_CONN_NONE, ++ TEST_CONN_FIRST, ++ /* A connection that subscribes to signals */ ++ TEST_CONN_SUBSCRIBER = TEST_CONN_FIRST, ++ /* A mockup of a legitimate service */ ++ TEST_CONN_SERVICE, ++ /* A mockup of a second legitimate service */ ++ TEST_CONN_SERVICE2, ++ /* A connection that tries to trick @subscriber into processing its signals ++ * as if they came from @service */ ++ TEST_CONN_ATTACKER, ++ NUM_TEST_CONNS ++} TestConn; ++ ++static const char * const test_conn_descriptions[NUM_TEST_CONNS] = ++{ ++ "(unused)", ++ "subscriber", ++ "service", ++ "service 2", ++ "attacker" ++}; ++ ++typedef enum ++{ ++ SUBSCRIPTION_MODE_CONN, ++ SUBSCRIPTION_MODE_PROXY, ++ SUBSCRIPTION_MODE_PARALLEL ++} SubscriptionMode; ++ ++typedef struct ++{ ++ GDBusProxy *received_by_proxy; ++ TestConn sender; ++ char *path; ++ char *iface; ++ char *member; ++ GVariant *parameters; ++ char *arg0; ++ guint32 step; ++} ReceivedMessage; ++ ++static void ++received_message_free (ReceivedMessage *self) ++{ ++ ++ g_clear_object (&self->received_by_proxy); ++ g_free (self->path); ++ g_free (self->iface); ++ g_free (self->member); ++ g_clear_pointer (&self->parameters, g_variant_unref); ++ g_free (self->arg0); ++ g_free (self); ++} ++ ++typedef struct ++{ ++ TestConn sender; ++ TestConn unicast_to; ++ const char *path; ++ const char *iface; ++ const char *member; ++ const char *arg0; ++ guint received_by_conn; ++ guint received_by_proxy; ++} TestEmitSignal; ++ ++typedef struct ++{ ++ TestConn sender; ++ const char *path; ++ const char *iface; ++ const char *member; ++ const char *arg0; ++ GDBusSignalFlags flags; ++} TestSubscribe; ++ ++typedef enum ++{ ++ TEST_ACTION_NONE = 0, ++ TEST_ACTION_SUBSCRIBE, ++ TEST_ACTION_EMIT_SIGNAL, ++} TestAction; ++ ++typedef struct ++{ ++ TestAction action; ++ union { ++ TestEmitSignal signal; ++ TestSubscribe subscribe; ++ } u; ++} TestStep; ++ ++/* Arbitrary, extend as necessary to accommodate the longest test */ ++#define MAX_TEST_STEPS 10 ++ ++typedef struct ++{ ++ const char *description; ++ TestStep steps[MAX_TEST_STEPS]; ++} TestPlan; ++ ++static const TestPlan plan_simple = ++{ ++ .description = "A broadcast is only received after subscribing to it", ++ .steps = { ++ { ++ /* We don't receive a signal if we haven't subscribed yet */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_SERVICE, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 0, ++ .received_by_proxy = 0 ++ }, ++ }, ++ { ++ .action = TEST_ACTION_SUBSCRIBE, ++ .u.subscribe = { ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ }, ++ }, ++ { ++ /* Now it works */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_SERVICE, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 1, ++ /* The proxy can't be used in this case, because it needs ++ * a bus name to subscribe to */ ++ .received_by_proxy = 0 ++ }, ++ }, ++ }, ++}; ++ ++static const TestPlan plan_broadcast_from_anyone = ++{ ++ .description = "A subscription with NULL sender accepts broadcast and unicast", ++ .steps = { ++ { ++ /* Subscriber wants to receive signals from anyone */ ++ .action = TEST_ACTION_SUBSCRIBE, ++ .u.subscribe = { ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ }, ++ }, ++ { ++ /* First service sends a broadcast */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_SERVICE, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 1, ++ .received_by_proxy = 0 ++ }, ++ }, ++ { ++ /* Second service also sends a broadcast */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_SERVICE2, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 1, ++ .received_by_proxy = 0 ++ }, ++ }, ++ { ++ /* First service sends a unicast signal */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_SERVICE, ++ .unicast_to = TEST_CONN_SUBSCRIBER, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 1, ++ .received_by_proxy = 0 ++ }, ++ }, ++ { ++ /* Second service also sends a unicast signal */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_SERVICE2, ++ .unicast_to = TEST_CONN_SUBSCRIBER, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 1, ++ .received_by_proxy = 0 ++ }, ++ }, ++ }, ++}; ++ ++static const TestPlan plan_match_twice = ++{ ++ .description = "A message matching more than one subscription is received " ++ "once per subscription", ++ .steps = { ++ { ++ .action = TEST_ACTION_SUBSCRIBE, ++ .u.subscribe = { ++ .sender = TEST_CONN_SERVICE, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ }, ++ }, ++ { ++ .action = TEST_ACTION_SUBSCRIBE, ++ .u.subscribe = { ++ .path = EXAMPLE_PATH, ++ }, ++ }, ++ { ++ .action = TEST_ACTION_SUBSCRIBE, ++ .u.subscribe = { ++ .iface = EXAMPLE_INTERFACE, ++ }, ++ }, ++ { ++ .action = TEST_ACTION_SUBSCRIBE, ++ .u.subscribe = { ++ .sender = TEST_CONN_SERVICE, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ }, ++ }, ++ { ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_SERVICE, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 4, ++ /* Only the first and last work with GDBusProxy */ ++ .received_by_proxy = 2 ++ }, ++ }, ++ }, ++}; ++ ++static const TestPlan plan_limit_by_unique_name = ++{ ++ .description = "A subscription via a unique name only accepts messages " ++ "sent by that same unique name", ++ .steps = { ++ { ++ /* Subscriber wants to receive signals from service */ ++ .action = TEST_ACTION_SUBSCRIBE, ++ .u.subscribe = { ++ .sender = TEST_CONN_SERVICE, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ }, ++ }, ++ { ++ /* Attacker wants to trick subscriber into thinking that service ++ * sent a signal */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_ATTACKER, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 0, ++ .received_by_proxy = 0 ++ }, ++ }, ++ { ++ /* Attacker tries harder, by sending a signal unicast directly to ++ * the subscriber */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_ATTACKER, ++ .unicast_to = TEST_CONN_SUBSCRIBER, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 0, ++ .received_by_proxy = 0 ++ }, ++ }, ++ { ++ /* When the real service sends a signal, it should still get through */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_SERVICE, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 1, ++ .received_by_proxy = 1 ++ }, ++ }, ++ }, ++}; ++ ++typedef struct ++{ ++ const TestPlan *plan; ++ SubscriptionMode mode; ++ GError *error; ++ /* (element-type ReceivedMessage) */ ++ GPtrArray *received; ++ /* conns[TEST_CONN_NONE] is unused and remains NULL */ ++ GDBusConnection *conns[NUM_TEST_CONNS]; ++ /* Proxies on conns[TEST_CONN_SUBSCRIBER] */ ++ GPtrArray *proxies; ++ /* unique_names[TEST_CONN_NONE] is unused and remains NULL */ ++ const char *unique_names[NUM_TEST_CONNS]; ++ /* finished[TEST_CONN_NONE] is unused and remains FALSE */ ++ gboolean finished[NUM_TEST_CONNS]; ++ /* Remains 0 for any step that is not a subscription */ ++ guint subscriptions[MAX_TEST_STEPS]; ++ /* Number of times the signal from step n was received */ ++ guint received_by_conn[MAX_TEST_STEPS]; ++ /* Number of times the signal from step n was received */ ++ guint received_by_proxy[MAX_TEST_STEPS]; ++ guint finished_subscription; ++} Fixture; ++ ++/* Wait for asynchronous messages from @conn to have been processed ++ * by the message bus, as a sequence point so that we can make ++ * "happens before" and "happens after" assertions relative to this. ++ * The easiest way to achieve this is to call a message bus method that has ++ * no arguments and wait for it to return: because the message bus processes ++ * messages in-order, anything we sent before this must have been processed ++ * by the time this call arrives. */ ++static void ++connection_wait_for_bus (GDBusConnection *conn) ++{ ++ GError *error = NULL; ++ GVariant *call_result; ++ ++ call_result = g_dbus_connection_call_sync (conn, ++ DBUS_SERVICE_DBUS, ++ DBUS_PATH_DBUS, ++ DBUS_INTERFACE_DBUS, ++ "GetId", ++ NULL, /* arguments */ ++ NULL, /* result type */ ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, ++ NULL, ++ &error); ++ g_assert_no_error (error); ++ g_assert_nonnull (call_result); ++ g_variant_unref (call_result); ++} ++ ++/* ++ * Called when the subscriber receives a message from any connection ++ * announcing that it has emitted all the signals that it plans to emit. ++ */ ++static void ++subscriber_finished_cb (GDBusConnection *conn, ++ const char *sender_name, ++ const char *path, ++ const char *iface, ++ const char *member, ++ GVariant *parameters, ++ void *user_data) ++{ ++ Fixture *f = user_data; ++ GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER]; ++ guint i; ++ ++ g_assert_true (conn == subscriber); ++ ++ for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++) ++ { ++ if (g_str_equal (sender_name, f->unique_names[i])) ++ { ++ g_assert_false (f->finished[i]); ++ f->finished[i] = TRUE; ++ ++ g_test_message ("Received Finished signal from %s %s", ++ test_conn_descriptions[i], sender_name); ++ return; ++ } ++ } ++ ++ g_error ("Received Finished signal from unknown sender %s", sender_name); ++} ++ ++/* ++ * Called when we receive a signal, either via the GDBusProxy (proxy != NULL) ++ * or via the GDBusConnection (proxy == NULL). ++ */ ++static void ++fixture_received_signal (Fixture *f, ++ GDBusProxy *proxy, ++ const char *sender_name, ++ const char *path, ++ const char *iface, ++ const char *member, ++ GVariant *parameters) ++{ ++ guint i; ++ ReceivedMessage *received; ++ ++ /* Ignore the Finished signal if it matches a wildcard subscription */ ++ if (g_str_equal (member, FINISHED_SIGNAL)) ++ return; ++ ++ received = g_new0 (ReceivedMessage, 1); ++ ++ if (proxy != NULL) ++ received->received_by_proxy = g_object_ref (proxy); ++ else ++ received->received_by_proxy = NULL; ++ ++ received->path = g_strdup (path); ++ received->iface = g_strdup (iface); ++ received->member = g_strdup (member); ++ received->parameters = g_variant_ref (parameters); ++ ++ for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++) ++ { ++ if (g_str_equal (sender_name, f->unique_names[i])) ++ { ++ received->sender = i; ++ g_assert_false (f->finished[i]); ++ break; ++ } ++ } ++ ++ g_assert_cmpint (received->sender, !=, TEST_CONN_NONE); ++ ++ g_test_message ("Signal received from %s %s via %s", ++ test_conn_descriptions[received->sender], ++ sender_name, ++ proxy != NULL ? "proxy" : "connection"); ++ g_test_message ("\tPath: %s", path); ++ g_test_message ("\tInterface: %s", iface); ++ g_test_message ("\tMember: %s", member); ++ ++ if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(su)"))) ++ { ++ g_variant_get (parameters, "(su)", &received->arg0, &received->step); ++ g_test_message ("\tString argument 0: %s", received->arg0); ++ g_test_message ("\tSent in step: %u", received->step); ++ } ++ else ++ { ++ g_assert_cmpstr (g_variant_get_type_string (parameters), ==, "(uu)"); ++ g_variant_get (parameters, "(uu)", NULL, &received->step); ++ g_test_message ("\tArgument 0: (not a string)"); ++ g_test_message ("\tSent in step: %u", received->step); ++ } ++ ++ g_ptr_array_add (f->received, g_steal_pointer (&received)); ++} ++ ++static void ++proxy_signal_cb (GDBusProxy *proxy, ++ const char *sender_name, ++ const char *member, ++ GVariant *parameters, ++ void *user_data) ++{ ++ Fixture *f = user_data; ++ ++ fixture_received_signal (f, proxy, sender_name, ++ g_dbus_proxy_get_object_path (proxy), ++ g_dbus_proxy_get_interface_name (proxy), ++ member, parameters); ++} ++ ++static void ++subscribed_signal_cb (GDBusConnection *conn, ++ const char *sender_name, ++ const char *path, ++ const char *iface, ++ const char *member, ++ GVariant *parameters, ++ void *user_data) ++{ ++ Fixture *f = user_data; ++ GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER]; ++ ++ g_assert_true (conn == subscriber); ++ ++ fixture_received_signal (f, NULL, sender_name, path, iface, member, parameters); ++} ++ ++static void ++fixture_subscribe (Fixture *f, ++ const TestSubscribe *subscribe, ++ guint step_number) ++{ ++ GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER]; ++ const char *sender; ++ ++ if (subscribe->sender != TEST_CONN_NONE) ++ { ++ sender = f->unique_names[subscribe->sender]; ++ g_test_message ("\tSender: %s %s", ++ test_conn_descriptions[subscribe->sender], ++ sender); ++ } ++ else ++ { ++ sender = NULL; ++ g_test_message ("\tSender: (any)"); ++ } ++ ++ g_test_message ("\tPath: %s", nonnull (subscribe->path, "(any)")); ++ g_test_message ("\tInterface: %s", ++ nonnull (subscribe->iface, "(any)")); ++ g_test_message ("\tMember: %s", ++ nonnull (subscribe->member, "(any)")); ++ g_test_message ("\tString argument 0: %s", ++ nonnull (subscribe->arg0, "(any)")); ++ g_test_message ("\tFlags: %x", subscribe->flags); ++ ++ if (f->mode != SUBSCRIPTION_MODE_PROXY) ++ { ++ /* CONN or PARALLEL */ ++ guint id; ++ ++ g_test_message ("\tSubscribing via connection"); ++ id = g_dbus_connection_signal_subscribe (subscriber, ++ sender, ++ subscribe->iface, ++ subscribe->member, ++ subscribe->path, ++ subscribe->arg0, ++ subscribe->flags, ++ subscribed_signal_cb, ++ f, NULL); ++ g_assert_cmpuint (id, !=, 0); ++ f->subscriptions[step_number] = id; ++ } ++ ++ if (f->mode != SUBSCRIPTION_MODE_CONN) ++ { ++ /* PROXY or PARALLEL */ ++ ++ if (sender == NULL) ++ { ++ g_test_message ("\tCannot subscribe via proxy: no bus name"); ++ } ++ else if (subscribe->path == NULL) ++ { ++ g_test_message ("\tCannot subscribe via proxy: no path"); ++ } ++ else if (subscribe->iface == NULL) ++ { ++ g_test_message ("\tCannot subscribe via proxy: no interface"); ++ } ++ else ++ { ++ GDBusProxy *proxy; ++ ++ g_test_message ("\tSubscribing via proxy"); ++ proxy = g_dbus_proxy_new_sync (subscriber, ++ (G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES ++ | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START), ++ NULL, /* GDBusInterfaceInfo */ ++ sender, ++ subscribe->path, ++ subscribe->iface, ++ NULL, /* GCancellable */ ++ &f->error); ++ g_assert_no_error (f->error); ++ g_assert_nonnull (proxy); ++ g_signal_connect (proxy, "g-signal", G_CALLBACK (proxy_signal_cb), f); ++ g_ptr_array_add (f->proxies, g_steal_pointer (&proxy)); ++ } ++ } ++ ++ /* As in setup(), we need to wait for AddMatch to happen. */ ++ g_test_message ("Waiting for AddMatch to be processed"); ++ connection_wait_for_bus (subscriber); ++} ++ ++static void ++fixture_emit_signal (Fixture *f, ++ const TestEmitSignal *signal, ++ guint step_number) ++{ ++ GVariant *body; ++ const char *destination; ++ gboolean ok; ++ ++ g_test_message ("\tSender: %s", ++ test_conn_descriptions[signal->sender]); ++ ++ if (signal->unicast_to != TEST_CONN_NONE) ++ { ++ destination = f->unique_names[signal->unicast_to]; ++ g_test_message ("\tDestination: %s %s", ++ test_conn_descriptions[signal->unicast_to], ++ destination); ++ } ++ else ++ { ++ destination = NULL; ++ g_test_message ("\tDestination: (broadcast)"); ++ } ++ ++ g_assert_nonnull (signal->path); ++ g_test_message ("\tPath: %s", signal->path); ++ g_assert_nonnull (signal->iface); ++ g_test_message ("\tInterface: %s", signal->iface); ++ g_assert_nonnull (signal->member); ++ g_test_message ("\tMember: %s", signal->member); ++ ++ /* If arg0 is non-NULL, put it in the message's argument 0. ++ * Otherwise put something that will not match any arg0. ++ * Either way, put the sequence number in argument 1 so we can ++ * correlate sent messages with received messages later. */ ++ if (signal->arg0 != NULL) ++ { ++ g_test_message ("\tString argument 0: %s", signal->arg0); ++ /* floating */ ++ body = g_variant_new ("(su)", signal->arg0, (guint32) step_number); ++ } ++ else ++ { ++ g_test_message ("\tArgument 0: (not a string)"); ++ body = g_variant_new ("(uu)", (guint32) 0, (guint32) step_number); ++ } ++ ++ ok = g_dbus_connection_emit_signal (f->conns[signal->sender], ++ destination, ++ signal->path, ++ signal->iface, ++ signal->member, ++ /* steals floating reference */ ++ g_steal_pointer (&body), ++ &f->error); ++ g_assert_no_error (f->error); ++ g_assert_true (ok); ++ ++ /* Emitting the signal is asynchronous, so if we want subsequent steps ++ * to be guaranteed to happen after the signal from the message bus's ++ * perspective, we have to do a round-trip to the message bus to sync up. */ ++ g_test_message ("Waiting for signal to reach message bus"); ++ connection_wait_for_bus (f->conns[signal->sender]); ++} ++ ++static void ++fixture_run_plan (Fixture *f, ++ const TestPlan *plan, ++ SubscriptionMode mode) ++{ ++ guint i; ++ ++ G_STATIC_ASSERT (G_N_ELEMENTS (plan->steps) == G_N_ELEMENTS (f->subscriptions)); ++ G_STATIC_ASSERT (G_N_ELEMENTS (plan->steps) == G_N_ELEMENTS (f->received_by_conn)); ++ G_STATIC_ASSERT (G_N_ELEMENTS (plan->steps) == G_N_ELEMENTS (f->received_by_proxy)); ++ ++ f->mode = mode; ++ f->plan = plan; ++ ++ g_test_summary (plan->description); ++ ++ for (i = 0; i < G_N_ELEMENTS (plan->steps); i++) ++ { ++ const TestStep *step = &plan->steps[i]; ++ ++ switch (step->action) ++ { ++ case TEST_ACTION_SUBSCRIBE: ++ g_test_message ("Step %u: adding subscription", i); ++ fixture_subscribe (f, &step->u.subscribe, i); ++ break; ++ ++ case TEST_ACTION_EMIT_SIGNAL: ++ g_test_message ("Step %u: emitting signal", i); ++ fixture_emit_signal (f, &step->u.signal, i); ++ break; ++ ++ case TEST_ACTION_NONE: ++ /* Padding to fill the rest of the array, do nothing */ ++ break; ++ ++ default: ++ g_return_if_reached (); ++ } ++ } ++ ++ /* Now that we have done everything we wanted to do, emit Finished ++ * from each connection. */ ++ for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++) ++ { ++ gboolean ok; ++ ++ ok = g_dbus_connection_emit_signal (f->conns[i], ++ NULL, ++ FINISHED_PATH, ++ FINISHED_INTERFACE, ++ FINISHED_SIGNAL, ++ NULL, ++ &f->error); ++ g_assert_no_error (f->error); ++ g_assert_true (ok); ++ } ++ ++ /* Wait until we have seen the Finished signal from each sender */ ++ while (TRUE) ++ { ++ gboolean all_finished = TRUE; ++ ++ for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++) ++ all_finished = all_finished && f->finished[i]; ++ ++ if (all_finished) ++ break; ++ ++ g_main_context_iteration (NULL, TRUE); ++ } ++ ++ /* Assert that the correct things happened before each Finished signal */ ++ for (i = 0; i < f->received->len; i++) ++ { ++ const ReceivedMessage *received = g_ptr_array_index (f->received, i); ++ ++ g_assert_cmpuint (received->step, <, G_N_ELEMENTS (f->received_by_conn)); ++ g_assert_cmpuint (received->step, <, G_N_ELEMENTS (f->received_by_proxy)); ++ g_assert_cmpint (plan->steps[received->step].action, ++ ==, TEST_ACTION_EMIT_SIGNAL); ++ ++ if (received->received_by_proxy != NULL) ++ f->received_by_proxy[received->step] += 1; ++ else ++ f->received_by_conn[received->step] += 1; ++ } ++ ++ for (i = 0; i < G_N_ELEMENTS (plan->steps); i++) ++ { ++ const TestStep *step = &plan->steps[i]; ++ ++ if (step->action == TEST_ACTION_EMIT_SIGNAL) ++ { ++ const TestEmitSignal *signal = &plan->steps[i].u.signal; ++ ++ if (mode != SUBSCRIPTION_MODE_PROXY) ++ { ++ g_test_message ("Signal from step %u was received %u times by " ++ "GDBusConnection, expected %u", ++ i, f->received_by_conn[i], signal->received_by_conn); ++ g_assert_cmpuint (f->received_by_conn[i], ==, signal->received_by_conn); ++ } ++ else ++ { ++ g_assert_cmpuint (f->received_by_conn[i], ==, 0); ++ } ++ ++ if (mode != SUBSCRIPTION_MODE_CONN) ++ { ++ g_test_message ("Signal from step %u was received %u times by " ++ "GDBusProxy, expected %u", ++ i, f->received_by_proxy[i], signal->received_by_proxy); ++ g_assert_cmpuint (f->received_by_proxy[i], ==, signal->received_by_proxy); ++ } ++ else ++ { ++ g_assert_cmpuint (f->received_by_proxy[i], ==, 0); ++ } ++ } ++ } ++} ++ ++static void ++setup (Fixture *f, ++ G_GNUC_UNUSED const void *context) ++{ ++ GDBusConnection *subscriber; ++ guint i; ++ ++ session_bus_up (); ++ ++ f->proxies = g_ptr_array_new_full (MAX_TEST_STEPS, g_object_unref); ++ f->received = g_ptr_array_new_full (MAX_TEST_STEPS, ++ (GDestroyNotify) received_message_free); ++ ++ for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++) ++ { ++ f->conns[i] = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, &f->error); ++ g_assert_no_error (f->error); ++ g_assert_nonnull (f->conns[i]); ++ ++ f->unique_names[i] = g_dbus_connection_get_unique_name (f->conns[i]); ++ g_assert_nonnull (f->unique_names[i]); ++ g_test_message ("%s is %s", ++ test_conn_descriptions[i], ++ f->unique_names[i]); ++ } ++ ++ subscriber = f->conns[TEST_CONN_SUBSCRIBER]; ++ ++ /* Used to wait for all connections to finish sending whatever they ++ * wanted to send */ ++ f->finished_subscription = g_dbus_connection_signal_subscribe (subscriber, ++ NULL, ++ FINISHED_INTERFACE, ++ FINISHED_SIGNAL, ++ FINISHED_PATH, ++ NULL, ++ G_DBUS_SIGNAL_FLAGS_NONE, ++ subscriber_finished_cb, ++ f, NULL); ++ /* AddMatch is sent asynchronously, so we don't know how ++ * soon it will be processed. Before emitting signals, we ++ * need to wait for the message bus to get as far as processing ++ * AddMatch. */ ++ g_test_message ("Waiting for AddMatch to be processed"); ++ connection_wait_for_bus (subscriber); ++} ++ ++static void ++test_conn_subscribe (Fixture *f, ++ const void *context) ++{ ++ fixture_run_plan (f, context, SUBSCRIPTION_MODE_CONN); ++} ++ ++static void ++test_proxy_subscribe (Fixture *f, ++ const void *context) ++{ ++ fixture_run_plan (f, context, SUBSCRIPTION_MODE_PROXY); ++} ++ ++static void ++test_parallel_subscribe (Fixture *f, ++ const void *context) ++{ ++ fixture_run_plan (f, context, SUBSCRIPTION_MODE_PARALLEL); ++} ++ ++static void ++teardown (Fixture *f, ++ G_GNUC_UNUSED const void *context) ++{ ++ GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER]; ++ guint i; ++ ++ g_ptr_array_unref (f->proxies); ++ ++ if (f->finished_subscription != 0) ++ g_dbus_connection_signal_unsubscribe (subscriber, f->finished_subscription); ++ ++ for (i = 0; i < G_N_ELEMENTS (f->subscriptions); i++) ++ { ++ if (f->subscriptions[i] != 0) ++ g_dbus_connection_signal_unsubscribe (subscriber, f->subscriptions[i]); ++ } ++ ++ g_ptr_array_unref (f->received); ++ ++ for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++) ++ g_clear_object (&f->conns[i]); ++ ++ g_clear_error (&f->error); ++ ++ session_bus_down (); ++} ++ ++int ++main (int argc, ++ char *argv[]) ++{ ++ g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); ++ ++ g_test_dbus_unset (); ++ ++#define ADD_SUBSCRIBE_TEST(name) \ ++ do { \ ++ g_test_add ("/gdbus/subscribe/conn/" #name, \ ++ Fixture, &plan_ ## name, \ ++ setup, test_conn_subscribe, teardown); \ ++ g_test_add ("/gdbus/subscribe/proxy/" #name, \ ++ Fixture, &plan_ ## name, \ ++ setup, test_proxy_subscribe, teardown); \ ++ g_test_add ("/gdbus/subscribe/parallel/" #name, \ ++ Fixture, &plan_ ## name, \ ++ setup, test_parallel_subscribe, teardown); \ ++ } while (0) ++ ++ ADD_SUBSCRIBE_TEST (simple); ++ ADD_SUBSCRIBE_TEST (broadcast_from_anyone); ++ ADD_SUBSCRIBE_TEST (match_twice); ++ ADD_SUBSCRIBE_TEST (limit_by_unique_name); ++ ++ return g_test_run(); ++} +--- a/gio/tests/meson.build ++++ b/gio/tests/meson.build +@@ -374,6 +374,7 @@ if host_machine.system() != 'windows' + }, + 'gdbus-proxy-unique-name' : {'extra_sources' : extra_sources}, + 'gdbus-proxy-well-known-name' : {'extra_sources' : extra_sources}, ++ 'gdbus-subscribe' : {'extra_sources' : extra_sources}, + 'gdbus-test-codegen' : { + 'extra_sources' : [extra_sources, gdbus_test_codegen_generated, gdbus_test_codegen_generated_interface_info], + 'c_args' : ['-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_32'], diff --git a/libs/glib2/patches/103-CVE-2024-34397-tests-Add-support-for-subscribing-to-signals-from-a-well-.patch b/libs/glib2/patches/103-CVE-2024-34397-tests-Add-support-for-subscribing-to-signals-from-a-well-.patch new file mode 100644 index 0000000000..bf756007dd --- /dev/null +++ b/libs/glib2/patches/103-CVE-2024-34397-tests-Add-support-for-subscribing-to-signals-from-a-well-.patch @@ -0,0 +1,243 @@ +From: Simon McVittie +Date: Fri, 8 Mar 2024 19:28:15 +0000 +Subject: tests: Add support for subscribing to signals from a well-known name + +Signed-off-by: Simon McVittie +Origin: upstream, https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +--- + gio/tests/gdbus-subscribe.c | 133 +++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 126 insertions(+), 7 deletions(-) + +--- a/gio/tests/gdbus-subscribe.c ++++ b/gio/tests/gdbus-subscribe.c +@@ -7,6 +7,9 @@ + + #include "gdbus-tests.h" + ++/* From the D-Bus Specification */ ++#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 ++ + #define DBUS_SERVICE_DBUS "org.freedesktop.DBus" + #define DBUS_PATH_DBUS "/org/freedesktop/DBus" + #define DBUS_INTERFACE_DBUS DBUS_SERVICE_DBUS +@@ -22,6 +25,9 @@ + #define EXAMPLE_INTERFACE "org.gtk.GDBus.ExampleInterface" + #define FOO_SIGNAL "Foo" + ++#define ALREADY_OWNED_NAME "org.gtk.Test.AlreadyOwned" ++#define OWNED_LATER_NAME "org.gtk.Test.OwnedLater" ++ + /* Log @s in a debug message. */ + static inline const char * + nonnull (const char *s, +@@ -101,7 +107,8 @@ typedef struct + + typedef struct + { +- TestConn sender; ++ const char *string_sender; ++ TestConn unique_sender; + const char *path; + const char *iface; + const char *member; +@@ -109,11 +116,18 @@ typedef struct + GDBusSignalFlags flags; + } TestSubscribe; + ++typedef struct ++{ ++ const char *name; ++ TestConn owner; ++} TestOwnName; ++ + typedef enum + { + TEST_ACTION_NONE = 0, + TEST_ACTION_SUBSCRIBE, + TEST_ACTION_EMIT_SIGNAL, ++ TEST_ACTION_OWN_NAME, + } TestAction; + + typedef struct +@@ -122,6 +136,7 @@ typedef struct + union { + TestEmitSignal signal; + TestSubscribe subscribe; ++ TestOwnName own_name; + } u; + } TestStep; + +@@ -247,7 +262,7 @@ static const TestPlan plan_match_twice = + { + .action = TEST_ACTION_SUBSCRIBE, + .u.subscribe = { +- .sender = TEST_CONN_SERVICE, ++ .unique_sender = TEST_CONN_SERVICE, + .path = EXAMPLE_PATH, + .iface = EXAMPLE_INTERFACE, + }, +@@ -267,7 +282,7 @@ static const TestPlan plan_match_twice = + { + .action = TEST_ACTION_SUBSCRIBE, + .u.subscribe = { +- .sender = TEST_CONN_SERVICE, ++ .unique_sender = TEST_CONN_SERVICE, + .path = EXAMPLE_PATH, + .iface = EXAMPLE_INTERFACE, + }, +@@ -296,7 +311,7 @@ static const TestPlan plan_limit_by_uniq + /* Subscriber wants to receive signals from service */ + .action = TEST_ACTION_SUBSCRIBE, + .u.subscribe = { +- .sender = TEST_CONN_SERVICE, ++ .unique_sender = TEST_CONN_SERVICE, + .path = EXAMPLE_PATH, + .iface = EXAMPLE_INTERFACE, + }, +@@ -343,6 +358,62 @@ static const TestPlan plan_limit_by_uniq + }, + }; + ++static const TestPlan plan_limit_by_well_known_name = ++{ ++ .description = "A subscription via a well-known name only accepts messages " ++ "sent by the owner of that well-known name", ++ .steps = { ++ { ++ /* Service already owns one name */ ++ .action = TEST_ACTION_OWN_NAME, ++ .u.own_name = { ++ .name = ALREADY_OWNED_NAME, ++ .owner = TEST_CONN_SERVICE ++ }, ++ }, ++ { ++ /* Subscriber wants to receive signals from service */ ++ .action = TEST_ACTION_SUBSCRIBE, ++ .u.subscribe = { ++ .string_sender = ALREADY_OWNED_NAME, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ }, ++ }, ++ { ++ /* Subscriber wants to receive signals from service by another name */ ++ .action = TEST_ACTION_SUBSCRIBE, ++ .u.subscribe = { ++ .string_sender = OWNED_LATER_NAME, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ }, ++ }, ++ { ++ /* Service claims another name */ ++ .action = TEST_ACTION_OWN_NAME, ++ .u.own_name = { ++ .name = OWNED_LATER_NAME, ++ .owner = TEST_CONN_SERVICE ++ }, ++ }, ++ { ++ /* Now the subscriber gets this signal twice, once for each ++ * subscription; and similarly each of the two proxies gets this ++ * signal twice */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_SERVICE, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 2, ++ .received_by_proxy = 2 ++ }, ++ }, ++ }, ++}; ++ + typedef struct + { + const TestPlan *plan; +@@ -540,11 +611,16 @@ fixture_subscribe (Fixture * + GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER]; + const char *sender; + +- if (subscribe->sender != TEST_CONN_NONE) ++ if (subscribe->string_sender != NULL) ++ { ++ sender = subscribe->string_sender; ++ g_test_message ("\tSender: %s", sender); ++ } ++ else if (subscribe->unique_sender != TEST_CONN_NONE) + { +- sender = f->unique_names[subscribe->sender]; ++ sender = f->unique_names[subscribe->unique_sender]; + g_test_message ("\tSender: %s %s", +- test_conn_descriptions[subscribe->sender], ++ test_conn_descriptions[subscribe->unique_sender], + sender); + } + else +@@ -690,6 +766,43 @@ fixture_emit_signal (Fixture + } + + static void ++fixture_own_name (Fixture *f, ++ const TestOwnName *own_name) ++{ ++ GVariant *call_result; ++ guint32 flags; ++ guint32 result_code; ++ ++ g_test_message ("\tName: %s", own_name->name); ++ g_test_message ("\tOwner: %s", ++ test_conn_descriptions[own_name->owner]); ++ ++ /* For simplicity, we do this via a direct bus call rather than ++ * using g_bus_own_name_on_connection(). The flags in ++ * GBusNameOwnerFlags are numerically equal to those in the ++ * D-Bus wire protocol. */ ++ flags = G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE; ++ call_result = g_dbus_connection_call_sync (f->conns[own_name->owner], ++ DBUS_SERVICE_DBUS, ++ DBUS_PATH_DBUS, ++ DBUS_INTERFACE_DBUS, ++ "RequestName", ++ g_variant_new ("(su)", ++ own_name->name, ++ flags), ++ G_VARIANT_TYPE ("(u)"), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, ++ NULL, ++ &f->error); ++ g_assert_no_error (f->error); ++ g_assert_nonnull (call_result); ++ g_variant_get (call_result, "(u)", &result_code); ++ g_assert_cmpuint (result_code, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); ++ g_variant_unref (call_result); ++} ++ ++static void + fixture_run_plan (Fixture *f, + const TestPlan *plan, + SubscriptionMode mode) +@@ -721,6 +834,11 @@ fixture_run_plan (Fixture *f, + fixture_emit_signal (f, &step->u.signal, i); + break; + ++ case TEST_ACTION_OWN_NAME: ++ g_test_message ("Step %u: claiming bus name", i); ++ fixture_own_name (f, &step->u.own_name); ++ break; ++ + case TEST_ACTION_NONE: + /* Padding to fill the rest of the array, do nothing */ + break; +@@ -933,6 +1051,7 @@ main (int argc, + ADD_SUBSCRIBE_TEST (broadcast_from_anyone); + ADD_SUBSCRIBE_TEST (match_twice); + ADD_SUBSCRIBE_TEST (limit_by_unique_name); ++ ADD_SUBSCRIBE_TEST (limit_by_well_known_name); + + return g_test_run(); + } diff --git a/libs/glib2/patches/104-CVE-2024-34397-tests-Add-a-test-case-for-what-happens-if-a-unique-name-d.patch b/libs/glib2/patches/104-CVE-2024-34397-tests-Add-a-test-case-for-what-happens-if-a-unique-name-d.patch new file mode 100644 index 0000000000..5f8c552785 --- /dev/null +++ b/libs/glib2/patches/104-CVE-2024-34397-tests-Add-a-test-case-for-what-happens-if-a-unique-name-d.patch @@ -0,0 +1,79 @@ +From: Simon McVittie +Date: Fri, 8 Mar 2024 19:44:03 +0000 +Subject: tests: Add a test-case for what happens if a unique name doesn't + exist + +On GNOME/glib#3268 there was some concern about whether this would +allow an attacker to send signals and have them be matched to a +GDBusProxy in this situation, but it seems that was a false alarm. + +Signed-off-by: Simon McVittie +Origin: upstream, https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +--- + gio/tests/gdbus-subscribe.c | 48 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 48 insertions(+) + +--- a/gio/tests/gdbus-subscribe.c ++++ b/gio/tests/gdbus-subscribe.c +@@ -358,6 +358,53 @@ static const TestPlan plan_limit_by_uniq + }, + }; + ++static const TestPlan plan_nonexistent_unique_name = ++{ ++ .description = "A subscription via a unique name that doesn't exist " ++ "accepts no messages", ++ .steps = { ++ { ++ /* Subscriber wants to receive signals from service */ ++ .action = TEST_ACTION_SUBSCRIBE, ++ .u.subscribe = { ++ /* This relies on the implementation detail that the dbus-daemon ++ * (and presumably other bus implementations) never actually generates ++ * a unique name in this format */ ++ .string_sender = ":0.this.had.better.not.exist", ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ }, ++ }, ++ { ++ /* Attacker wants to trick subscriber into thinking that service ++ * sent a signal */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_ATTACKER, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 0, ++ .received_by_proxy = 0 ++ }, ++ }, ++ { ++ /* Attacker tries harder, by sending a signal unicast directly to ++ * the subscriber */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_ATTACKER, ++ .unicast_to = TEST_CONN_SUBSCRIBER, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 0, ++ .received_by_proxy = 0 ++ }, ++ }, ++ }, ++}; ++ + static const TestPlan plan_limit_by_well_known_name = + { + .description = "A subscription via a well-known name only accepts messages " +@@ -1051,6 +1098,7 @@ main (int argc, + ADD_SUBSCRIBE_TEST (broadcast_from_anyone); + ADD_SUBSCRIBE_TEST (match_twice); + ADD_SUBSCRIBE_TEST (limit_by_unique_name); ++ ADD_SUBSCRIBE_TEST (nonexistent_unique_name); + ADD_SUBSCRIBE_TEST (limit_by_well_known_name); + + return g_test_run(); diff --git a/libs/glib2/patches/105-CVE-2024-34397-tests-Add-test-coverage-for-signals-that-match-the-messag.patch b/libs/glib2/patches/105-CVE-2024-34397-tests-Add-test-coverage-for-signals-that-match-the-messag.patch new file mode 100644 index 0000000000..a5582b7df5 --- /dev/null +++ b/libs/glib2/patches/105-CVE-2024-34397-tests-Add-test-coverage-for-signals-that-match-the-messag.patch @@ -0,0 +1,254 @@ +From: Simon McVittie +Date: Fri, 8 Mar 2024 20:10:29 +0000 +Subject: tests: Add test coverage for signals that match the message bus's + name + +This is a special case of unique names, even though it's syntactically +a well-known name. + +Signed-off-by: Simon McVittie +Origin: upstream, https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +--- + gio/tests/gdbus-subscribe.c | 161 ++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 154 insertions(+), 7 deletions(-) + +--- a/gio/tests/gdbus-subscribe.c ++++ b/gio/tests/gdbus-subscribe.c +@@ -13,6 +13,7 @@ + #define DBUS_SERVICE_DBUS "org.freedesktop.DBus" + #define DBUS_PATH_DBUS "/org/freedesktop/DBus" + #define DBUS_INTERFACE_DBUS DBUS_SERVICE_DBUS ++#define NAME_OWNER_CHANGED "NameOwnerChanged" + + /* A signal that each connection emits to indicate that it has finished + * emitting other signals */ +@@ -101,6 +102,7 @@ typedef struct + const char *iface; + const char *member; + const char *arg0; ++ const char *args; + guint received_by_conn; + guint received_by_proxy; + } TestEmitSignal; +@@ -120,6 +122,8 @@ typedef struct + { + const char *name; + TestConn owner; ++ guint received_by_conn; ++ guint received_by_proxy; + } TestOwnName; + + typedef enum +@@ -461,6 +465,63 @@ static const TestPlan plan_limit_by_well + }, + }; + ++static const TestPlan plan_limit_to_message_bus = ++{ ++ .description = "A subscription to the message bus only accepts messages " ++ "from the message bus", ++ .steps = { ++ { ++ /* Subscriber wants to receive signals from the message bus itself */ ++ .action = TEST_ACTION_SUBSCRIBE, ++ .u.subscribe = { ++ .string_sender = DBUS_SERVICE_DBUS, ++ .path = DBUS_PATH_DBUS, ++ .iface = DBUS_INTERFACE_DBUS, ++ }, ++ }, ++ { ++ /* Attacker wants to trick subscriber into thinking that the message ++ * bus sent a signal */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_ATTACKER, ++ .path = DBUS_PATH_DBUS, ++ .iface = DBUS_INTERFACE_DBUS, ++ .member = NAME_OWNER_CHANGED, ++ .arg0 = "would I lie to you?", ++ .received_by_conn = 0, ++ .received_by_proxy = 0 ++ }, ++ }, ++ { ++ /* Attacker tries harder, by sending a signal unicast directly to ++ * the subscriber, and using more realistic arguments */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .unicast_to = TEST_CONN_SUBSCRIBER, ++ .sender = TEST_CONN_ATTACKER, ++ .path = DBUS_PATH_DBUS, ++ .iface = DBUS_INTERFACE_DBUS, ++ .member = NAME_OWNER_CHANGED, ++ .args = "('com.example.Name', '', ':1.12')", ++ .received_by_conn = 0, ++ .received_by_proxy = 0 ++ }, ++ }, ++ { ++ /* When the message bus sends a signal (in this case triggered by ++ * owning a name), it should still get through */ ++ .action = TEST_ACTION_OWN_NAME, ++ .u.own_name = { ++ .name = OWNED_LATER_NAME, ++ .owner = TEST_CONN_SERVICE, ++ .received_by_conn = 1, ++ .received_by_proxy = 1 ++ }, ++ }, ++ }, ++}; ++ + typedef struct + { + const TestPlan *plan; +@@ -591,7 +652,18 @@ fixture_received_signal (Fixture *f, + } + } + +- g_assert_cmpint (received->sender, !=, TEST_CONN_NONE); ++ if (g_str_equal (sender_name, DBUS_SERVICE_DBUS)) ++ { ++ g_test_message ("Signal received from message bus %s", ++ sender_name); ++ } ++ else ++ { ++ g_test_message ("Signal received from %s %s", ++ test_conn_descriptions[received->sender], ++ sender_name); ++ g_assert_cmpint (received->sender, !=, TEST_CONN_NONE); ++ } + + g_test_message ("Signal received from %s %s via %s", + test_conn_descriptions[received->sender], +@@ -607,13 +679,56 @@ fixture_received_signal (Fixture *f, + g_test_message ("\tString argument 0: %s", received->arg0); + g_test_message ("\tSent in step: %u", received->step); + } +- else ++ else if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(uu)"))) + { +- g_assert_cmpstr (g_variant_get_type_string (parameters), ==, "(uu)"); + g_variant_get (parameters, "(uu)", NULL, &received->step); + g_test_message ("\tArgument 0: (not a string)"); + g_test_message ("\tSent in step: %u", received->step); + } ++ else if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sss)"))) ++ { ++ const char *name; ++ const char *old_owner; ++ const char *new_owner; ++ ++ /* The only signal of this signature that we legitimately receive ++ * during this test is NameOwnerChanged, so just assert that it ++ * is from the message bus and can be matched to a plausible step. ++ * (This is less thorough than the above, and will not work if we ++ * add a test scenario where a name's ownership is repeatedly ++ * changed while watching NameOwnerChanged - so don't do that.) */ ++ g_assert_cmpstr (sender_name, ==, DBUS_SERVICE_DBUS); ++ g_assert_cmpstr (path, ==, DBUS_PATH_DBUS); ++ g_assert_cmpstr (iface, ==, DBUS_INTERFACE_DBUS); ++ g_assert_cmpstr (member, ==, NAME_OWNER_CHANGED); ++ ++ g_variant_get (parameters, "(&s&s&s)", &name, &old_owner, &new_owner); ++ ++ for (i = 0; i < G_N_ELEMENTS (f->plan->steps); i++) ++ { ++ const TestStep *step = &f->plan->steps[i]; ++ ++ if (step->action == TEST_ACTION_OWN_NAME) ++ { ++ const TestOwnName *own_name = &step->u.own_name; ++ ++ if (g_str_equal (name, own_name->name) ++ && g_str_equal (new_owner, f->unique_names[own_name->owner]) ++ && own_name->received_by_conn > 0) ++ { ++ received->step = i; ++ break; ++ } ++ } ++ ++ if (i >= G_N_ELEMENTS (f->plan->steps)) ++ g_error ("Could not match message to a test step"); ++ } ++ } ++ else ++ { ++ g_error ("Unexpected message received"); ++ } + + g_ptr_array_add (f->received, g_steal_pointer (&received)); + } +@@ -782,10 +897,15 @@ fixture_emit_signal (Fixture + * Otherwise put something that will not match any arg0. + * Either way, put the sequence number in argument 1 so we can + * correlate sent messages with received messages later. */ +- if (signal->arg0 != NULL) ++ if (signal->args != NULL) + { +- g_test_message ("\tString argument 0: %s", signal->arg0); + /* floating */ ++ body = g_variant_new_parsed (signal->args); ++ g_assert_nonnull (body); ++ } ++ else if (signal->arg0 != NULL) ++ { ++ g_test_message ("\tString argument 0: %s", signal->arg0); + body = g_variant_new ("(su)", signal->arg0, (guint32) step_number); + } + else +@@ -933,8 +1053,6 @@ fixture_run_plan (Fixture *f, + + g_assert_cmpuint (received->step, <, G_N_ELEMENTS (f->received_by_conn)); + g_assert_cmpuint (received->step, <, G_N_ELEMENTS (f->received_by_proxy)); +- g_assert_cmpint (plan->steps[received->step].action, +- ==, TEST_ACTION_EMIT_SIGNAL); + + if (received->received_by_proxy != NULL) + f->received_by_proxy[received->step] += 1; +@@ -974,6 +1092,34 @@ fixture_run_plan (Fixture *f, + g_assert_cmpuint (f->received_by_proxy[i], ==, 0); + } + } ++ else if (step->action == TEST_ACTION_OWN_NAME) ++ { ++ const TestOwnName *own_name = &plan->steps[i].u.own_name; ++ ++ if (mode != SUBSCRIPTION_MODE_PROXY) ++ { ++ g_test_message ("NameOwnerChanged from step %u was received %u " ++ "times by GDBusConnection, expected %u", ++ i, f->received_by_conn[i], own_name->received_by_conn); ++ g_assert_cmpuint (f->received_by_conn[i], ==, own_name->received_by_conn); ++ } ++ else ++ { ++ g_assert_cmpuint (f->received_by_conn[i], ==, 0); ++ } ++ ++ if (mode != SUBSCRIPTION_MODE_CONN) ++ { ++ g_test_message ("NameOwnerChanged from step %u was received %u " ++ "times by GDBusProxy, expected %u", ++ i, f->received_by_proxy[i], own_name->received_by_proxy); ++ g_assert_cmpuint (f->received_by_proxy[i], ==, own_name->received_by_proxy); ++ } ++ else ++ { ++ g_assert_cmpuint (f->received_by_proxy[i], ==, 0); ++ } ++ } + } + } + +@@ -1100,6 +1246,7 @@ main (int argc, + ADD_SUBSCRIBE_TEST (limit_by_unique_name); + ADD_SUBSCRIBE_TEST (nonexistent_unique_name); + ADD_SUBSCRIBE_TEST (limit_by_well_known_name); ++ ADD_SUBSCRIBE_TEST (limit_to_message_bus); + + return g_test_run(); + } diff --git a/libs/glib2/patches/106-CVE-2024-34397-gdbusprivate-Add-symbolic-constants-for-the-message-bus-i.patch b/libs/glib2/patches/106-CVE-2024-34397-gdbusprivate-Add-symbolic-constants-for-the-message-bus-i.patch new file mode 100644 index 0000000000..265cb9c82e --- /dev/null +++ b/libs/glib2/patches/106-CVE-2024-34397-gdbusprivate-Add-symbolic-constants-for-the-message-bus-i.patch @@ -0,0 +1,35 @@ +From: Simon McVittie +Date: Thu, 14 Mar 2024 19:18:15 +0000 +Subject: gdbusprivate: Add symbolic constants for the message bus itself + +Using these is a bit more clearly correct than repeating them everywhere. +To avoid excessive diffstat in a branch for a bug fix, I'm not +immediately replacing all existing occurrences of the same literals with +these names. + +The names of these constants are chosen to be consistent with libdbus, +despite using somewhat outdated terminology (D-Bus now uses the term +"well-known bus name" for what used to be called a service name, +reserving the word "service" to mean specifically the programs that +have .service files and participate in service activation). + +Signed-off-by: Simon McVittie +Origin: upstream, https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +--- + gio/gdbusprivate.h | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/gio/gdbusprivate.h ++++ b/gio/gdbusprivate.h +@@ -31,6 +31,11 @@ + + G_BEGIN_DECLS + ++/* Bus name, interface and object path of the message bus itself */ ++#define DBUS_SERVICE_DBUS "org.freedesktop.DBus" ++#define DBUS_INTERFACE_DBUS DBUS_SERVICE_DBUS ++#define DBUS_PATH_DBUS "/org/freedesktop/DBus" ++ + /* ---------------------------------------------------------------------------------------------------- */ + + typedef struct GDBusWorker GDBusWorker; diff --git a/libs/glib2/patches/107-CVE-2024-34397-gdbusconnection-Move-SignalData-SignalSubscriber-higher-u.patch b/libs/glib2/patches/107-CVE-2024-34397-gdbusconnection-Move-SignalData-SignalSubscriber-higher-u.patch new file mode 100644 index 0000000000..c498428202 --- /dev/null +++ b/libs/glib2/patches/107-CVE-2024-34397-gdbusconnection-Move-SignalData-SignalSubscriber-higher-u.patch @@ -0,0 +1,158 @@ +From: Simon McVittie +Date: Thu, 14 Mar 2024 19:24:24 +0000 +Subject: gdbusconnection: Move SignalData, SignalSubscriber higher up + +Subsequent changes will need to access these data structures from +on_worker_message_received(). No functional change here, only moving +code around. + +Signed-off-by: Simon McVittie +Origin: upstream, https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +--- + gio/gdbusconnection.c | 128 +++++++++++++++++++++++++------------------------- + 1 file changed, 65 insertions(+), 63 deletions(-) + +--- a/gio/gdbusconnection.c ++++ b/gio/gdbusconnection.c +@@ -285,6 +285,71 @@ call_destroy_notify (GMainContext *cont + + /* ---------------------------------------------------------------------------------------------------- */ + ++typedef struct ++{ ++ /* All fields are immutable after construction. */ ++ gatomicrefcount ref_count; ++ GDBusSignalCallback callback; ++ gpointer user_data; ++ GDestroyNotify user_data_free_func; ++ guint id; ++ GMainContext *context; ++} SignalSubscriber; ++ ++static SignalSubscriber * ++signal_subscriber_ref (SignalSubscriber *subscriber) ++{ ++ g_atomic_ref_count_inc (&subscriber->ref_count); ++ return subscriber; ++} ++ ++static void ++signal_subscriber_unref (SignalSubscriber *subscriber) ++{ ++ if (g_atomic_ref_count_dec (&subscriber->ref_count)) ++ { ++ /* Destroy the user data. It doesn’t matter which thread ++ * signal_subscriber_unref() is called in (or whether it’s called with a ++ * lock held), as call_destroy_notify() always defers to the next ++ * #GMainContext iteration. */ ++ call_destroy_notify (subscriber->context, ++ subscriber->user_data_free_func, ++ subscriber->user_data); ++ ++ g_main_context_unref (subscriber->context); ++ g_free (subscriber); ++ } ++} ++ ++typedef struct ++{ ++ gchar *rule; ++ gchar *sender; ++ gchar *sender_unique_name; /* if sender is unique or org.freedesktop.DBus, then that name... otherwise blank */ ++ gchar *interface_name; ++ gchar *member; ++ gchar *object_path; ++ gchar *arg0; ++ GDBusSignalFlags flags; ++ GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */ ++} SignalData; ++ ++static void ++signal_data_free (SignalData *signal_data) ++{ ++ g_free (signal_data->rule); ++ g_free (signal_data->sender); ++ g_free (signal_data->sender_unique_name); ++ g_free (signal_data->interface_name); ++ g_free (signal_data->member); ++ g_free (signal_data->object_path); ++ g_free (signal_data->arg0); ++ g_ptr_array_unref (signal_data->subscribers); ++ g_free (signal_data); ++} ++ ++/* ---------------------------------------------------------------------------------------------------- */ ++ + #ifdef G_OS_WIN32 + #define CONNECTION_ENSURE_LOCK(obj) do { ; } while (FALSE) + #else +@@ -3241,69 +3306,6 @@ g_dbus_connection_remove_filter (GDBusCo + + /* ---------------------------------------------------------------------------------------------------- */ + +-typedef struct +-{ +- gchar *rule; +- gchar *sender; +- gchar *sender_unique_name; /* if sender is unique or org.freedesktop.DBus, then that name... otherwise blank */ +- gchar *interface_name; +- gchar *member; +- gchar *object_path; +- gchar *arg0; +- GDBusSignalFlags flags; +- GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */ +-} SignalData; +- +-static void +-signal_data_free (SignalData *signal_data) +-{ +- g_free (signal_data->rule); +- g_free (signal_data->sender); +- g_free (signal_data->sender_unique_name); +- g_free (signal_data->interface_name); +- g_free (signal_data->member); +- g_free (signal_data->object_path); +- g_free (signal_data->arg0); +- g_ptr_array_unref (signal_data->subscribers); +- g_free (signal_data); +-} +- +-typedef struct +-{ +- /* All fields are immutable after construction. */ +- gatomicrefcount ref_count; +- GDBusSignalCallback callback; +- gpointer user_data; +- GDestroyNotify user_data_free_func; +- guint id; +- GMainContext *context; +-} SignalSubscriber; +- +-static SignalSubscriber * +-signal_subscriber_ref (SignalSubscriber *subscriber) +-{ +- g_atomic_ref_count_inc (&subscriber->ref_count); +- return subscriber; +-} +- +-static void +-signal_subscriber_unref (SignalSubscriber *subscriber) +-{ +- if (g_atomic_ref_count_dec (&subscriber->ref_count)) +- { +- /* Destroy the user data. It doesn’t matter which thread +- * signal_subscriber_unref() is called in (or whether it’s called with a +- * lock held), as call_destroy_notify() always defers to the next +- * #GMainContext iteration. */ +- call_destroy_notify (subscriber->context, +- subscriber->user_data_free_func, +- subscriber->user_data); +- +- g_main_context_unref (subscriber->context); +- g_free (subscriber); +- } +-} +- + static gchar * + args_to_rule (const gchar *sender, + const gchar *interface_name, diff --git a/libs/glib2/patches/108-CVE-2024-34397-gdbusconnection-Factor-out-signal_data_new_take.patch b/libs/glib2/patches/108-CVE-2024-34397-gdbusconnection-Factor-out-signal_data_new_take.patch new file mode 100644 index 0000000000..ed33ad00e7 --- /dev/null +++ b/libs/glib2/patches/108-CVE-2024-34397-gdbusconnection-Factor-out-signal_data_new_take.patch @@ -0,0 +1,72 @@ +From: Simon McVittie +Date: Thu, 14 Mar 2024 19:30:12 +0000 +Subject: gdbusconnection: Factor out signal_data_new_take() + +No functional changes, except that the implicit ownership-transfer +for the rule field becomes explicit (the local variable is set to NULL +afterwards). + +Signed-off-by: Simon McVittie +Origin: upstream, https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +--- + gio/gdbusconnection.c | 42 ++++++++++++++++++++++++++++++++---------- + 1 file changed, 32 insertions(+), 10 deletions(-) + +--- a/gio/gdbusconnection.c ++++ b/gio/gdbusconnection.c +@@ -334,6 +334,30 @@ typedef struct + GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */ + } SignalData; + ++static SignalData * ++signal_data_new_take (gchar *rule, ++ gchar *sender, ++ gchar *sender_unique_name, ++ gchar *interface_name, ++ gchar *member, ++ gchar *object_path, ++ gchar *arg0, ++ GDBusSignalFlags flags) ++{ ++ SignalData *signal_data = g_new0 (SignalData, 1); ++ ++ signal_data->rule = rule; ++ signal_data->sender = sender; ++ signal_data->sender_unique_name = sender_unique_name; ++ signal_data->interface_name = interface_name; ++ signal_data->member = member; ++ signal_data->object_path = object_path; ++ signal_data->arg0 = arg0; ++ signal_data->flags = flags; ++ signal_data->subscribers = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref); ++ return g_steal_pointer (&signal_data); ++} ++ + static void + signal_data_free (SignalData *signal_data) + { +@@ -3572,16 +3596,14 @@ g_dbus_connection_signal_subscribe (GDBu + goto out; + } + +- signal_data = g_new0 (SignalData, 1); +- signal_data->rule = rule; +- signal_data->sender = g_strdup (sender); +- signal_data->sender_unique_name = g_strdup (sender_unique_name); +- signal_data->interface_name = g_strdup (interface_name); +- signal_data->member = g_strdup (member); +- signal_data->object_path = g_strdup (object_path); +- signal_data->arg0 = g_strdup (arg0); +- signal_data->flags = flags; +- signal_data->subscribers = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref); ++ signal_data = signal_data_new_take (g_steal_pointer (&rule), ++ g_strdup (sender), ++ g_strdup (sender_unique_name), ++ g_strdup (interface_name), ++ g_strdup (member), ++ g_strdup (object_path), ++ g_strdup (arg0), ++ flags); + g_ptr_array_add (signal_data->subscribers, subscriber); + + g_hash_table_insert (connection->map_rule_to_signal_data, diff --git a/libs/glib2/patches/109-CVE-2024-34397-gdbusconnection-Factor-out-add_signal_data.patch b/libs/glib2/patches/109-CVE-2024-34397-gdbusconnection-Factor-out-add_signal_data.patch new file mode 100644 index 0000000000..e779534b91 --- /dev/null +++ b/libs/glib2/patches/109-CVE-2024-34397-gdbusconnection-Factor-out-add_signal_data.patch @@ -0,0 +1,99 @@ +From: Simon McVittie +Date: Tue, 23 Apr 2024 20:31:57 +0100 +Subject: gdbusconnection: Factor out add_signal_data() + +No functional changes. + +Signed-off-by: Simon McVittie +Origin: upstream, https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +--- + gio/gdbusconnection.c | 64 +++++++++++++++++++++++++++++---------------------- + 1 file changed, 37 insertions(+), 27 deletions(-) + +--- a/gio/gdbusconnection.c ++++ b/gio/gdbusconnection.c +@@ -3450,6 +3450,42 @@ is_signal_data_for_name_lost_or_acquired + + /* ---------------------------------------------------------------------------------------------------- */ + ++/* called in any thread, connection lock is held */ ++static void ++add_signal_data (GDBusConnection *connection, ++ SignalData *signal_data) ++{ ++ GPtrArray *signal_data_array; ++ ++ g_hash_table_insert (connection->map_rule_to_signal_data, ++ signal_data->rule, ++ signal_data); ++ ++ /* Add the match rule to the bus... ++ * ++ * Avoid adding match rules for NameLost and NameAcquired messages - the bus will ++ * always send such messages to us. ++ */ ++ if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) ++ { ++ if (!is_signal_data_for_name_lost_or_acquired (signal_data)) ++ add_match_rule (connection, signal_data->rule); ++ } ++ ++ signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, ++ signal_data->sender_unique_name); ++ if (signal_data_array == NULL) ++ { ++ signal_data_array = g_ptr_array_new (); ++ g_hash_table_insert (connection->map_sender_unique_name_to_signal_data_array, ++ g_strdup (signal_data->sender_unique_name), ++ signal_data_array); ++ } ++ g_ptr_array_add (signal_data_array, signal_data); ++} ++ ++/* ---------------------------------------------------------------------------------------------------- */ ++ + /** + * g_dbus_connection_signal_subscribe: + * @connection: a #GDBusConnection +@@ -3539,7 +3575,6 @@ g_dbus_connection_signal_subscribe (GDBu + gchar *rule; + SignalData *signal_data; + SignalSubscriber *subscriber; +- GPtrArray *signal_data_array; + const gchar *sender_unique_name; + + /* Right now we abort if AddMatch() fails since it can only fail with the bus being in +@@ -3605,32 +3640,7 @@ g_dbus_connection_signal_subscribe (GDBu + g_strdup (arg0), + flags); + g_ptr_array_add (signal_data->subscribers, subscriber); +- +- g_hash_table_insert (connection->map_rule_to_signal_data, +- signal_data->rule, +- signal_data); +- +- /* Add the match rule to the bus... +- * +- * Avoid adding match rules for NameLost and NameAcquired messages - the bus will +- * always send such messages to us. +- */ +- if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) +- { +- if (!is_signal_data_for_name_lost_or_acquired (signal_data)) +- add_match_rule (connection, signal_data->rule); +- } +- +- signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, +- signal_data->sender_unique_name); +- if (signal_data_array == NULL) +- { +- signal_data_array = g_ptr_array_new (); +- g_hash_table_insert (connection->map_sender_unique_name_to_signal_data_array, +- g_strdup (signal_data->sender_unique_name), +- signal_data_array); +- } +- g_ptr_array_add (signal_data_array, signal_data); ++ add_signal_data (connection, signal_data); + + out: + g_hash_table_insert (connection->map_id_to_signal_data, diff --git a/libs/glib2/patches/110-CVE-2024-34397-gdbusconnection-Factor-out-remove_signal_data_if_unused.patch b/libs/glib2/patches/110-CVE-2024-34397-gdbusconnection-Factor-out-remove_signal_data_if_unused.patch new file mode 100644 index 0000000000..f348925f67 --- /dev/null +++ b/libs/glib2/patches/110-CVE-2024-34397-gdbusconnection-Factor-out-remove_signal_data_if_unused.patch @@ -0,0 +1,123 @@ +From: Simon McVittie +Date: Thu, 14 Mar 2024 19:51:59 +0000 +Subject: gdbusconnection: Factor out remove_signal_data_if_unused + +No functional change, just removing some nesting. The check for whether +signal_data->subscribers is empty changes from a conditional that tests +whether it is into an early-return if it isn't. + +A subsequent commit will add additional conditions that make us consider +a SignalData to be still in use and therefore not eligible to be removed. + +Signed-off-by: Simon McVittie +Origin: upstream, https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +--- + gio/gdbusconnection.c | 83 +++++++++++++++++++++++++++++---------------------- + 1 file changed, 48 insertions(+), 35 deletions(-) + +--- a/gio/gdbusconnection.c ++++ b/gio/gdbusconnection.c +@@ -3654,6 +3654,52 @@ g_dbus_connection_signal_subscribe (GDBu + + /* ---------------------------------------------------------------------------------------------------- */ + ++/* ++ * Called in any thread. ++ * Must hold the connection lock when calling this, unless ++ * connection->finalizing is TRUE. ++ * May free signal_data, so do not dereference it after this. ++ */ ++static void ++remove_signal_data_if_unused (GDBusConnection *connection, ++ SignalData *signal_data) ++{ ++ GPtrArray *signal_data_array; ++ ++ if (signal_data->subscribers->len != 0) ++ return; ++ ++ g_warn_if_fail (g_hash_table_remove (connection->map_rule_to_signal_data, signal_data->rule)); ++ ++ signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, ++ signal_data->sender_unique_name); ++ g_warn_if_fail (signal_data_array != NULL); ++ g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data)); ++ ++ if (signal_data_array->len == 0) ++ { ++ g_warn_if_fail (g_hash_table_remove (connection->map_sender_unique_name_to_signal_data_array, ++ signal_data->sender_unique_name)); ++ } ++ ++ /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */ ++ if ((connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) && ++ !is_signal_data_for_name_lost_or_acquired (signal_data) && ++ !g_dbus_connection_is_closed (connection) && ++ !connection->finalizing) ++ { ++ /* The check for g_dbus_connection_is_closed() means that ++ * sending the RemoveMatch message can't fail with ++ * G_IO_ERROR_CLOSED, because we're holding the lock, ++ * so on_worker_closed() can't happen between the check we just ++ * did, and releasing the lock later. ++ */ ++ remove_match_rule (connection, signal_data->rule); ++ } ++ ++ signal_data_free (signal_data); ++} ++ + /* called in any thread */ + /* must hold lock when calling this (except if connection->finalizing is TRUE) + * returns the number of removed subscribers */ +@@ -3662,7 +3708,6 @@ unsubscribe_id_internal (GDBusConnection + guint subscription_id) + { + SignalData *signal_data; +- GPtrArray *signal_data_array; + guint n; + guint n_removed = 0; + +@@ -3689,40 +3734,8 @@ unsubscribe_id_internal (GDBusConnection + GUINT_TO_POINTER (subscription_id))); + n_removed++; + g_ptr_array_remove_index_fast (signal_data->subscribers, n); +- +- if (signal_data->subscribers->len == 0) +- { +- g_warn_if_fail (g_hash_table_remove (connection->map_rule_to_signal_data, signal_data->rule)); +- +- signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, +- signal_data->sender_unique_name); +- g_warn_if_fail (signal_data_array != NULL); +- g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data)); +- +- if (signal_data_array->len == 0) +- { +- g_warn_if_fail (g_hash_table_remove (connection->map_sender_unique_name_to_signal_data_array, +- signal_data->sender_unique_name)); +- } +- +- /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */ +- if ((connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) && +- !is_signal_data_for_name_lost_or_acquired (signal_data) && +- !g_dbus_connection_is_closed (connection) && +- !connection->finalizing) +- { +- /* The check for g_dbus_connection_is_closed() means that +- * sending the RemoveMatch message can't fail with +- * G_IO_ERROR_CLOSED, because we're holding the lock, +- * so on_worker_closed() can't happen between the check we just +- * did, and releasing the lock later. +- */ +- remove_match_rule (connection, signal_data->rule); +- } +- +- signal_data_free (signal_data); +- } +- ++ /* May free signal_data */ ++ remove_signal_data_if_unused (connection, signal_data); + goto out; + } + diff --git a/libs/glib2/patches/111-CVE-2024-34397-gdbusconnection-Stop-storing-sender_unique_name-in-Signal.patch b/libs/glib2/patches/111-CVE-2024-34397-gdbusconnection-Stop-storing-sender_unique_name-in-Signal.patch new file mode 100644 index 0000000000..d0817d4feb --- /dev/null +++ b/libs/glib2/patches/111-CVE-2024-34397-gdbusconnection-Stop-storing-sender_unique_name-in-Signal.patch @@ -0,0 +1,163 @@ +From: Simon McVittie +Date: Tue, 23 Apr 2024 20:39:05 +0100 +Subject: gdbusconnection: Stop storing sender_unique_name in SignalData + +This will become confusing when we start tracking the owner of a +well-known-name sender, and it's redundant anyway. Instead, track the +1 bit of data that we actually need: whether it's a well-known name. + +Strictly speaking this too is redundant, because it's syntactically +derivable from the sender, but only via extra string operations. +A subsequent commit will add a data structure to keep track of the +owner of a well-known-name sender, at which point this boolean will +be replaced by the presence or absence of that data structure. + +Signed-off-by: Simon McVittie +Origin: upstream, https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +--- + gio/gdbusconnection.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +--- a/gio/gdbusconnection.c ++++ b/gio/gdbusconnection.c +@@ -325,19 +325,19 @@ typedef struct + { + gchar *rule; + gchar *sender; +- gchar *sender_unique_name; /* if sender is unique or org.freedesktop.DBus, then that name... otherwise blank */ + gchar *interface_name; + gchar *member; + gchar *object_path; + gchar *arg0; + GDBusSignalFlags flags; + GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */ ++ gboolean sender_is_its_own_owner; + } SignalData; + + static SignalData * + signal_data_new_take (gchar *rule, + gchar *sender, +- gchar *sender_unique_name, ++ gboolean sender_is_its_own_owner, + gchar *interface_name, + gchar *member, + gchar *object_path, +@@ -348,7 +348,7 @@ signal_data_new_take (gchar *rule, + + signal_data->rule = rule; + signal_data->sender = sender; +- signal_data->sender_unique_name = sender_unique_name; ++ signal_data->sender_is_its_own_owner = sender_is_its_own_owner; + signal_data->interface_name = interface_name; + signal_data->member = member; + signal_data->object_path = object_path; +@@ -363,7 +363,6 @@ signal_data_free (SignalData *signal_dat + { + g_free (signal_data->rule); + g_free (signal_data->sender); +- g_free (signal_data->sender_unique_name); + g_free (signal_data->interface_name); + g_free (signal_data->member); + g_free (signal_data->object_path); +@@ -3441,7 +3440,7 @@ remove_match_rule (GDBusConnection *conn + static gboolean + is_signal_data_for_name_lost_or_acquired (SignalData *signal_data) + { +- return g_strcmp0 (signal_data->sender_unique_name, "org.freedesktop.DBus") == 0 && ++ return g_strcmp0 (signal_data->sender, "org.freedesktop.DBus") == 0 && + g_strcmp0 (signal_data->interface_name, "org.freedesktop.DBus") == 0 && + g_strcmp0 (signal_data->object_path, "/org/freedesktop/DBus") == 0 && + (g_strcmp0 (signal_data->member, "NameLost") == 0 || +@@ -3453,7 +3452,8 @@ is_signal_data_for_name_lost_or_acquired + /* called in any thread, connection lock is held */ + static void + add_signal_data (GDBusConnection *connection, +- SignalData *signal_data) ++ SignalData *signal_data, ++ const char *sender_unique_name) + { + GPtrArray *signal_data_array; + +@@ -3473,12 +3473,12 @@ add_signal_data (GDBusConnection *connec + } + + signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, +- signal_data->sender_unique_name); ++ sender_unique_name); + if (signal_data_array == NULL) + { + signal_data_array = g_ptr_array_new (); + g_hash_table_insert (connection->map_sender_unique_name_to_signal_data_array, +- g_strdup (signal_data->sender_unique_name), ++ g_strdup (sender_unique_name), + signal_data_array); + } + g_ptr_array_add (signal_data_array, signal_data); +@@ -3575,6 +3575,7 @@ g_dbus_connection_signal_subscribe (GDBu + gchar *rule; + SignalData *signal_data; + SignalSubscriber *subscriber; ++ gboolean sender_is_its_own_owner; + const gchar *sender_unique_name; + + /* Right now we abort if AddMatch() fails since it can only fail with the bus being in +@@ -3610,6 +3611,11 @@ g_dbus_connection_signal_subscribe (GDBu + rule = args_to_rule (sender, interface_name, member, object_path, arg0, flags); + + if (sender != NULL && (g_dbus_is_unique_name (sender) || g_strcmp0 (sender, "org.freedesktop.DBus") == 0)) ++ sender_is_its_own_owner = TRUE; ++ else ++ sender_is_its_own_owner = FALSE; ++ ++ if (sender_is_its_own_owner) + sender_unique_name = sender; + else + sender_unique_name = ""; +@@ -3633,14 +3639,14 @@ g_dbus_connection_signal_subscribe (GDBu + + signal_data = signal_data_new_take (g_steal_pointer (&rule), + g_strdup (sender), +- g_strdup (sender_unique_name), ++ sender_is_its_own_owner, + g_strdup (interface_name), + g_strdup (member), + g_strdup (object_path), + g_strdup (arg0), + flags); + g_ptr_array_add (signal_data->subscribers, subscriber); +- add_signal_data (connection, signal_data); ++ add_signal_data (connection, signal_data, sender_unique_name); + + out: + g_hash_table_insert (connection->map_id_to_signal_data, +@@ -3664,22 +3670,28 @@ static void + remove_signal_data_if_unused (GDBusConnection *connection, + SignalData *signal_data) + { ++ const gchar *sender_unique_name; + GPtrArray *signal_data_array; + + if (signal_data->subscribers->len != 0) + return; + ++ if (signal_data->sender_is_its_own_owner) ++ sender_unique_name = signal_data->sender; ++ else ++ sender_unique_name = ""; ++ + g_warn_if_fail (g_hash_table_remove (connection->map_rule_to_signal_data, signal_data->rule)); + + signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, +- signal_data->sender_unique_name); ++ sender_unique_name); + g_warn_if_fail (signal_data_array != NULL); + g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data)); + + if (signal_data_array->len == 0) + { + g_warn_if_fail (g_hash_table_remove (connection->map_sender_unique_name_to_signal_data_array, +- signal_data->sender_unique_name)); ++ sender_unique_name)); + } + + /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */ diff --git a/libs/glib2/patches/112-CVE-2024-34397-gdbus-Track-name-owners-for-signal-subscriptions.patch b/libs/glib2/patches/112-CVE-2024-34397-gdbus-Track-name-owners-for-signal-subscriptions.patch new file mode 100644 index 0000000000..bc1acd1edf --- /dev/null +++ b/libs/glib2/patches/112-CVE-2024-34397-gdbus-Track-name-owners-for-signal-subscriptions.patch @@ -0,0 +1,504 @@ +From: Simon McVittie +Date: Wed, 1 May 2024 15:43:09 +0100 +Subject: gdbus: Track name owners for signal subscriptions + +We will use this in a subsequent commit to prevent signals from an +impostor from being delivered to a subscriber. + +To avoid message reordering leading to misleading situations, this does +not use the existing mechanism for watching bus name ownership, which +delivers the ownership changes to other main-contexts. Instead, it all +happens on the single thread used by the GDBusWorker, so the order in +which messages are received is the order in which they are processed. + +[Backported to glib-2-74, resolving minor conflicts] +Signed-off-by: Simon McVittie +Origin: upstream, https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +--- + gio/gdbusconnection.c | 350 +++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 343 insertions(+), 7 deletions(-) + +--- a/gio/gdbusconnection.c ++++ b/gio/gdbusconnection.c +@@ -323,6 +323,31 @@ signal_subscriber_unref (SignalSubscribe + + typedef struct + { ++ /* ++ * 1 reference while waiting for GetNameOwner() to finish ++ * 1 reference for each SignalData that points to this one as its ++ * shared_name_watcher ++ */ ++ grefcount ref_count; ++ ++ gchar *owner; ++ guint32 get_name_owner_serial; ++} WatchedName; ++ ++static WatchedName * ++watched_name_new (void) ++{ ++ WatchedName *watched_name = g_new0 (WatchedName, 1); ++ ++ g_ref_count_init (&watched_name->ref_count); ++ watched_name->owner = NULL; ++ return g_steal_pointer (&watched_name); ++} ++ ++typedef struct SignalData SignalData; ++ ++struct SignalData ++{ + gchar *rule; + gchar *sender; + gchar *interface_name; +@@ -331,13 +356,36 @@ typedef struct + gchar *arg0; + GDBusSignalFlags flags; + GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */ +- gboolean sender_is_its_own_owner; +-} SignalData; ++ ++ /* ++ * If the sender is a well-known name, this is an unowned SignalData ++ * representing the NameOwnerChanged signal that tracks its owner. ++ * NULL if sender is NULL. ++ * NULL if sender is its own owner (a unique name or DBUS_SERVICE_DBUS). ++ * ++ * Invariants: if not NULL, then ++ * shared_name_watcher->sender == DBUS_SERVICE_DBUS ++ * shared_name_watcher->interface_name == DBUS_INTERFACE_DBUS ++ * shared_name_watcher->member == "NameOwnerChanged" ++ * shared_name_watcher->object_path == DBUS_PATH_DBUS ++ * shared_name_watcher->arg0 == sender ++ * shared_name_watcher->flags == NONE ++ * shared_name_watcher->watched_name == NULL ++ */ ++ SignalData *shared_name_watcher; ++ ++ /* ++ * Non-NULL if this SignalData is another SignalData's shared_name_watcher. ++ * One reference for each SignalData that has this one as its ++ * shared_name_watcher. ++ * Otherwise NULL. ++ */ ++ WatchedName *watched_name; ++}; + + static SignalData * + signal_data_new_take (gchar *rule, + gchar *sender, +- gboolean sender_is_its_own_owner, + gchar *interface_name, + gchar *member, + gchar *object_path, +@@ -348,7 +396,6 @@ signal_data_new_take (gchar *rule, + + signal_data->rule = rule; + signal_data->sender = sender; +- signal_data->sender_is_its_own_owner = sender_is_its_own_owner; + signal_data->interface_name = interface_name; + signal_data->member = member; + signal_data->object_path = object_path; +@@ -361,6 +408,17 @@ signal_data_new_take (gchar *rule, + static void + signal_data_free (SignalData *signal_data) + { ++ /* The SignalData should not be freed while it still has subscribers */ ++ g_assert (signal_data->subscribers->len == 0); ++ ++ /* The SignalData should not be freed while it is watching for ++ * NameOwnerChanged on behalf of another SignalData */ ++ g_assert (signal_data->watched_name == NULL); ++ ++ /* The SignalData should be detached from its name watcher, if any, ++ * before it is freed */ ++ g_assert (signal_data->shared_name_watcher == NULL); ++ + g_free (signal_data->rule); + g_free (signal_data->sender); + g_free (signal_data->interface_name); +@@ -368,6 +426,7 @@ signal_data_free (SignalData *signal_dat + g_free (signal_data->object_path); + g_free (signal_data->arg0); + g_ptr_array_unref (signal_data->subscribers); ++ + g_free (signal_data); + } + +@@ -499,6 +558,7 @@ struct _GDBusConnection + + /* Map used for managing method replies, protected by @lock */ + GHashTable *map_method_serial_to_task; /* guint32 -> GTask* */ ++ GHashTable *map_method_serial_to_name_watcher; /* guint32 -> unowned SignalData* */ + + /* Maps used for managing signal subscription, protected by @lock */ + GHashTable *map_rule_to_signal_data; /* match rule (gchar*) -> SignalData */ +@@ -747,6 +807,7 @@ g_dbus_connection_finalize (GObject *obj + g_error_free (connection->initialization_error); + + g_hash_table_unref (connection->map_method_serial_to_task); ++ g_hash_table_unref (connection->map_method_serial_to_name_watcher); + + g_hash_table_unref (connection->map_rule_to_signal_data); + g_hash_table_unref (connection->map_id_to_signal_data); +@@ -1151,6 +1212,7 @@ g_dbus_connection_init (GDBusConnection + g_mutex_init (&connection->init_lock); + + connection->map_method_serial_to_task = g_hash_table_new (g_direct_hash, g_direct_equal); ++ connection->map_method_serial_to_name_watcher = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); + + connection->map_rule_to_signal_data = g_hash_table_new (g_str_hash, + g_str_equal); +@@ -2268,6 +2330,191 @@ g_dbus_connection_send_message_with_repl + + /* ---------------------------------------------------------------------------------------------------- */ + ++/* ++ * Called in any thread. ++ * Must hold the connection lock when calling this, unless ++ * connection->finalizing is TRUE. ++ */ ++static void ++name_watcher_unref_watched_name (GDBusConnection *connection, ++ SignalData *name_watcher) ++{ ++ WatchedName *watched_name = name_watcher->watched_name; ++ ++ g_assert (watched_name != NULL); ++ ++ if (!g_ref_count_dec (&watched_name->ref_count)) ++ return; ++ ++ /* Removing watched_name from the name_watcher may result in ++ * name_watcher being freed, so we must make sure name_watcher is no ++ * longer in map_method_serial_to_name_watcher. ++ * ++ * If we stop watching the name while our GetNameOwner call was still ++ * in-flight, then when the reply eventually arrives, we will not find ++ * its serial number in the map and harmlessly ignore it as a result. */ ++ if (watched_name->get_name_owner_serial != 0) ++ g_hash_table_remove (connection->map_method_serial_to_name_watcher, ++ GUINT_TO_POINTER (watched_name->get_name_owner_serial)); ++ ++ name_watcher->watched_name = NULL; ++ g_free (watched_name->owner); ++ g_free (watched_name); ++} ++ ++/* called in GDBusWorker thread with lock held */ ++static void ++name_watcher_set_name_owner_unlocked (SignalData *name_watcher, ++ const char *new_owner) ++{ ++ if (new_owner != NULL && new_owner[0] == '\0') ++ new_owner = NULL; ++ ++ g_assert (name_watcher->watched_name != NULL); ++ g_set_str (&name_watcher->watched_name->owner, new_owner); ++} ++ ++/* called in GDBusWorker thread with lock held */ ++static void ++name_watcher_deliver_name_owner_changed_unlocked (SignalData *name_watcher, ++ GDBusMessage *message) ++{ ++ GVariant *body; ++ ++ body = g_dbus_message_get_body (message); ++ ++ if (G_LIKELY (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(sss)")))) ++ { ++ const char *name; ++ const char *new_owner; ++ ++ g_variant_get (body, "(&s&s&s)", &name, NULL, &new_owner); ++ ++ /* Our caller already checked this */ ++ g_assert (g_strcmp0 (name_watcher->arg0, name) == 0); ++ ++ if (G_LIKELY (new_owner[0] == '\0' || g_dbus_is_unique_name (new_owner))) ++ name_watcher_set_name_owner_unlocked (name_watcher, new_owner); ++ else ++ g_warning ("Received NameOwnerChanged signal with invalid owner \"%s\" for \"%s\"", ++ new_owner, name); ++ } ++ else ++ { ++ g_warning ("Received NameOwnerChanged signal with unexpected " ++ "signature %s", ++ body == NULL ? "()" : g_variant_get_type_string (body)); ++ ++ } ++} ++ ++/* called in GDBusWorker thread with lock held */ ++static void ++name_watcher_deliver_get_name_owner_reply_unlocked (SignalData *name_watcher, ++ GDBusConnection *connection, ++ GDBusMessage *message) ++{ ++ GDBusMessageType type; ++ GVariant *body; ++ WatchedName *watched_name; ++ ++ watched_name = name_watcher->watched_name; ++ g_assert (watched_name != NULL); ++ g_assert (watched_name->get_name_owner_serial != 0); ++ ++ type = g_dbus_message_get_message_type (message); ++ body = g_dbus_message_get_body (message); ++ ++ if (type == G_DBUS_MESSAGE_TYPE_ERROR) ++ { ++ if (g_strcmp0 (g_dbus_message_get_error_name (message), ++ "org.freedesktop.DBus.Error.NameHasNoOwner")) ++ name_watcher_set_name_owner_unlocked (name_watcher, NULL); ++ /* else it's something like NoReply or AccessDenied, which tells ++ * us nothing - leave the owner set to whatever we most recently ++ * learned from NameOwnerChanged, or NULL */ ++ } ++ else if (type != G_DBUS_MESSAGE_TYPE_METHOD_RETURN) ++ { ++ g_warning ("Received GetNameOwner reply with unexpected type %d", ++ type); ++ } ++ else if (G_LIKELY (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))) ++ { ++ const char *new_owner; ++ ++ g_variant_get (body, "(&s)", &new_owner); ++ ++ if (G_LIKELY (g_dbus_is_unique_name (new_owner))) ++ name_watcher_set_name_owner_unlocked (name_watcher, new_owner); ++ else ++ g_warning ("Received GetNameOwner reply with invalid owner \"%s\" for \"%s\"", ++ new_owner, name_watcher->arg0); ++ } ++ else ++ { ++ g_warning ("Received GetNameOwner reply with unexpected signature %s", ++ body == NULL ? "()" : g_variant_get_type_string (body)); ++ } ++ ++ g_hash_table_remove (connection->map_method_serial_to_name_watcher, ++ GUINT_TO_POINTER (watched_name->get_name_owner_serial)); ++ watched_name->get_name_owner_serial = 0; ++} ++ ++/* Called in a user thread, lock is held */ ++static void ++name_watcher_call_get_name_owner_unlocked (GDBusConnection *connection, ++ SignalData *name_watcher) ++{ ++ GDBusMessage *message; ++ GError *local_error = NULL; ++ WatchedName *watched_name; ++ ++ g_assert (g_strcmp0 (name_watcher->sender, DBUS_SERVICE_DBUS) == 0); ++ g_assert (g_strcmp0 (name_watcher->interface_name, DBUS_INTERFACE_DBUS) == 0); ++ g_assert (g_strcmp0 (name_watcher->member, "NameOwnerChanged") == 0); ++ g_assert (g_strcmp0 (name_watcher->object_path, DBUS_PATH_DBUS) == 0); ++ /* arg0 of the NameOwnerChanged message is the well-known name whose owner ++ * we are interested in */ ++ g_assert (g_dbus_is_name (name_watcher->arg0)); ++ g_assert (name_watcher->flags == G_DBUS_SIGNAL_FLAGS_NONE); ++ ++ watched_name = name_watcher->watched_name; ++ g_assert (watched_name != NULL); ++ g_assert (watched_name->owner == NULL); ++ g_assert (watched_name->get_name_owner_serial == 0); ++ g_assert (name_watcher->shared_name_watcher == NULL); ++ ++ message = g_dbus_message_new_method_call (DBUS_SERVICE_DBUS, ++ DBUS_PATH_DBUS, ++ DBUS_INTERFACE_DBUS, ++ "GetNameOwner"); ++ g_dbus_message_set_body (message, g_variant_new ("(s)", name_watcher->arg0)); ++ ++ if (g_dbus_connection_send_message_unlocked (connection, message, ++ G_DBUS_SEND_MESSAGE_FLAGS_NONE, ++ &watched_name->get_name_owner_serial, ++ &local_error)) ++ { ++ g_assert (watched_name->get_name_owner_serial != 0); ++ g_hash_table_insert (connection->map_method_serial_to_name_watcher, ++ GUINT_TO_POINTER (watched_name->get_name_owner_serial), ++ name_watcher); ++ } ++ else ++ { ++ g_critical ("Error while sending GetNameOwner() message: %s", ++ local_error->message); ++ g_clear_error (&local_error); ++ g_assert (watched_name->get_name_owner_serial == 0); ++ } ++ ++ g_object_unref (message); ++} ++ ++/* ---------------------------------------------------------------------------------------------------- */ ++ + typedef struct + { + guint id; +@@ -2391,6 +2638,7 @@ on_worker_message_received (GDBusWorker + { + guint32 reply_serial; + GTask *task; ++ SignalData *name_watcher; + + reply_serial = g_dbus_message_get_reply_serial (message); + CONNECTION_LOCK (connection); +@@ -2406,6 +2654,19 @@ on_worker_message_received (GDBusWorker + { + //g_debug ("message reply/error for serial %d but no SendMessageData found for %p", reply_serial, connection); + } ++ ++ name_watcher = g_hash_table_lookup (connection->map_method_serial_to_name_watcher, ++ GUINT_TO_POINTER (reply_serial)); ++ ++ if (name_watcher != NULL) ++ { ++ g_assert (name_watcher->watched_name != NULL); ++ g_assert (name_watcher->watched_name->get_name_owner_serial == reply_serial); ++ name_watcher_deliver_get_name_owner_reply_unlocked (name_watcher, ++ connection, ++ message); ++ } ++ + CONNECTION_UNLOCK (connection); + } + else if (message_type == G_DBUS_MESSAGE_TYPE_SIGNAL) +@@ -3574,6 +3835,7 @@ g_dbus_connection_signal_subscribe (GDBu + { + gchar *rule; + SignalData *signal_data; ++ SignalData *name_watcher = NULL; + SignalSubscriber *subscriber; + gboolean sender_is_its_own_owner; + const gchar *sender_unique_name; +@@ -3639,13 +3901,59 @@ g_dbus_connection_signal_subscribe (GDBu + + signal_data = signal_data_new_take (g_steal_pointer (&rule), + g_strdup (sender), +- sender_is_its_own_owner, + g_strdup (interface_name), + g_strdup (member), + g_strdup (object_path), + g_strdup (arg0), + flags); + g_ptr_array_add (signal_data->subscribers, subscriber); ++ ++ /* If subscribing to a signal from a specific sender with a well-known ++ * name, we must first subscribe to NameOwnerChanged signals for that ++ * well-known name, so that we can match the current owner of the name ++ * against the sender of each signal. */ ++ if (sender != NULL && !sender_is_its_own_owner) ++ { ++ gchar *name_owner_rule = NULL; ++ ++ /* We already checked that sender != NULL implies MESSAGE_BUS_CONNECTION */ ++ g_assert (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION); ++ ++ name_owner_rule = args_to_rule (DBUS_SERVICE_DBUS, ++ DBUS_INTERFACE_DBUS, ++ "NameOwnerChanged", ++ DBUS_PATH_DBUS, ++ sender, ++ G_DBUS_SIGNAL_FLAGS_NONE); ++ name_watcher = g_hash_table_lookup (connection->map_rule_to_signal_data, name_owner_rule); ++ ++ if (name_watcher == NULL) ++ { ++ name_watcher = signal_data_new_take (g_steal_pointer (&name_owner_rule), ++ g_strdup (DBUS_SERVICE_DBUS), ++ g_strdup (DBUS_INTERFACE_DBUS), ++ g_strdup ("NameOwnerChanged"), ++ g_strdup (DBUS_PATH_DBUS), ++ g_strdup (sender), ++ G_DBUS_SIGNAL_FLAGS_NONE); ++ add_signal_data (connection, name_watcher, DBUS_SERVICE_DBUS); ++ } ++ ++ if (name_watcher->watched_name == NULL) ++ { ++ name_watcher->watched_name = watched_name_new (); ++ name_watcher_call_get_name_owner_unlocked (connection, name_watcher); ++ } ++ else ++ { ++ g_ref_count_inc (&name_watcher->watched_name->ref_count); ++ } ++ ++ signal_data->shared_name_watcher = name_watcher; ++ ++ g_clear_pointer (&name_owner_rule, g_free); ++ } ++ + add_signal_data (connection, signal_data, sender_unique_name); + + out: +@@ -3673,10 +3981,18 @@ remove_signal_data_if_unused (GDBusConne + const gchar *sender_unique_name; + GPtrArray *signal_data_array; + ++ /* Cannot remove while there are still subscribers */ + if (signal_data->subscribers->len != 0) + return; + +- if (signal_data->sender_is_its_own_owner) ++ /* Cannot remove while another SignalData is still using this one ++ * as its shared_name_watcher, which holds watched_name->ref_count > 0 */ ++ if (signal_data->watched_name != NULL) ++ return; ++ ++ /* Point of no return: we have committed to removing it */ ++ ++ if (signal_data->sender != NULL && signal_data->shared_name_watcher == NULL) + sender_unique_name = signal_data->sender; + else + sender_unique_name = ""; +@@ -3709,6 +4025,15 @@ remove_signal_data_if_unused (GDBusConne + remove_match_rule (connection, signal_data->rule); + } + ++ if (signal_data->shared_name_watcher != NULL) ++ { ++ SignalData *name_watcher = g_steal_pointer (&signal_data->shared_name_watcher); ++ ++ name_watcher_unref_watched_name (connection, name_watcher); ++ /* May free signal_data */ ++ remove_signal_data_if_unused (connection, name_watcher); ++ } ++ + signal_data_free (signal_data); + } + +@@ -3981,6 +4306,17 @@ schedule_callbacks (GDBusConnection *con + continue; + } + ++ if (signal_data->watched_name != NULL) ++ { ++ /* Invariant: SignalData should only have a watched_name if it ++ * represents the NameOwnerChanged signal */ ++ g_assert (g_strcmp0 (sender, DBUS_SERVICE_DBUS) == 0); ++ g_assert (g_strcmp0 (interface, DBUS_INTERFACE_DBUS) == 0); ++ g_assert (g_strcmp0 (path, DBUS_PATH_DBUS) == 0); ++ g_assert (g_strcmp0 (member, "NameOwnerChanged") == 0); ++ name_watcher_deliver_name_owner_changed_unlocked (signal_data, message); ++ } ++ + for (m = 0; m < signal_data->subscribers->len; m++) + { + SignalSubscriber *subscriber = signal_data->subscribers->pdata[m]; +@@ -4042,7 +4378,7 @@ distribute_signals (GDBusConnection *con + schedule_callbacks (connection, signal_data_array, message, sender); + } + +- /* collect subscribers not matching on sender */ ++ /* collect subscribers not matching on sender, or matching a well-known name */ + signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, ""); + if (signal_data_array != NULL) + schedule_callbacks (connection, signal_data_array, message, sender); diff --git a/libs/glib2/patches/113-CVE-2024-34397-gdbusconnection-Don-t-deliver-signals-if-the-sender-doesn.patch b/libs/glib2/patches/113-CVE-2024-34397-gdbusconnection-Don-t-deliver-signals-if-the-sender-doesn.patch new file mode 100644 index 0000000000..b9d80f2ee3 --- /dev/null +++ b/libs/glib2/patches/113-CVE-2024-34397-gdbusconnection-Don-t-deliver-signals-if-the-sender-doesn.patch @@ -0,0 +1,65 @@ +From: Simon McVittie +Date: Thu, 14 Mar 2024 20:42:41 +0000 +Subject: gdbusconnection: Don't deliver signals if the sender doesn't match + +Otherwise a malicious connection on a shared bus, especially the system +bus, could trick GDBus clients into processing signals sent by the +malicious connection as though they had come from the real owner of a +well-known service name. + +Resolves: https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +Signed-off-by: Simon McVittie +Origin: upstream, https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +--- + gio/gdbusconnection.c | 40 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +--- a/gio/gdbusconnection.c ++++ b/gio/gdbusconnection.c +@@ -4287,6 +4287,46 @@ schedule_callbacks (GDBusConnection *con + if (signal_data->object_path != NULL && g_strcmp0 (signal_data->object_path, path) != 0) + continue; + ++ if (signal_data->shared_name_watcher != NULL) ++ { ++ /* We want signals from a specified well-known name, which means ++ * the signal's sender needs to be the unique name that currently ++ * owns that well-known name, and we will have found this ++ * SignalData in ++ * connection->map_sender_unique_name_to_signal_data_array[""]. */ ++ const WatchedName *watched_name; ++ const char *current_owner; ++ ++ g_assert (signal_data->sender != NULL); ++ /* Invariant: We never need to watch for the owner of a unique ++ * name, or for the owner of DBUS_SERVICE_DBUS, either of which ++ * is always its own owner */ ++ g_assert (!g_dbus_is_unique_name (signal_data->sender)); ++ g_assert (g_strcmp0 (signal_data->sender, DBUS_SERVICE_DBUS) != 0); ++ ++ watched_name = signal_data->shared_name_watcher->watched_name; ++ g_assert (watched_name != NULL); ++ current_owner = watched_name->owner; ++ ++ /* Skip the signal if the actual sender is not known to own ++ * the required name */ ++ if (current_owner == NULL || g_strcmp0 (current_owner, sender) != 0) ++ continue; ++ } ++ else if (signal_data->sender != NULL) ++ { ++ /* We want signals from a unique name or o.fd.DBus... */ ++ g_assert (g_dbus_is_unique_name (signal_data->sender) ++ || g_str_equal (signal_data->sender, DBUS_SERVICE_DBUS)); ++ ++ /* ... which means we must have found this SignalData in ++ * connection->map_sender_unique_name_to_signal_data_array[signal_data->sender], ++ * therefore we would only have found it if the signal's ++ * actual sender matches the required signal_data->sender */ ++ g_assert (g_strcmp0 (signal_data->sender, sender) == 0); ++ } ++ /* else the sender is unspecified and we will accept anything */ ++ + if (signal_data->arg0 != NULL) + { + if (arg0 == NULL) diff --git a/libs/glib2/patches/114-CVE-2024-34397-tests-Add-a-test-for-matching-by-two-well-known-names.patch b/libs/glib2/patches/114-CVE-2024-34397-tests-Add-a-test-for-matching-by-two-well-known-names.patch new file mode 100644 index 0000000000..768e7fc90d --- /dev/null +++ b/libs/glib2/patches/114-CVE-2024-34397-tests-Add-a-test-for-matching-by-two-well-known-names.patch @@ -0,0 +1,38 @@ +From: Simon McVittie +Date: Fri, 8 Mar 2024 19:51:50 +0000 +Subject: tests: Add a test for matching by two well-known names + +The expected result is that because TEST_CONN_SERVICE owns +ALREADY_OWNED_NAME but not (yet) OWNED_LATER_NAME, the signal will be +delivered to the subscriber for the former but not the latter. +Before #3268 was fixed, it was incorrectly delivered to both. + +Reproduces: https://gitlab.gnome.org/GNOME/glib/-/issues/3268 (partially) +Signed-off-by: Simon McVittie +Origin: upstream, https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +--- + gio/tests/gdbus-subscribe.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/gio/tests/gdbus-subscribe.c ++++ b/gio/tests/gdbus-subscribe.c +@@ -441,6 +441,19 @@ static const TestPlan plan_limit_by_well + }, + }, + { ++ /* When the service sends a signal with the name it already owns, ++ * it should get through */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_SERVICE, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 1, ++ .received_by_proxy = 1 ++ }, ++ }, ++ { + /* Service claims another name */ + .action = TEST_ACTION_OWN_NAME, + .u.own_name = { diff --git a/libs/glib2/patches/115-CVE-2024-34397-tests-Add-a-test-for-signal-filtering-by-well-known-name.patch b/libs/glib2/patches/115-CVE-2024-34397-tests-Add-a-test-for-signal-filtering-by-well-known-name.patch new file mode 100644 index 0000000000..c78d7da4ef --- /dev/null +++ b/libs/glib2/patches/115-CVE-2024-34397-tests-Add-a-test-for-signal-filtering-by-well-known-name.patch @@ -0,0 +1,52 @@ +From: Simon McVittie +Date: Fri, 8 Mar 2024 19:53:22 +0000 +Subject: tests: Add a test for signal filtering by well-known name + +The vulnerability reported as GNOME/glib#3268 can be characterized +as: these signals from an attacker should not be delivered to either +the GDBusConnection or the GDBusProxy, but in fact they are (in at +least some scenarios). + +Reproduces: https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +Signed-off-by: Simon McVittie +Origin: upstream, https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +--- + gio/tests/gdbus-subscribe.c | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +--- a/gio/tests/gdbus-subscribe.c ++++ b/gio/tests/gdbus-subscribe.c +@@ -441,6 +441,33 @@ static const TestPlan plan_limit_by_well + }, + }, + { ++ /* Attacker wants to trick subscriber into thinking that service ++ * sent a signal */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_ATTACKER, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 0, ++ .received_by_proxy = 0 ++ }, ++ }, ++ { ++ /* Attacker tries harder, by sending a signal unicast directly to ++ * the subscriber */ ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_ATTACKER, ++ .unicast_to = TEST_CONN_SUBSCRIBER, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 0, ++ .received_by_proxy = 0 ++ }, ++ }, ++ { + /* When the service sends a signal with the name it already owns, + * it should get through */ + .action = TEST_ACTION_EMIT_SIGNAL, diff --git a/libs/glib2/patches/116-CVE-2024-34397-tests-Ensure-that-unsubscribing-with-GetNameOwner-in-flig.patch b/libs/glib2/patches/116-CVE-2024-34397-tests-Ensure-that-unsubscribing-with-GetNameOwner-in-flig.patch new file mode 100644 index 0000000000..874bd1dcec --- /dev/null +++ b/libs/glib2/patches/116-CVE-2024-34397-tests-Ensure-that-unsubscribing-with-GetNameOwner-in-flig.patch @@ -0,0 +1,112 @@ +From: Simon McVittie +Date: Tue, 23 Apr 2024 21:39:43 +0100 +Subject: tests: Ensure that unsubscribing with GetNameOwner in-flight doesn't + crash + +This was a bug that existed during development of this branch; make sure +it doesn't come back. + +This test fails with a use-after-free and crash if we comment out the +part of name_watcher_unref_watched_name() that removes the name watcher +from `map_method_serial_to_name_watcher`. + +It would also fail with an assertion failure if we asserted in +name_watcher_unref_watched_name() that get_name_owner_serial == 0 +(i.e. that GetNameOwner is not in-flight at destruction). + +Signed-off-by: Simon McVittie +Origin: upstream, https://gitlab.gnome.org/GNOME/glib/-/issues/3268 +--- + gio/tests/gdbus-subscribe.c | 52 ++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 51 insertions(+), 1 deletion(-) + +--- a/gio/tests/gdbus-subscribe.c ++++ b/gio/tests/gdbus-subscribe.c +@@ -116,6 +116,7 @@ typedef struct + const char *member; + const char *arg0; + GDBusSignalFlags flags; ++ gboolean unsubscribe_immediately; + } TestSubscribe; + + typedef struct +@@ -141,6 +142,7 @@ typedef struct + TestEmitSignal signal; + TestSubscribe subscribe; + TestOwnName own_name; ++ guint unsubscribe_undo_step; + } u; + } TestStep; + +@@ -505,6 +507,43 @@ static const TestPlan plan_limit_by_well + }, + }; + ++static const TestPlan plan_unsubscribe_immediately = ++{ ++ .description = "Unsubscribing before GetNameOwner can return doesn't result in a crash", ++ .steps = { ++ { ++ /* Service already owns one name */ ++ .action = TEST_ACTION_OWN_NAME, ++ .u.own_name = { ++ .name = ALREADY_OWNED_NAME, ++ .owner = TEST_CONN_SERVICE ++ }, ++ }, ++ { ++ .action = TEST_ACTION_SUBSCRIBE, ++ .u.subscribe = { ++ .string_sender = ALREADY_OWNED_NAME, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .unsubscribe_immediately = TRUE ++ }, ++ }, ++ { ++ .action = TEST_ACTION_EMIT_SIGNAL, ++ .u.signal = { ++ .sender = TEST_CONN_SERVICE, ++ .path = EXAMPLE_PATH, ++ .iface = EXAMPLE_INTERFACE, ++ .member = FOO_SIGNAL, ++ .received_by_conn = 0, ++ /* The proxy can't unsubscribe, except by destroying the proxy ++ * completely, which we don't currently implement in this test */ ++ .received_by_proxy = 1 ++ }, ++ }, ++ }, ++}; ++ + static const TestPlan plan_limit_to_message_bus = + { + .description = "A subscription to the message bus only accepts messages " +@@ -855,8 +894,18 @@ fixture_subscribe (Fixture * + subscribe->flags, + subscribed_signal_cb, + f, NULL); ++ + g_assert_cmpuint (id, !=, 0); +- f->subscriptions[step_number] = id; ++ ++ if (subscribe->unsubscribe_immediately) ++ { ++ g_test_message ("\tImmediately unsubscribing"); ++ g_dbus_connection_signal_unsubscribe (subscriber, id); ++ } ++ else ++ { ++ f->subscriptions[step_number] = id; ++ } + } + + if (f->mode != SUBSCRIPTION_MODE_CONN) +@@ -1287,6 +1336,7 @@ main (int argc, + ADD_SUBSCRIBE_TEST (nonexistent_unique_name); + ADD_SUBSCRIBE_TEST (limit_by_well_known_name); + ADD_SUBSCRIBE_TEST (limit_to_message_bus); ++ ADD_SUBSCRIBE_TEST (unsubscribe_immediately); + + return g_test_run(); + } diff --git a/libs/glib2/patches/117-CVE-2024-34397-gdbus-proxy-test-Wait-before-asserting-name-owner-has-gon.patch b/libs/glib2/patches/117-CVE-2024-34397-gdbus-proxy-test-Wait-before-asserting-name-owner-has-gon.patch new file mode 100644 index 0000000000..670e532005 --- /dev/null +++ b/libs/glib2/patches/117-CVE-2024-34397-gdbus-proxy-test-Wait-before-asserting-name-owner-has-gon.patch @@ -0,0 +1,39 @@ +From: Simon McVittie +Date: Mon, 6 May 2024 21:24:53 +0100 +Subject: gdbus-proxy test: Wait before asserting name owner has gone away + +GDBusConnection sends each signal to recipients in a separate idle +callback, and there's no particular guarantee about the order in which +they're scheduled or dispatched. For the NameOwnerChanged signal that +reports the name becoming unowned, it's possible that g_bus_watch_name() +gets its idle callback called before the GDBusProxy:g-name-owner +machinery has updated the name owner, in which case the assertion +will fail. + +Fixing GNOME/glib#3268 introduced a new subscription to NameOwnerChanged +which can alter the order of delivery, particularly in the case where +G_DBUS_PROXY_FLAGS_NO_MATCH_RULE was used (as tested in +/gdbus/proxy/no-match-rule). The resulting test failure is intermittent, +but reliably appears within 100 repetitions of that test. + +Fixes: 511c5f5b "tests: Wait for gdbus-testserver to die when killing it" +Signed-off-by: Simon McVittie +--- + gio/tests/gdbus-proxy.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/gio/tests/gdbus-proxy.c ++++ b/gio/tests/gdbus-proxy.c +@@ -780,6 +780,12 @@ kill_test_service (GDBusConnection *conn + while (!name_disappeared) + g_main_context_iteration (NULL, TRUE); + ++ /* GDBusConnection doesn't guarantee that different subscriptions to the ++ * same signal will get their callbacks scheduled in any particular order, ++ * so make sure they have all happened */ ++ while (g_main_context_iteration (NULL, FALSE)) ++ continue; ++ + g_bus_unwatch_name (watch_id); + #else + g_warning ("Can't kill com.example.TestService"); diff --git a/libs/glib2/patches/118-CVE-2024-34397-gdbusconnection-Allow-name-owners-to-have-the-syntax-of-a.patch b/libs/glib2/patches/118-CVE-2024-34397-gdbusconnection-Allow-name-owners-to-have-the-syntax-of-a.patch new file mode 100644 index 0000000000..2a47e43b09 --- /dev/null +++ b/libs/glib2/patches/118-CVE-2024-34397-gdbusconnection-Allow-name-owners-to-have-the-syntax-of-a.patch @@ -0,0 +1,47 @@ +From: Simon McVittie +Date: Wed, 8 May 2024 10:09:40 +0100 +Subject: gdbusconnection: Allow name owners to have the syntax of a + well-known name + +In a D-Bus-Specification-compliant message bus, the owner of a well-known +name is a unique name. However, ibus has its own small implementation +of a message bus (src/ibusbus.c) in which org.freedesktop.IBus is +special-cased to also have itself as its owner (like org.freedesktop.DBus +on a standard message bus), and connects to that bus with the +G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION flag. The ability to do +this regressed when CVE-2024-34397 was fixed. + +Relax the checks to allow the owner of a well-known name to be any valid +D-Bus name, even if it is not syntactically a unique name. + +Bug: https://gitlab.gnome.org/GNOME/glib/-/issues/3353 +Bug-Debian: https://bugs.debian.org/1070730 +Bug-Debian: https://bugs.debian.org/1070736 +Bug-Debian: https://bugs.debian.org/1070743 +Bug-Debian: https://bugs.debian.org/1070745 +Signed-off-by: Simon McVittie +Forwarded: https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4053 +--- + gio/gdbusconnection.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/gio/gdbusconnection.c ++++ b/gio/gdbusconnection.c +@@ -2393,7 +2393,7 @@ name_watcher_deliver_name_owner_changed_ + /* Our caller already checked this */ + g_assert (g_strcmp0 (name_watcher->arg0, name) == 0); + +- if (G_LIKELY (new_owner[0] == '\0' || g_dbus_is_unique_name (new_owner))) ++ if (G_LIKELY (new_owner[0] == '\0' || g_dbus_is_name (new_owner))) + name_watcher_set_name_owner_unlocked (name_watcher, new_owner); + else + g_warning ("Received NameOwnerChanged signal with invalid owner \"%s\" for \"%s\"", +@@ -2445,7 +2445,7 @@ name_watcher_deliver_get_name_owner_repl + + g_variant_get (body, "(&s)", &new_owner); + +- if (G_LIKELY (g_dbus_is_unique_name (new_owner))) ++ if (G_LIKELY (g_dbus_is_name (new_owner))) + name_watcher_set_name_owner_unlocked (name_watcher, new_owner); + else + g_warning ("Received GetNameOwner reply with invalid owner \"%s\" for \"%s\"", diff --git a/libs/glib2/patches/120-gdbusmessage-Clean-the-cached-arg0-when-setting-the-messa.patch b/libs/glib2/patches/120-gdbusmessage-Clean-the-cached-arg0-when-setting-the-messa.patch new file mode 100644 index 0000000000..c5ea8019a5 --- /dev/null +++ b/libs/glib2/patches/120-gdbusmessage-Clean-the-cached-arg0-when-setting-the-messa.patch @@ -0,0 +1,39 @@ +From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= +Date: Wed, 8 May 2024 22:53:51 +0200 +Subject: gdbusmessage: Clean the cached arg0 when setting the message body + +We're now caching arg0 but such value is not cleared when a new body is +set as it's in the connection filter test cases where we've a leak as +highlighted by both valgrind and leak sanitizer + +Origin: upstream, 2.80.3, commit:fe89e9f3cb6e0fd0dc2bd8a2d413799e1443cef1 +Bug-Debian: https://bugs.debian.org/1070851 +--- + gio/gdbusmessage.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/gio/gdbusmessage.c ++++ b/gio/gdbusmessage.c +@@ -1164,10 +1164,12 @@ g_dbus_message_set_body (GDBusMessage * + + if (message->body != NULL) + g_variant_unref (message->body); ++ ++ g_clear_pointer (&message->arg0_cache, g_variant_unref); ++ + if (body == NULL) + { + message->body = NULL; +- message->arg0_cache = NULL; + g_dbus_message_set_signature (message, NULL); + } + else +@@ -1181,8 +1183,6 @@ g_dbus_message_set_body (GDBusMessage * + if (g_variant_is_of_type (message->body, G_VARIANT_TYPE_TUPLE) && + g_variant_n_children (message->body) > 0) + message->arg0_cache = g_variant_get_child_value (message->body, 0); +- else +- message->arg0_cache = NULL; + + type_string = g_variant_get_type_string (body); + type_string_len = strlen (type_string); diff --git a/net/banip/Makefile b/net/banip/Makefile index 9b22116e0b..e641bfce6f 100644 --- a/net/banip/Makefile +++ b/net/banip/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=banip PKG_VERSION:=1.0.0 -PKG_RELEASE:=5 +PKG_RELEASE:=6 PKG_LICENSE:=GPL-3.0-or-later PKG_MAINTAINER:=Dirk Brenken diff --git a/net/banip/files/banip-functions.sh b/net/banip/files/banip-functions.sh index cf83913bb4..e9fa2f5d2c 100644 --- a/net/banip/files/banip-functions.sh +++ b/net/banip/files/banip-functions.sh @@ -123,7 +123,7 @@ f_cmd() { cmd="$(command -v "${pri_cmd}" 2>/dev/null)" if [ ! -x "${cmd}" ]; then if [ -n "${sec_cmd}" ]; then - [ "${sec_cmd}" = "true" ] && return + [ "${sec_cmd}" = "optional" ] && return cmd="$(command -v "${sec_cmd}" 2>/dev/null)" fi if [ -x "${cmd}" ]; then @@ -1645,7 +1645,7 @@ f_mail() { # log monitor # f_monitor() { - local daemon logread_cmd loglimit_cmd nft_expiry line proto ip log_raw log_count rdap_log rdap_rc rdap_prefix rdap_length rdap_info + local daemon logread_cmd loglimit_cmd nft_expiry line proto ip log_raw log_count idx prefix cidr rdap_log rdap_rc rdap_idx rdap_info if [ -f "${ban_logreadfile}" ]; then logread_cmd="${ban_logreadcmd} -qf ${ban_logreadfile} 2>/dev/null | ${ban_grepcmd} -e \"${ban_logterm%%??}\" 2>/dev/null" @@ -1693,16 +1693,22 @@ f_monitor() { rdap_log="$("${ban_fetchcmd}" ${ban_rdapparm} "${ban_rdapfile}" "${ban_rdapurl}${ip}" 2>&1)" rdap_rc="${?}" if [ "${rdap_rc}" = "0" ] && [ -s "${ban_rdapfile}" ]; then - [ "${proto}" = "v4" ] && rdap_prefix="$(jsonfilter -l1 -i "${ban_rdapfile}" -qe '@.cidr0_cidrs.*.v4prefix')" - [ "${proto}" = "v6" ] && rdap_prefix="$(jsonfilter -l1 -i "${ban_rdapfile}" -qe '@.cidr0_cidrs.*.v6prefix')" - rdap_length="$(jsonfilter -l1 -i "${ban_rdapfile}" -qe '@.cidr0_cidrs.*.length')" - rdap_info="$(jsonfilter -l1 -i "${ban_rdapfile}" -qe '@.country' -qe '@.notices[@.title="Source"].description[1]' | awk 'BEGIN{RS="";FS="\n"}{printf "%s, %s",$1,$2}')" - [ -z "${rdap_info}" ] && rdap_info="$(jsonfilter -l1 -i "${ban_rdapfile}" -qe '@.notices[0].links[0].value' | awk 'BEGIN{FS="[/.]"}{printf"%s, %s","n/a",toupper($4)}')" - if [ -n "${rdap_prefix}" ] && [ -n "${rdap_length}" ]; then - if "${ban_nftcmd}" add element inet banIP "blocklist${proto}" { ${rdap_prefix}/${rdap_length} ${nft_expiry} } >/dev/null 2>&1; then - f_log "info" "add IP range '${rdap_prefix}/${rdap_length}' (source: ${rdap_info:-"n/a"} ::: expiry: ${ban_nftexpiry:-"-"}) to blocklist${proto} set" + [ "${proto}" = "v4" ] && rdap_idx="$("${ban_jsoncmd}" -i "${ban_rdapfile}" -qe '@.cidr0_cidrs[@.v4prefix].*' | "${ban_awkcmd}" '{ORS=" "; print}')" + [ "${proto}" = "v6" ] && rdap_idx="$("${ban_jsoncmd}" -i "${ban_rdapfile}" -qe '@.cidr0_cidrs[@.v6prefix].*' | "${ban_awkcmd}" '{ORS=" "; print}')" + rdap_info="$("${ban_jsoncmd}" -l1 -i "${ban_rdapfile}" -qe '@.country' -qe '@.notices[@.title="Source"].description[1]' | "${ban_awkcmd}" 'BEGIN{RS="";FS="\n"}{printf "%s, %s",$1,$2}')" + [ -z "${rdap_info}" ] && rdap_info="$("${ban_jsoncmd}" -l1 -i "${ban_rdapfile}" -qe '@.notices[0].links[0].value' | "${ban_awkcmd}" 'BEGIN{FS="[/.]"}{printf"%s, %s","n/a",toupper($4)}')" + for idx in ${rdap_idx}; do + if [ -z "${prefix}" ]; then + prefix="${idx}" + continue + else + cidr="${prefix}/${idx}" + if "${ban_nftcmd}" add element inet banIP "blocklist${proto}" { ${cidr} ${nft_expiry} } >/dev/null 2>&1; then + f_log "info" "add IP range '${cidr}' (source: ${rdap_info:-"n/a"} ::: expiry: ${ban_nftexpiry:-"-"}) to blocklist${proto} set" + fi + prefix="" fi - fi + done else f_log "info" "rdap request failed (rc: ${rdap_rc:-"-"}/log: ${rdap_log})" fi @@ -1730,7 +1736,7 @@ else f_log "emerg" "system libraries not found" fi -# initial system calls +# reference required system utilities # ban_awkcmd="$(f_cmd gawk awk)" ban_catcmd="$(f_cmd cat)" @@ -1739,7 +1745,7 @@ ban_grepcmd="$(f_cmd grep)" ban_jsoncmd="$(f_cmd jsonfilter)" ban_logcmd="$(f_cmd logger)" ban_lookupcmd="$(f_cmd nslookup)" -ban_mailcmd="$(f_cmd msmtp true)" +ban_mailcmd="$(f_cmd msmtp optional)" ban_nftcmd="$(f_cmd nft)" ban_pgrepcmd="$(f_cmd pgrep)" ban_sedcmd="$(f_cmd sed)" diff --git a/net/cloudflared/Makefile b/net/cloudflared/Makefile index b49ba6282f..c85b23f2ff 100644 --- a/net/cloudflared/Makefile +++ b/net/cloudflared/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=cloudflared PKG_VERSION:=2024.4.1 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/cloudflare/cloudflared/tar.gz/$(PKG_VERSION)? diff --git a/net/cloudflared/files/cloudflared.init b/net/cloudflared/files/cloudflared.init index ffef8d0931..35794b3687 100755 --- a/net/cloudflared/files/cloudflared.init +++ b/net/cloudflared/files/cloudflared.init @@ -53,4 +53,5 @@ reload_service() { service_triggers() { procd_add_reload_trigger "$CONF" + procd_add_interface_trigger "interface.*.up" "wan" /etc/init.d/cloudflared restart } diff --git a/net/rclone/Makefile b/net/rclone/Makefile index 513b358bce..96af98b447 100644 --- a/net/rclone/Makefile +++ b/net/rclone/Makefile @@ -6,12 +6,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=rclone -PKG_VERSION:=1.66.0 +PKG_VERSION:=1.68.0 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/rclone/rclone/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=9249391867044a0fa4c5a948b46a03b320706b4d5c4d59db9d4aeff8d47cade2 +PKG_HASH:=6e0acbef1c9d21d7a4d53d876c374466de0966f2a1994a8ae448ea0c179ccc6a PKG_LICENSE:=MIT PKG_LICENSE_FILES:=LICENSE diff --git a/net/travelmate/Makefile b/net/travelmate/Makefile index 8747c030b0..836f3bf80d 100644 --- a/net/travelmate/Makefile +++ b/net/travelmate/Makefile @@ -6,8 +6,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=travelmate -PKG_VERSION:=2.1.2 -PKG_RELEASE:=6 +PKG_VERSION:=2.1.3 +PKG_RELEASE:=1 PKG_LICENSE:=GPL-3.0-or-later PKG_MAINTAINER:=Dirk Brenken @@ -22,7 +22,7 @@ define Package/travelmate endef define Package/travelmate/description -A wlan connection manager for travel router. +A wlan connection manager for travel routers. Please see https://github.com/openwrt/packages/blob/master/net/travelmate/files/README.md for further information. endef diff --git a/net/travelmate/files/README.md b/net/travelmate/files/README.md index 1b1f065a5d..f776e1caf0 100644 --- a/net/travelmate/files/README.md +++ b/net/travelmate/files/README.md @@ -191,5 +191,15 @@ Please join the travelmate discussion in this [forum thread](https://forum.lede- * stop the travelmate daemon with _/etc/init.d/travelmate stop_ * remove the travelmate package (_opkg remove luci-app-travelmate_, _opkg remove travelmate_) +## Donations +You like this project - is there a way to donate? Generally speaking "No" - I have a well-paying full-time job and my OpenWrt projects are just a hobby of mine in my spare time. + +If you still insist to donate some bucks ... +* I would be happy if you put your money in kind into other, social projects in your area, e.g. a children's hospice +* Let's meet and invite me for a coffee if you are in my area, the “Markgräfler Land” in southern Germany or in Switzerland (Basel) +* Send your money to my [PayPal account](https://www.paypal.me/DirkBrenken) and I will collect your donations over the year to support various social projects in my area + +No matter what you decide - thank you very much for your support! + Have fun! Dirk diff --git a/net/travelmate/files/travelmate.mail b/net/travelmate/files/travelmate.mail index 0b12866b60..243d1fd3e3 100755 --- a/net/travelmate/files/travelmate.mail +++ b/net/travelmate/files/travelmate.mail @@ -18,11 +18,14 @@ trm_mailreceiver="$(uci_get travelmate global trm_mailreceiver)" trm_mailprofile="$(uci_get travelmate global trm_mailprofile "trm_notify")" trm_mailsender="$(uci_get travelmate global trm_mailsender "no-reply@travelmate")" trm_rtfile="$(uci_get travelmate global trm_rtfile "/tmp/trm_runtime.json")" -trm_mailpgm="$(command -v msmtp)" +trm_mailcmd="$(command -v msmtp)" +trm_ubuscmd="$(command -v ubus)" +trm_jsoncmd="$(command -v jsonfilter)" trm_logger="$(command -v logger)" +trm_ver="$("${trm_ubuscmd}" -S call rpc-sys packagelist '{ "all": true }' 2>/dev/null | "${trm_jsoncmd}" -ql1 -e '@.packages.travelmate')" if [ -z "${trm_mailreceiver}" ]; then - "${trm_logger}" -p "err" -t "trm-mail [${$}]" "please set the mail receiver with the 'trm_mailreceiver' option" 2>/dev/null + "${trm_logger}" -p "err" -t "trm-${trm_ver}[${$}]" "please set the mail receiver with the 'trm_mailreceiver' option" 2>/dev/null exit 1 fi @@ -50,5 +53,5 @@ trm_mailtext="${trm_mailtext}" # send mail # -printf "%b" "${trm_mailhead}${trm_mailtext}" 2>/dev/null | "${trm_mailpgm}" ${debug} -a "${trm_mailprofile}" "${trm_mailreceiver}" >/dev/null 2>&1 -"${trm_logger}" -p "info" -t "trm-mail [${$}]" "mail sent to '${trm_mailreceiver}' with rc '${?}'" 2>/dev/null +printf "%b" "${trm_mailhead}${trm_mailtext}" 2>/dev/null | "${trm_mailcmd}" ${debug} -a "${trm_mailprofile}" "${trm_mailreceiver}" >/dev/null 2>&1 +"${trm_logger}" -p "info" -t "trm-${trm_ver}[${$}]" "mail sent to '${trm_mailreceiver}' with rc '${?}'" 2>/dev/null diff --git a/net/travelmate/files/travelmate.sh b/net/travelmate/files/travelmate.sh index 39660dd81b..a554399f3b 100755 --- a/net/travelmate/files/travelmate.sh +++ b/net/travelmate/files/travelmate.sh @@ -669,6 +669,11 @@ f_check() { { [ "${mode}" = "dev" ] && { [ "${status}" = "false" ] || { [ "${trm_ifstatus}" != "${status}" ] && [ "${enabled}" = "0" ]; }; }; }; then f_wifi fi + if [ "${mode}" = "sta" ]; then + "${trm_ubuscmd}" -S call network.interface."${trm_iface}" down >/dev/null 2>&1 + "${trm_ubuscmd}" -S call network.interface."${trm_iface}" up >/dev/null 2>&1 + fi + while [ "${wait_time}" -le "${trm_maxwait}" ]; do [ "${wait_time}" -gt "0" ] && sleep 1 wait_time="$((wait_time + 1))" @@ -1025,11 +1030,10 @@ else f_log "err" "system libraries not found" fi -# force ntp restart/sync +# force ntp hotplug event/time sync # -if [ -f "/etc/init.d/sysntpd" ] && [ ! -s "${trm_ntpfile}" ]; then - /etc/init.d/sysntpd restart >/dev/null 2>&1 - f_log "debug" "ntp time sync requested" +if [ ! -s "${trm_ntpfile}" ]; then + "${trm_ubuscmd}" -S call hotplug.ntp call '{ "env": [ "ACTION=stratum" ] }' >/dev/null 2>&1 fi # control travelmate actions diff --git a/net/travelmate/files/travelmate_ntp.hotplug b/net/travelmate/files/travelmate_ntp.hotplug index 5195c03dc1..efe7180f36 100755 --- a/net/travelmate/files/travelmate_ntp.hotplug +++ b/net/travelmate/files/travelmate_ntp.hotplug @@ -1,6 +1,6 @@ #!/bin/sh # ntp hotplug script for travelmate -# Copyright (c) 2020-2023 Dirk Brenken (dev@brenken.org) +# Copyright (c) 2020-2024 Dirk Brenken (dev@brenken.org) # This is free software, licensed under the GNU General Public License v3. # set (s)hellcheck exceptions @@ -8,9 +8,12 @@ trm_init="/etc/init.d/travelmate" trm_ntpfile="/var/state/travelmate.ntp" -trm_logger="$(command -v logger)" if [ "${ACTION}" = "stratum" ] && [ ! -s "${trm_ntpfile}" ] && "${trm_init}" enabled; then printf "%s" "$(date "+%Y.%m.%d-%H:%M:%S")" > "${trm_ntpfile}" - "${trm_logger}" -p "info" -t "trm-ntp [${$}]" "get ntp time sync" + trm_ubuscmd="$(command -v ubus)" + trm_jsoncmd="$(command -v jsonfilter)" + trm_logger="$(command -v logger)" + trm_ver="$("${trm_ubuscmd}" -S call rpc-sys packagelist '{ "all": true }' 2>/dev/null | "${trm_jsoncmd}" -ql1 -e '@.packages.travelmate')" + "${trm_logger}" -p "info" -t "trm-${trm_ver}[${$}]" "get ntp time sync" fi diff --git a/net/v2ray-core/Makefile b/net/v2ray-core/Makefile index 3c8488dd97..2bb7aaaa3d 100644 --- a/net/v2ray-core/Makefile +++ b/net/v2ray-core/Makefile @@ -5,12 +5,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=v2ray-core -PKG_VERSION:=5.16.1 +PKG_VERSION:=5.18.0 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/v2fly/v2ray-core/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=e5d61b97168ebdf6da3d672ab40abe5b22951d46997072ca1ee497a3aa47ba05 +PKG_HASH:=15acf65228867d47dcab27f87af048a2f0e6ed5d347a2e68730d30ae2a3871eb PKG_LICENSE:=MIT PKG_LICENSE_FILES:=LICENSE diff --git a/net/v2ray-geodata/Makefile b/net/v2ray-geodata/Makefile index 26f35c4ac9..e3929eb24f 100644 --- a/net/v2ray-geodata/Makefile +++ b/net/v2ray-geodata/Makefile @@ -12,31 +12,31 @@ PKG_MAINTAINER:=Tianling Shen include $(INCLUDE_DIR)/package.mk -GEOIP_VER:=202408290048 +GEOIP_VER:=202409120050 GEOIP_FILE:=geoip.dat.$(GEOIP_VER) define Download/geoip URL:=https://github.com/v2fly/geoip/releases/download/$(GEOIP_VER)/ URL_FILE:=geoip.dat FILE:=$(GEOIP_FILE) - HASH:=428f8d3c2f65be51afa945a3464b44fde82d509f5df3f1383a5902d1706d1fe4 + HASH:=4ec83c46f84b3efb9856903e7c10d6c21f6515b9e656575c483dcf2a3d80f916 endef -GEOSITE_VER:=20240829063032 +GEOSITE_VER:=20240914091803 GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER) define Download/geosite URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/ URL_FILE:=dlc.dat FILE:=$(GEOSITE_FILE) - HASH:=acabd214b0a05363f678baba64dfb745ffc551a9dea6d8c15abe0821a0cac5e9 + HASH:=c171f61d3ba8e0dcf31a9548e9fd928a9416e064ad9417664eadda8d25eb6ad9 endef -GEOSITE_IRAN_VER:=202408260030 +GEOSITE_IRAN_VER:=202409160034 GEOSITE_IRAN_FILE:=iran.dat.$(GEOSITE_IRAN_VER) define Download/geosite-ir URL:=https://github.com/bootmortis/iran-hosted-domains/releases/download/$(GEOSITE_IRAN_VER)/ URL_FILE:=iran.dat FILE:=$(GEOSITE_IRAN_FILE) - HASH:=d95bd88c33b41514400ced2ec117834dd325c24a46c04e82f8c04ef040648f14 + HASH:=d4f7a05bb3c81a52a511a7ea5d2d865adadcb2d0ccdf4dd3a7bca5851d1e9d27 endef define Package/v2ray-geodata/template diff --git a/utils/nano/Makefile b/utils/nano/Makefile index 226625aaf3..5cbd349adb 100644 --- a/utils/nano/Makefile +++ b/utils/nano/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=nano -PKG_VERSION:=8.1 +PKG_VERSION:=8.2 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=@GNU/nano -PKG_HASH:=93b3e3e9155ae389fe9ccf9cb7ab380eac29602835ba3077b22f64d0f0cbe8cb +PKG_HASH:=d5ad07dd862facae03051c54c6535e54c7ed7407318783fcad1ad2d7076fffeb PKG_LICENSE:=GPL-3.0-or-later PKG_LICENSE_FILES:=COPYING