Version in base suite: 0.1.6-1+deb13u1 Base version: xdg-dbus-proxy_0.1.6-1+deb13u1 Target version: xdg-dbus-proxy_0.1.6-1+deb13u2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/x/xdg-dbus-proxy/xdg-dbus-proxy_0.1.6-1+deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/x/xdg-dbus-proxy/xdg-dbus-proxy_0.1.6-1+deb13u2.dsc changelog | 12 patches/GHSA-r7hp-698j-2h6c/Revert-Don-t-require-TALK-permission-for-broadcast-rules.patch | 83 ++++ patches/series | 10 patches/tests/tests-Add-access-control-rules-and-connections-that-match.patch | 150 +++++++ patches/tests/tests-Assert-that-ability-to-own-names-is-enforced.patch | 132 ++++++ patches/tests/tests-Avoid-a-warning-with-newer-GLib.patch | 26 + patches/tests/tests-Factor-out-fixture_start_proxy.patch | 144 +++++++ patches/tests/tests-Filter-and-count-incoming-messages-on-each-unsandbo.patch | 195 ++++++++++ patches/tests/tests-Optionally-run-a-dbus-monitor.patch | 66 +++ patches/tests/tests-Send-xdg-dbus-proxy-stdout-to-a-copy-of-its-stderr.patch | 34 + patches/tests/tests-Test-method-calls-being-blocked-or-allowed.patch | 172 ++++++++ patches/tests/tests-Test-that-messages-from-outside-sandbox-are-not-rec.patch | 191 +++++++++ 12 files changed, 1215 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmphuwx7suq/xdg-dbus-proxy_0.1.6-1+deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmphuwx7suq/xdg-dbus-proxy_0.1.6-1+deb13u2.dsc: no acceptable signature found diff -Nru xdg-dbus-proxy-0.1.6/debian/changelog xdg-dbus-proxy-0.1.6/debian/changelog --- xdg-dbus-proxy-0.1.6/debian/changelog 2026-04-10 22:31:23.000000000 +0000 +++ xdg-dbus-proxy-0.1.6/debian/changelog 2026-08-11 12:43:30.000000000 +0000 @@ -1,3 +1,15 @@ +xdg-dbus-proxy (0.1.6-1+deb13u2) trixie-security; urgency=high + + * d/p/GHSA-r7hp-698j-2h6c/*.patch: + Fix a vulnerability in access control for receiving broadcasts. + In 0.1.6 and 0.1.7, a malicious or compromised Flatpak app could + receive any broadcast D-Bus message on the session bus or the AT-SPI + bus, leading to unintended information disclosure. + * d/p/tests/*.patch: + Add automated test coverage for message filtering + + -- Simon McVittie Tue, 11 Aug 2026 13:43:30 +0100 + xdg-dbus-proxy (0.1.6-1+deb13u1) trixie-security; urgency=high * d/gbp.conf: Configure for trixie diff -Nru xdg-dbus-proxy-0.1.6/debian/patches/GHSA-r7hp-698j-2h6c/Revert-Don-t-require-TALK-permission-for-broadcast-rules.patch xdg-dbus-proxy-0.1.6/debian/patches/GHSA-r7hp-698j-2h6c/Revert-Don-t-require-TALK-permission-for-broadcast-rules.patch --- xdg-dbus-proxy-0.1.6/debian/patches/GHSA-r7hp-698j-2h6c/Revert-Don-t-require-TALK-permission-for-broadcast-rules.patch 1970-01-01 00:00:00.000000000 +0000 +++ xdg-dbus-proxy-0.1.6/debian/patches/GHSA-r7hp-698j-2h6c/Revert-Don-t-require-TALK-permission-for-broadcast-rules.patch 2026-08-11 12:43:30.000000000 +0000 @@ -0,0 +1,83 @@ +From: Simon McVittie +Date: Sun, 26 Jul 2026 14:03:16 +0100 +Subject: Revert "Don't require TALK permission for broadcast rules" +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 8bit + +The commit reverted here appears to have been based on a misunderstanding +of how `--broadcast` rules were designed to work. Adding a `--broadcast` or +`--call` rule gives the sandboxed D-Bus client a *limited* version of the +TALK permission: it is allowed to call methods or listen for broadcasts +(as appropriate), and it is allowed to call `StartServiceByName()` +for the requested bus name. + +However, when the rules +`--broadcast=org.a11y.atspi.Registry.EventListenerRegistered=@/org/a11y/atspi/registry` +and +`--broadcast=org.a11y.atspi.Registry.EventListenerDeregistered=@/org/a11y/atspi/registry` +were added to Flatpak in https://github.com/flatpak/flatpak/pull/5828, +the meaning of those rules was not as intended: they're matching bus names +`org.a11y.atspi.Registry.EventListenerRegistered` and …Deregistered`, +which in practice don't actually exist. As a result, the rules didn't +appear to work until the Flatpak contributor either added `--talk` +(which is *unrestricted* TALK access, clearly not desired), or altered +the xdg-dbus-proxy code so that `--broadcast` would bypass the intended +broadcast filtering. + +Allowing broadcasts in the presence of any rule with the TALK policy +meant that adding *any* `--broadcast` rule would allow receiving +*all* broadcasts, regardless of object path, interface or member name +(any_filter_matches() would not be called), which was clearly not as +intended. + +An attacker could use this to receive host-side broadcasts that are not +intended to be visible to the sandboxed app, weakening the sandbox. For +example, a malicious or compromised Flatpak app could receive any +broadcast on the session bus or the AT-SPI bus. + +Undo this change. Instead, we should fix the match rules used on the +AT-SPI bus by Flatpak to what they were intended to be, which I believe +means +`--broadcast=org.a11y.atspi.Registry=org.a11y.atspi.Registry.EventListenerRegistered@/org/a11y/atspi/registry` +and the same for `…Deregistered`. If non-Flatpak app frameworks use +xdg-dbus-proxy, they might need similar changes. + +Potential collateral damage from this change is that some Flatpak apps +might have accidentally been relying on the ability to receive all +broadcast signals on the session bus, which they would have been able +to do since Flatpak 1.15.9. If such apps exist, they will need to be +updated to add explicit `--talk-name` rules for the relevant D-Bus names. +Again, if non-Flatpak app frameworks use xdg-dbus-proxy, those frameworks' +apps might need similar changes. + +This reverts commit 029784535ed9cbec6c431b12ba1a9eca6c147055. + +Bug: https://github.com/flatpak/xdg-dbus-proxy/security/advisories/GHSA-r7hp-698j-2h6c +Signed-off-by: Simon McVittie +Origin: upstream, 0.1.8 +--- + flatpak-proxy.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/flatpak-proxy.c b/flatpak-proxy.c +index 8a4d597..a97e62b 100644 +--- a/flatpak-proxy.c ++++ b/flatpak-proxy.c +@@ -2806,11 +2806,11 @@ got_buffer_from_bus (FlatpakProxyClient *client, ProxySide *side, Buffer *buffer + policy = flatpak_proxy_client_get_max_policy_and_matched (client, header->sender, &filters); + + if (policy == FLATPAK_POLICY_OWN || +- policy == FLATPAK_POLICY_TALK || +- any_filter_matches (filters, FILTER_TYPE_BROADCAST, +- header->path, +- header->interface, +- header->member)) ++ (policy == FLATPAK_POLICY_TALK && ++ any_filter_matches (filters, FILTER_TYPE_BROADCAST, ++ header->path, ++ header->interface, ++ header->member))) + filtered = FALSE; + + if (filtered) diff -Nru xdg-dbus-proxy-0.1.6/debian/patches/series xdg-dbus-proxy-0.1.6/debian/patches/series --- xdg-dbus-proxy-0.1.6/debian/patches/series 2026-04-10 22:31:23.000000000 +0000 +++ xdg-dbus-proxy-0.1.6/debian/patches/series 2026-08-11 12:43:30.000000000 +0000 @@ -1 +1,11 @@ Improve-detection-of-eavesdrop-true.patch +tests/tests-Send-xdg-dbus-proxy-stdout-to-a-copy-of-its-stderr.patch +tests/tests-Avoid-a-warning-with-newer-GLib.patch +tests/tests-Optionally-run-a-dbus-monitor.patch +tests/tests-Factor-out-fixture_start_proxy.patch +tests/tests-Add-access-control-rules-and-connections-that-match.patch +tests/tests-Assert-that-ability-to-own-names-is-enforced.patch +tests/tests-Filter-and-count-incoming-messages-on-each-unsandbo.patch +tests/tests-Test-method-calls-being-blocked-or-allowed.patch +GHSA-r7hp-698j-2h6c/Revert-Don-t-require-TALK-permission-for-broadcast-rules.patch +tests/tests-Test-that-messages-from-outside-sandbox-are-not-rec.patch diff -Nru xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Add-access-control-rules-and-connections-that-match.patch xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Add-access-control-rules-and-connections-that-match.patch --- xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Add-access-control-rules-and-connections-that-match.patch 1970-01-01 00:00:00.000000000 +0000 +++ xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Add-access-control-rules-and-connections-that-match.patch 2026-08-11 12:43:30.000000000 +0000 @@ -0,0 +1,150 @@ +From: Simon McVittie +Date: Sun, 26 Jul 2026 11:21:12 +0100 +Subject: tests: Add access-control rules, + and connections that match those rules + +Signed-off-by: Simon McVittie +Origin: upstream, 0.1.8 +--- + tests/test-proxy.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 100 insertions(+) + +diff --git a/tests/test-proxy.c b/tests/test-proxy.c +index 938a4a4..ed833c8 100644 +--- a/tests/test-proxy.c ++++ b/tests/test-proxy.c +@@ -34,6 +34,31 @@ + #define DBUS_PATH_DBUS "/org/freedesktop/DBus" + #define DBUS_INTERFACE_DBUS "org.freedesktop.DBus" + ++#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 ++#define DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2 ++#define DBUS_REQUEST_NAME_REPLY_EXISTS 3 ++#define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4 ++ ++#define CANNOT_ACCESS_NAME "com.example.CannotAccess" ++#define CAN_SEE_NAME "com.example.CanSee" ++#define CAN_TALK_NAME "com.example.CanTalk" ++#define CAN_OWN_NAME "com.example.CanOwn" ++#define CAN_CALL_ANYTHING_NAME "com.example.CanCallAny" ++#define CAN_CALL_SOME_NAME "com.example.CanCallSome" ++#define CAN_RECEIVE_ANYTHING_NAME "com.example.CanReceiveAny" ++#define CAN_RECEIVE_SOME_NAME "com.example.CanReceiveSome" ++ ++#define EXAMPLE_IFACE "net.example.AnyInterface" ++#define EXAMPLE_METHOD "Echo" ++#define EXAMPLE_SIGNAL "Shouted" ++#define EXAMPLE_PATH "/path" ++#define CAN_CALL_SOME_IFACE "org.example.CanCallThis" ++#define CAN_CALL_SOME_METHOD "OnlyThisMethod" ++#define CAN_CALL_SOME_PATH "/only/this/path" ++#define CAN_RECEIVE_SOME_IFACE "org.example.CanReceiveThis" ++#define CAN_RECEIVE_SOME_SIGNAL "JustThisSignal" ++#define CAN_RECEIVE_SOME_PATH "/just/this/path" ++ + typedef struct + { + GDBusConnection *conn; +@@ -60,6 +85,14 @@ connection_clear (Connection *self) + typedef struct + { + Connection proxied; ++ Connection cannot_access_conn; ++ Connection can_see_conn; ++ Connection can_talk_conn; ++ Connection can_own_conn; ++ Connection can_call_anything_conn; ++ Connection can_call_some_conn; ++ Connection can_receive_anything_conn; ++ Connection can_receive_some_conn; + GSubprocess *dbus_daemon; + GSubprocess *monitor; + GSubprocess *proxy; +@@ -76,6 +109,55 @@ typedef struct + int dummy; + } Config; + ++/* ++ * Open a direct connection to the bus ++ */ ++static void ++fixture_connect (Fixture *f, ++ Connection *conn, ++ const char *name) ++{ ++ g_autoptr(GError) error = NULL; ++ ++ g_return_if_fail (conn != NULL); ++ g_return_if_fail (conn->conn == NULL); ++ conn->conn = g_dbus_connection_new_for_address_sync (f->dbus_address, ++ (G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT ++ | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION), ++ NULL, /* observer */ ++ NULL, /* cancellable */ ++ &error); ++ g_assert_no_error (error); ++ g_assert_nonnull (conn->conn); ++ conn->unique_name = g_dbus_connection_get_unique_name (conn->conn); ++ ++ if (name != NULL) ++ { ++ g_autoptr(GVariant) tuple = NULL; ++ guint32 result = 0; ++ ++ tuple = g_dbus_connection_call_sync (conn->conn, ++ DBUS_SERVICE_DBUS, ++ DBUS_PATH_DBUS, ++ DBUS_INTERFACE_DBUS, ++ "RequestName", ++ g_variant_new ("(su)", ++ name, ++ (G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT ++ | G_BUS_NAME_OWNER_FLAGS_REPLACE ++ | G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE)), ++ G_VARIANT_TYPE ("(u)"), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, ++ NULL, /* cancellable */ ++ &error); ++ g_assert_no_error (error); ++ g_assert_nonnull (tuple); ++ g_variant_get (tuple, "(u)", &result); ++ g_assert_cmpuint (result, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); ++ } ++} ++ + static void + setup (Fixture *f, + gconstpointer context G_GNUC_UNUSED) +@@ -148,6 +230,15 @@ setup (Fixture *f, + f->proxy_socket = g_build_filename (f->temp_directory, "proxy", NULL); + escaped = g_dbus_address_escape_value (f->proxy_socket); + f->proxy_address = g_strdup_printf ("unix:path=%s", escaped); ++ ++ fixture_connect (f, &f->cannot_access_conn, CANNOT_ACCESS_NAME); ++ fixture_connect (f, &f->can_see_conn, CAN_SEE_NAME); ++ fixture_connect (f, &f->can_talk_conn, CAN_TALK_NAME); ++ fixture_connect (f, &f->can_own_conn, CAN_OWN_NAME); ++ fixture_connect (f, &f->can_call_anything_conn, CAN_CALL_ANYTHING_NAME); ++ fixture_connect (f, &f->can_call_some_conn, CAN_CALL_SOME_NAME); ++ fixture_connect (f, &f->can_receive_anything_conn, CAN_RECEIVE_ANYTHING_NAME); ++ fixture_connect (f, &f->can_receive_some_conn, CAN_RECEIVE_SOME_NAME); + } + + enum +@@ -184,6 +275,15 @@ fixture_start_proxy (Fixture *f) + "--fd=3", + f->dbus_address, + f->proxy_socket, ++ "--filter", ++ "--log", ++ "--see=" CAN_SEE_NAME, ++ "--talk=" CAN_TALK_NAME, ++ "--own=" CAN_OWN_NAME, ++ "--call=" CAN_CALL_ANYTHING_NAME "=*", ++ "--call=" CAN_CALL_SOME_NAME "=" CAN_CALL_SOME_IFACE "." CAN_CALL_SOME_METHOD "@" CAN_CALL_SOME_PATH, ++ "--broadcast=" CAN_RECEIVE_ANYTHING_NAME "=*", ++ "--broadcast=" CAN_RECEIVE_SOME_NAME "=" CAN_RECEIVE_SOME_IFACE "." CAN_RECEIVE_SOME_SIGNAL "@" CAN_RECEIVE_SOME_PATH, + NULL); + g_assert_no_error (error); + g_assert_nonnull (f->proxy); diff -Nru xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Assert-that-ability-to-own-names-is-enforced.patch xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Assert-that-ability-to-own-names-is-enforced.patch --- xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Assert-that-ability-to-own-names-is-enforced.patch 1970-01-01 00:00:00.000000000 +0000 +++ xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Assert-that-ability-to-own-names-is-enforced.patch 2026-08-11 12:43:30.000000000 +0000 @@ -0,0 +1,132 @@ +From: Simon McVittie +Date: Sun, 26 Jul 2026 11:49:34 +0100 +Subject: tests: Assert that ability to own names is enforced + +Signed-off-by: Simon McVittie +Origin: upstream, 0.1.8 +--- + tests/test-proxy.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 104 insertions(+) + +diff --git a/tests/test-proxy.c b/tests/test-proxy.c +index ed833c8..d90592d 100644 +--- a/tests/test-proxy.c ++++ b/tests/test-proxy.c +@@ -341,6 +341,109 @@ test_basics (Fixture *f, + g_assert_true (found); + } + ++typedef struct ++{ ++ const char *name; ++ gboolean can_own; ++ gboolean can_see; ++} OwnTest; ++ ++static const OwnTest own_tests[] = ++{ ++ { CANNOT_ACCESS_NAME, .can_own = FALSE, .can_see = FALSE }, ++ { CAN_SEE_NAME, .can_own = FALSE, .can_see = TRUE }, ++ { CAN_TALK_NAME, .can_own = FALSE, .can_see = TRUE }, ++ { CAN_OWN_NAME, .can_own = TRUE, .can_see = TRUE }, ++ { CAN_CALL_ANYTHING_NAME, .can_own = FALSE, .can_see = TRUE }, ++ { CAN_CALL_SOME_NAME, .can_own = FALSE, .can_see = TRUE }, ++ { CAN_RECEIVE_ANYTHING_NAME, .can_own = FALSE, .can_see = TRUE }, ++ { CAN_RECEIVE_SOME_NAME, .can_own = FALSE, .can_see = TRUE }, ++}; ++ ++static void ++test_own (Fixture *f, ++ gconstpointer context G_GNUC_UNUSED) ++{ ++ alarm (30); ++ fixture_start_proxy (f); ++ ++ for (size_t i = 0; i < G_N_ELEMENTS (own_tests); i++) ++ { ++ const OwnTest *t = &own_tests[i]; ++ g_autoptr(GError) error = NULL; ++ g_autoptr(GVariant) tuple = NULL; ++ const char *owner = NULL; ++ ++ g_test_message ("#%zu: sandboxed connection %s be allowed to own %s", ++ i, t->can_own ? "should" : "should not", t->name); ++ ++ tuple = g_dbus_connection_call_sync (f->proxied.conn, ++ DBUS_SERVICE_DBUS, ++ DBUS_PATH_DBUS, ++ DBUS_INTERFACE_DBUS, ++ "RequestName", ++ g_variant_new ("(su)", ++ t->name, ++ (G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT ++ | G_BUS_NAME_OWNER_FLAGS_REPLACE ++ | G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE)), ++ G_VARIANT_TYPE ("(u)"), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, ++ NULL, /* cancellable */ ++ &error); ++ ++ if (tuple != NULL) ++ g_test_message ("-> Was allowed"); ++ else ++ g_test_message ("-> Was not allowed: %s", error->message); ++ ++ if (t->can_own) ++ { ++ guint32 result = 0; ++ ++ g_assert_no_error (error); ++ g_assert_nonnull (tuple); ++ g_variant_get (tuple, "(u)", &result); ++ g_assert_cmpuint (result, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); ++ } ++ else if (t->can_see) ++ { ++ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED); ++ } ++ else ++ { ++ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN); ++ } ++ ++ g_clear_error (&error); ++ g_clear_pointer (&tuple, g_variant_unref); ++ ++ /* Use a different connection to check who actually owns the name */ ++ tuple = g_dbus_connection_call_sync (f->cannot_access_conn.conn, ++ DBUS_SERVICE_DBUS, ++ DBUS_PATH_DBUS, ++ DBUS_INTERFACE_DBUS, ++ "GetNameOwner", ++ g_variant_new ("(s)", t->name), ++ G_VARIANT_TYPE ("(s)"), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, ++ NULL, /* cancellable */ ++ NULL); ++ ++ if (tuple != NULL) ++ g_variant_get (tuple, "(&s)", &owner); ++ else ++ owner = ""; ++ ++ if (t->can_own) ++ g_assert_cmpstr (owner, ==, f->proxied.unique_name); ++ else ++ g_assert_cmpstr (owner, !=, f->proxied.unique_name); ++ } ++} ++ + static void + teardown (Fixture *f, + gconstpointer context G_GNUC_UNUSED) +@@ -408,6 +511,7 @@ main (int argc, + g_test_init (&argc, &argv, NULL); + + g_test_add ("/basics", Fixture, NULL, setup, test_basics, teardown); ++ g_test_add ("/own", Fixture, NULL, setup, test_own, teardown); + + return g_test_run (); + } diff -Nru xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Avoid-a-warning-with-newer-GLib.patch xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Avoid-a-warning-with-newer-GLib.patch --- xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Avoid-a-warning-with-newer-GLib.patch 1970-01-01 00:00:00.000000000 +0000 +++ xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Avoid-a-warning-with-newer-GLib.patch 2026-08-11 12:43:30.000000000 +0000 @@ -0,0 +1,26 @@ +From: Simon McVittie +Date: Sun, 26 Jul 2026 11:48:21 +0100 +Subject: tests: Avoid a warning with newer GLib + +Signed-off-by: Simon McVittie +Origin: upstream, 0.1.8 +--- + tests/test-proxy.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/tests/test-proxy.c b/tests/test-proxy.c +index df1f00b..ae106d9 100644 +--- a/tests/test-proxy.c ++++ b/tests/test-proxy.c +@@ -138,7 +138,11 @@ test_basics (Fixture *f, + + alarm (30); + ++#if GLIB_CHECK_VERSION (2, 78, 0) ++ g_unix_open_pipe (sync_pipe, O_CLOEXEC, &error); ++#else + g_unix_open_pipe (sync_pipe, FD_CLOEXEC, &error); ++#endif + g_assert_no_error (error); + f->sync_pipe = sync_pipe[READ_END]; + diff -Nru xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Factor-out-fixture_start_proxy.patch xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Factor-out-fixture_start_proxy.patch --- xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Factor-out-fixture_start_proxy.patch 1970-01-01 00:00:00.000000000 +0000 +++ xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Factor-out-fixture_start_proxy.patch 2026-08-11 12:43:30.000000000 +0000 @@ -0,0 +1,144 @@ +From: Simon McVittie +Date: Sun, 26 Jul 2026 14:27:10 +0100 +Subject: tests: Factor out fixture_start_proxy() + +Signed-off-by: Simon McVittie +Origin: upstream, 0.1.8 +--- + tests/test-proxy.c | 80 ++++++++++++++++++++++++++++++++++-------------------- + 1 file changed, 51 insertions(+), 29 deletions(-) + +diff --git a/tests/test-proxy.c b/tests/test-proxy.c +index 772fad5..938a4a4 100644 +--- a/tests/test-proxy.c ++++ b/tests/test-proxy.c +@@ -36,7 +36,30 @@ + + typedef struct + { +- GDBusConnection *proxied_conn; ++ GDBusConnection *conn; ++ const char *unique_name; ++} Connection; ++ ++static void ++connection_clear (Connection *self) ++{ ++ if (self->conn != NULL) ++ { ++ g_autoptr(GError) error = NULL; ++ ++ g_dbus_connection_close_sync (self->conn, NULL, &error); ++ ++ if (error != NULL) ++ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED); ++ } ++ ++ self->unique_name = NULL; ++ g_clear_object (&self->conn); ++} ++ ++typedef struct ++{ ++ Connection proxied; + GSubprocess *dbus_daemon; + GSubprocess *monitor; + GSubprocess *proxy; +@@ -135,21 +158,13 @@ enum + }; + + static void +-test_basics (Fixture *f, +- gconstpointer context G_GNUC_UNUSED) ++fixture_start_proxy (Fixture *f) + { + g_autoptr(GSubprocessLauncher) launcher = NULL; + g_autoptr(GError) error = NULL; +- g_autoptr(GVariant) tuple = NULL; +- g_auto(GStrv) strv = NULL; +- const char *proxied_name; + int sync_pipe[PIPE_FDS]; + char buf; + ssize_t bytes_read; +- gsize i; +- gboolean found; +- +- alarm (30); + + #if GLIB_CHECK_VERSION (2, 78, 0) + g_unix_open_pipe (sync_pipe, O_CLOEXEC, &error); +@@ -177,15 +192,32 @@ test_basics (Fixture *f, + bytes_read = read (sync_pipe[READ_END], &buf, 1); + g_assert_cmpint (bytes_read, ==, 1); + +- f->proxied_conn = g_dbus_connection_new_for_address_sync (f->proxy_address, +- G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT +- | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION, +- NULL, NULL, &error); ++ f->proxied.conn = g_dbus_connection_new_for_address_sync (f->proxy_address, ++ (G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT ++ | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION), ++ NULL, /* observer */ ++ NULL, /* cancellable */ ++ &error); + g_assert_no_error (error); +- g_assert_nonnull (f->proxied_conn); +- proxied_name = g_dbus_connection_get_unique_name (f->proxied_conn); ++ g_assert_nonnull (f->proxied.conn); ++ f->proxied.unique_name = g_dbus_connection_get_unique_name (f->proxied.conn); ++} + +- tuple = g_dbus_connection_call_sync (f->proxied_conn, DBUS_SERVICE_DBUS, ++static void ++test_basics (Fixture *f, ++ gconstpointer context G_GNUC_UNUSED) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(GVariant) tuple = NULL; ++ g_auto(GStrv) strv = NULL; ++ gsize i; ++ gboolean found; ++ ++ alarm (30); ++ ++ fixture_start_proxy (f); ++ ++ tuple = g_dbus_connection_call_sync (f->proxied.conn, DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, + "ListNames", NULL, + G_VARIANT_TYPE ("(as)"), +@@ -202,7 +234,7 @@ test_basics (Fixture *f, + { + g_test_message ("ListNames(): %s", strv[i]); + +- if (g_strcmp0 (strv[i], proxied_name) == 0) ++ if (g_strcmp0 (strv[i], f->proxied.unique_name) == 0) + found = TRUE; + } + +@@ -243,16 +275,7 @@ teardown (Fixture *f, + g_assert_no_error (error); + } + +- if (f->proxied_conn != NULL) +- { +- g_dbus_connection_close_sync (f->proxied_conn, NULL, &error); +- +- if (error != NULL) +- { +- g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED); +- g_clear_error (&error); +- } +- } ++ connection_clear (&f->proxied); + + if (f->proxy_socket != NULL) + { +@@ -271,7 +294,6 @@ teardown (Fixture *f, + } + + g_clear_object (&f->monitor); +- g_clear_object (&f->proxied_conn); + g_clear_object (&f->dbus_daemon); + g_clear_object (&f->proxy); + g_free (f->dbus_address); diff -Nru xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Filter-and-count-incoming-messages-on-each-unsandbo.patch xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Filter-and-count-incoming-messages-on-each-unsandbo.patch --- xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Filter-and-count-incoming-messages-on-each-unsandbo.patch 1970-01-01 00:00:00.000000000 +0000 +++ xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Filter-and-count-incoming-messages-on-each-unsandbo.patch 2026-08-11 12:43:30.000000000 +0000 @@ -0,0 +1,195 @@ +From: Simon McVittie +Date: Sun, 26 Jul 2026 13:09:54 +0100 +Subject: tests: Filter and count incoming messages on each unsandboxed + connection + +Signed-off-by: Simon McVittie +Origin: upstream, 0.1.8 +--- + tests/test-proxy.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 108 insertions(+) + +diff --git a/tests/test-proxy.c b/tests/test-proxy.c +index d90592d..6d10359 100644 +--- a/tests/test-proxy.c ++++ b/tests/test-proxy.c +@@ -62,7 +62,12 @@ + typedef struct + { + GDBusConnection *conn; ++ const char *label; + const char *unique_name; ++ guint filter; ++ int n_method_calls; /* atomic */ ++ int n_unicast_signals; /* atomic */ ++ int n_broadcasts; /* atomic */ + } Connection; + + static void +@@ -72,6 +77,12 @@ connection_clear (Connection *self) + { + g_autoptr(GError) error = NULL; + ++ if (self->filter != 0) ++ { ++ g_dbus_connection_remove_filter (self->conn, self->filter); ++ self->filter = 0; ++ } ++ + g_dbus_connection_close_sync (self->conn, NULL, &error); + + if (error != NULL) +@@ -93,6 +104,7 @@ typedef struct + Connection can_call_some_conn; + Connection can_receive_anything_conn; + Connection can_receive_some_conn; ++ GHashTable *connections_by_name; + GSubprocess *dbus_daemon; + GSubprocess *monitor; + GSubprocess *proxy; +@@ -109,6 +121,76 @@ typedef struct + int dummy; + } Config; + ++static GDBusMessage * ++conn_filter_cb (GDBusConnection *conn, ++ GDBusMessage *message, ++ gboolean incoming, ++ void *user_data) ++{ ++ Connection *conn_info = user_data; ++ ++ g_assert (conn == conn_info->conn); ++ ++ if (incoming) ++ { ++ GDBusMessageType type = g_dbus_message_get_message_type (message); ++ const char *sender = g_dbus_message_get_sender (message); ++ const char *dest = g_dbus_message_get_destination (message); ++ const char *path = g_dbus_message_get_path (message); ++ const char *iface = g_dbus_message_get_interface (message); ++ const char *member = g_dbus_message_get_member (message); ++ ++ g_test_message ("%s got message type %u, from=%s, to=%s, path=%s, %s.%s", ++ conn_info->label, ++ type, ++ sender ?: "(message bus)", ++ dest ?: "(broadcast)", ++ path ?: "(none)", ++ iface ?: "(none)", ++ member ?: "(none)"); ++ ++ switch (type) ++ { ++ case G_DBUS_MESSAGE_TYPE_METHOD_CALL: ++ g_test_message ("%s got method call", conn_info->label); ++ g_atomic_int_inc (&conn_info->n_method_calls); ++ break; ++ ++ case G_DBUS_MESSAGE_TYPE_SIGNAL: ++ if (sender == NULL) ++ { ++ g_test_message ("%s got signal from message bus, ignoring", conn_info->label); ++ } ++ else if (dest != NULL && dest[0] != '\0') ++ { ++ g_test_message ("%s got unicast signal", conn_info->label); ++ g_atomic_int_inc (&conn_info->n_unicast_signals); ++ } ++ else ++ { ++ g_test_message ("%s got broadcast signal", conn_info->label); ++ g_atomic_int_inc (&conn_info->n_broadcasts); ++ } ++ ++ break; ++ ++ case G_DBUS_MESSAGE_TYPE_METHOD_RETURN: ++ g_test_message ("%s got method reply", conn_info->label); ++ break; ++ ++ case G_DBUS_MESSAGE_TYPE_ERROR: ++ g_test_message ("%s got error reply", conn_info->label); ++ break; ++ ++ case G_DBUS_MESSAGE_TYPE_INVALID: ++ default: ++ g_assert_not_reached (); ++ } ++ } ++ ++ return message; ++} ++ + /* + * Open a direct connection to the bus + */ +@@ -121,6 +203,12 @@ fixture_connect (Fixture *f, + + g_return_if_fail (conn != NULL); + g_return_if_fail (conn->conn == NULL); ++ ++ if (name != NULL) ++ conn->label = name; ++ else ++ conn->label = "(unnamed connection)"; ++ + conn->conn = g_dbus_connection_new_for_address_sync (f->dbus_address, + (G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT + | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION), +@@ -155,7 +243,16 @@ fixture_connect (Fixture *f, + g_assert_nonnull (tuple); + g_variant_get (tuple, "(u)", &result); + g_assert_cmpuint (result, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); ++ ++ g_hash_table_replace (f->connections_by_name, ++ g_strdup (name), ++ conn); + } ++ ++ conn->filter = g_dbus_connection_add_filter (conn->conn, ++ conn_filter_cb, ++ conn, ++ NULL); + } + + static void +@@ -231,6 +328,11 @@ setup (Fixture *f, + escaped = g_dbus_address_escape_value (f->proxy_socket); + f->proxy_address = g_strdup_printf ("unix:path=%s", escaped); + ++ f->connections_by_name = g_hash_table_new_full (g_str_hash, ++ g_str_equal, ++ g_free, ++ NULL); ++ + fixture_connect (f, &f->cannot_access_conn, CANNOT_ACCESS_NAME); + fixture_connect (f, &f->can_see_conn, CAN_SEE_NAME); + fixture_connect (f, &f->can_talk_conn, CAN_TALK_NAME); +@@ -292,6 +394,7 @@ fixture_start_proxy (Fixture *f) + bytes_read = read (sync_pipe[READ_END], &buf, 1); + g_assert_cmpint (bytes_read, ==, 1); + ++ f->proxied.label = "Sandboxed connection"; + f->proxied.conn = g_dbus_connection_new_for_address_sync (f->proxy_address, + (G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT + | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION), +@@ -301,6 +404,10 @@ fixture_start_proxy (Fixture *f) + g_assert_no_error (error); + g_assert_nonnull (f->proxied.conn); + f->proxied.unique_name = g_dbus_connection_get_unique_name (f->proxied.conn); ++ f->proxied.filter = g_dbus_connection_add_filter (f->proxied.conn, ++ conn_filter_cb, ++ &f->proxied, ++ NULL); + } + + static void +@@ -496,6 +603,7 @@ teardown (Fixture *f, + g_free (f->temp_directory); + } + ++ g_clear_pointer (&f->connections_by_name, g_hash_table_unref); + g_clear_object (&f->monitor); + g_clear_object (&f->dbus_daemon); + g_clear_object (&f->proxy); diff -Nru xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Optionally-run-a-dbus-monitor.patch xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Optionally-run-a-dbus-monitor.patch --- xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Optionally-run-a-dbus-monitor.patch 1970-01-01 00:00:00.000000000 +0000 +++ xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Optionally-run-a-dbus-monitor.patch 2026-08-11 12:43:30.000000000 +0000 @@ -0,0 +1,66 @@ +From: Simon McVittie +Date: Sun, 26 Jul 2026 14:26:08 +0100 +Subject: tests: Optionally run a dbus-monitor + +This can help when debugging whether particular messages are getting +delivered or suppressed. + +Signed-off-by: Simon McVittie +Origin: upstream, 0.1.8 +--- + tests/test-proxy.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/tests/test-proxy.c b/tests/test-proxy.c +index ae106d9..772fad5 100644 +--- a/tests/test-proxy.c ++++ b/tests/test-proxy.c +@@ -38,6 +38,7 @@ typedef struct + { + GDBusConnection *proxied_conn; + GSubprocess *dbus_daemon; ++ GSubprocess *monitor; + GSubprocess *proxy; + gchar *dbus_address; + gchar *temp_directory; +@@ -102,6 +103,18 @@ setup (Fixture *f, + *newline = '\0'; + f->dbus_address = g_strdup (address_buffer); + ++ if (g_getenv ("TEST_DBUS_MONITOR") != NULL) ++ { ++ g_autoptr(GSubprocessLauncher) monitor_launcher = NULL; ++ ++ monitor_launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE); ++ g_subprocess_launcher_take_stdout_fd (monitor_launcher, dup (STDERR_FILENO)); ++ f->monitor = g_subprocess_launcher_spawn (monitor_launcher, NULL, ++ "dbus-monitor", ++ "--address", f->dbus_address, ++ NULL); ++ } ++ + f->proxy_path = g_getenv ("DBUS_PROXY"); + + if (f->proxy_path == NULL) +@@ -202,6 +215,13 @@ teardown (Fixture *f, + { + g_autoptr(GError) error = NULL; + ++ if (f->monitor != NULL) ++ { ++ g_subprocess_send_signal (f->monitor, SIGTERM); ++ g_subprocess_wait (f->monitor, NULL, &error); ++ g_assert_no_error (error); ++ } ++ + if (f->dbus_daemon != NULL) + { + g_subprocess_send_signal (f->dbus_daemon, SIGTERM); +@@ -250,6 +270,7 @@ teardown (Fixture *f, + g_free (f->temp_directory); + } + ++ g_clear_object (&f->monitor); + g_clear_object (&f->proxied_conn); + g_clear_object (&f->dbus_daemon); + g_clear_object (&f->proxy); diff -Nru xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Send-xdg-dbus-proxy-stdout-to-a-copy-of-its-stderr.patch xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Send-xdg-dbus-proxy-stdout-to-a-copy-of-its-stderr.patch --- xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Send-xdg-dbus-proxy-stdout-to-a-copy-of-its-stderr.patch 1970-01-01 00:00:00.000000000 +0000 +++ xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Send-xdg-dbus-proxy-stdout-to-a-copy-of-its-stderr.patch 2026-08-11 12:43:30.000000000 +0000 @@ -0,0 +1,34 @@ +From: Simon McVittie +Date: Sun, 26 Jul 2026 13:08:55 +0100 +Subject: tests: Send xdg-dbus-proxy stdout to a copy of its stderr + +Otherwise, if we enable `--log` or `G_MESSAGES_DEBUG`, the log messages +on stdout will build up in the stdout pipe until the buffer is full, +leading to a deadlock because we never read from the pipe. + +I think this was originally `G_SUBPROCESS_FLAGS_STDOUT_PIPE` because I'd +originally intended to use --fd=1 for the sync fd, before realising that +stdout is not a suitable fd for that purpose because xdg-dbus-proxy uses +it for other purposes. + +Fixes: e339140bb59dae022cd30b91d785a601aa1f1aeb "Add a simple unit test" +Signed-off-by: Simon McVittie +Origin: upstream, 0.1.8 +--- + tests/test-proxy.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tests/test-proxy.c b/tests/test-proxy.c +index 54a72ed..df1f00b 100644 +--- a/tests/test-proxy.c ++++ b/tests/test-proxy.c +@@ -142,7 +142,8 @@ test_basics (Fixture *f, + g_assert_no_error (error); + f->sync_pipe = sync_pipe[READ_END]; + +- launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE); ++ launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE); ++ g_subprocess_launcher_take_fd (launcher, dup (STDERR_FILENO), STDOUT_FILENO); + g_subprocess_launcher_take_fd (launcher, sync_pipe[WRITE_END], 3); + sync_pipe[WRITE_END] = -1; + diff -Nru xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Test-method-calls-being-blocked-or-allowed.patch xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Test-method-calls-being-blocked-or-allowed.patch --- xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Test-method-calls-being-blocked-or-allowed.patch 1970-01-01 00:00:00.000000000 +0000 +++ xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Test-method-calls-being-blocked-or-allowed.patch 2026-08-11 12:43:30.000000000 +0000 @@ -0,0 +1,172 @@ +From: Simon McVittie +Date: Sun, 26 Jul 2026 14:32:58 +0100 +Subject: tests: Test method calls being blocked or allowed + +Signed-off-by: Simon McVittie +Origin: upstream, 0.1.8 +--- + tests/test-proxy.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 137 insertions(+) + +diff --git a/tests/test-proxy.c b/tests/test-proxy.c +index 6d10359..829b88c 100644 +--- a/tests/test-proxy.c ++++ b/tests/test-proxy.c +@@ -59,6 +59,18 @@ + #define CAN_RECEIVE_SOME_SIGNAL "JustThisSignal" + #define CAN_RECEIVE_SOME_PATH "/just/this/path" + ++static void ++ready_cb (GObject *source_object, ++ GAsyncResult *result, ++ void *user_data) ++{ ++ GAsyncResult **result_p = user_data; ++ ++ g_assert_nonnull (result_p); ++ g_assert_null (*result_p); ++ *result_p = g_object_ref (result); ++} ++ + typedef struct + { + GDBusConnection *conn; +@@ -448,6 +460,130 @@ test_basics (Fixture *f, + g_assert_true (found); + } + ++typedef struct ++{ ++ const char *name; ++ const char *path; ++ const char *iface; ++ const char *method; ++ gboolean can_call; ++ gboolean can_see; ++} CallTest; ++ ++static const CallTest call_tests[] = ++{ ++ { CANNOT_ACCESS_NAME, EXAMPLE_PATH, EXAMPLE_IFACE, EXAMPLE_METHOD, ++ .can_call = FALSE, .can_see = FALSE }, ++ { CAN_SEE_NAME, EXAMPLE_PATH, EXAMPLE_IFACE, EXAMPLE_METHOD, ++ .can_call = FALSE, .can_see = TRUE }, ++ { CAN_TALK_NAME, EXAMPLE_PATH, EXAMPLE_IFACE, EXAMPLE_METHOD, ++ .can_call = TRUE, .can_see = TRUE }, ++ { CAN_OWN_NAME, EXAMPLE_PATH, EXAMPLE_IFACE, EXAMPLE_METHOD, ++ .can_call = TRUE, .can_see = TRUE }, ++ { CAN_RECEIVE_ANYTHING_NAME, EXAMPLE_PATH, EXAMPLE_IFACE, EXAMPLE_METHOD, ++ .can_call = FALSE, .can_see = TRUE }, ++ { CAN_RECEIVE_SOME_NAME, EXAMPLE_PATH, EXAMPLE_IFACE, EXAMPLE_METHOD, ++ .can_call = FALSE, .can_see = TRUE }, ++ ++ { CAN_CALL_ANYTHING_NAME, EXAMPLE_PATH, EXAMPLE_IFACE, EXAMPLE_METHOD, ++ .can_call = TRUE, .can_see = TRUE }, ++ ++ { CAN_CALL_SOME_NAME, EXAMPLE_PATH, EXAMPLE_IFACE, EXAMPLE_METHOD, ++ .can_call = FALSE, .can_see = TRUE }, ++ { CAN_CALL_SOME_NAME, CAN_CALL_SOME_PATH, CAN_CALL_SOME_IFACE, CAN_CALL_SOME_METHOD, ++ .can_call = TRUE, .can_see = TRUE }, ++ { CAN_CALL_SOME_NAME, EXAMPLE_PATH, CAN_CALL_SOME_IFACE, CAN_CALL_SOME_METHOD, ++ .can_call = FALSE, .can_see = TRUE }, ++ { CAN_CALL_SOME_NAME, CAN_CALL_SOME_PATH, EXAMPLE_IFACE, CAN_CALL_SOME_METHOD, ++ .can_call = FALSE, .can_see = TRUE }, ++ { CAN_CALL_SOME_NAME, CAN_CALL_SOME_PATH, CAN_CALL_SOME_IFACE, EXAMPLE_METHOD, ++ .can_call = FALSE, .can_see = TRUE }, ++}; ++ ++static void ++test_call (Fixture *f, ++ gconstpointer context G_GNUC_UNUSED) ++{ ++ alarm (30); ++ fixture_start_proxy (f); ++ ++ for (size_t i = 0; i < G_N_ELEMENTS (call_tests); i++) ++ { ++ const CallTest *t = &call_tests[i]; ++ g_autoptr(GAsyncResult) result = NULL; ++ g_autoptr(GError) error = NULL; ++ g_autoptr(GVariant) tuple = NULL; ++ const Connection *dest; ++ int n_calls_before; ++ ++ g_test_message ("#%zu: sandboxed connection %s be allowed to call %s:%s.%s on %s", ++ i, ++ t->can_call ? "should" : "should not", ++ t->path, ++ t->iface, ++ t->method, ++ t->name); ++ ++ dest = g_hash_table_lookup (f->connections_by_name, t->name); ++ g_assert_nonnull (dest); ++ n_calls_before = g_atomic_int_get (&dest->n_method_calls); ++ ++ g_dbus_connection_call (f->proxied.conn, ++ t->name, ++ t->path, ++ t->iface, ++ t->method, ++ NULL, ++ G_VARIANT_TYPE ("()"), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, ++ NULL, /* cancellable */ ++ ready_cb, ++ &result); ++ ++ while (result == NULL) ++ g_main_context_iteration (NULL, TRUE); ++ ++ tuple = g_dbus_connection_call_finish (f->proxied.conn, result, &error); ++ g_assert_nonnull (error); ++ g_assert_null (tuple); ++ g_test_message ("-> %s", error->message); ++ ++ if (t->can_call) ++ { ++ /* If the method call was allowed, we just return an error, ++ * because for simplicity we didn't actually implement any ++ * method calls. */ ++ g_assert_cmpstr (g_quark_to_string (error->domain), ++ ==, g_quark_to_string (G_DBUS_ERROR)); ++ ++ switch (error->code) ++ { ++ case G_DBUS_ERROR_UNKNOWN_METHOD: ++ case G_DBUS_ERROR_UNKNOWN_INTERFACE: ++ case G_DBUS_ERROR_UNKNOWN_OBJECT: ++ /* OK */ ++ break; ++ ++ default: ++ g_assert_not_reached (); ++ } ++ ++ g_assert_cmpint (g_atomic_int_get (&dest->n_method_calls), ==, n_calls_before + 1); ++ } ++ else if (t->can_see) ++ { ++ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED); ++ g_assert_cmpint (g_atomic_int_get (&dest->n_method_calls), ==, n_calls_before); ++ } ++ else ++ { ++ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN); ++ g_assert_cmpint (g_atomic_int_get (&dest->n_method_calls), ==, n_calls_before); ++ } ++ } ++} ++ + typedef struct + { + const char *name; +@@ -619,6 +755,7 @@ main (int argc, + g_test_init (&argc, &argv, NULL); + + g_test_add ("/basics", Fixture, NULL, setup, test_basics, teardown); ++ g_test_add ("/call", Fixture, NULL, setup, test_call, teardown); + g_test_add ("/own", Fixture, NULL, setup, test_own, teardown); + + return g_test_run (); diff -Nru xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Test-that-messages-from-outside-sandbox-are-not-rec.patch xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Test-that-messages-from-outside-sandbox-are-not-rec.patch --- xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Test-that-messages-from-outside-sandbox-are-not-rec.patch 1970-01-01 00:00:00.000000000 +0000 +++ xdg-dbus-proxy-0.1.6/debian/patches/tests/tests-Test-that-messages-from-outside-sandbox-are-not-rec.patch 2026-08-11 12:43:30.000000000 +0000 @@ -0,0 +1,191 @@ +From: Simon McVittie +Date: Sun, 26 Jul 2026 14:34:34 +0100 +Subject: tests: Test that messages from outside sandbox are (not) received + +In particular, this asserts that the vulnerability +https://github.com/flatpak/xdg-dbus-proxy/security/advisories/GHSA-r7hp-698j-2h6c +has been fixed. + +Signed-off-by: Simon McVittie +Origin: upstream, 0.1.8 +--- + tests/test-proxy.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 138 insertions(+) + +diff --git a/tests/test-proxy.c b/tests/test-proxy.c +index 829b88c..777c1d7 100644 +--- a/tests/test-proxy.c ++++ b/tests/test-proxy.c +@@ -33,6 +33,7 @@ + #define DBUS_SERVICE_DBUS "org.freedesktop.DBus" + #define DBUS_PATH_DBUS "/org/freedesktop/DBus" + #define DBUS_INTERFACE_DBUS "org.freedesktop.DBus" ++#define DBUS_INTERFACE_PEER "org.freedesktop.DBus.Peer" + + #define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 + #define DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2 +@@ -367,6 +368,7 @@ fixture_start_proxy (Fixture *f) + { + g_autoptr(GSubprocessLauncher) launcher = NULL; + g_autoptr(GError) error = NULL; ++ g_autoptr(GVariant) tuple = NULL; + int sync_pipe[PIPE_FDS]; + char buf; + ssize_t bytes_read; +@@ -416,6 +418,18 @@ fixture_start_proxy (Fixture *f) + g_assert_no_error (error); + g_assert_nonnull (f->proxied.conn); + f->proxied.unique_name = g_dbus_connection_get_unique_name (f->proxied.conn); ++ tuple = g_dbus_connection_call_sync (f->proxied.conn, ++ DBUS_SERVICE_DBUS, ++ DBUS_PATH_DBUS, ++ DBUS_INTERFACE_DBUS, ++ "AddMatch", ++ g_variant_new ("(s)", ""), ++ G_VARIANT_TYPE ("()"), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, ++ NULL, /* cancellable */ ++ &error); ++ g_assert_no_error (error); + f->proxied.filter = g_dbus_connection_add_filter (f->proxied.conn, + conn_filter_cb, + &f->proxied, +@@ -687,6 +701,129 @@ test_own (Fixture *f, + } + } + ++typedef struct ++{ ++ const char *name; ++ const char *path; ++ const char *iface; ++ const char *member; ++ gboolean can_receive_broadcast; ++} ReceiveTest; ++ ++static const ReceiveTest receive_tests[] = ++{ ++ { CANNOT_ACCESS_NAME, EXAMPLE_PATH, EXAMPLE_IFACE, EXAMPLE_SIGNAL, FALSE }, ++ { CAN_SEE_NAME, EXAMPLE_PATH, EXAMPLE_IFACE, EXAMPLE_SIGNAL, FALSE }, ++ { CAN_TALK_NAME, EXAMPLE_PATH, EXAMPLE_IFACE, EXAMPLE_SIGNAL, TRUE }, ++ { CAN_OWN_NAME, EXAMPLE_PATH, EXAMPLE_IFACE, EXAMPLE_SIGNAL, TRUE }, ++ ++ /* Before GHSA-r7hp-698j-2h6c was fixed, both of these would receive the ++ * broadcast, but that was unintended */ ++ { CAN_CALL_ANYTHING_NAME, EXAMPLE_PATH, EXAMPLE_IFACE, EXAMPLE_SIGNAL, FALSE }, ++ { CAN_CALL_SOME_NAME, EXAMPLE_PATH, EXAMPLE_IFACE, EXAMPLE_SIGNAL, FALSE }, ++ ++ { CAN_RECEIVE_ANYTHING_NAME, EXAMPLE_PATH, EXAMPLE_IFACE, EXAMPLE_SIGNAL, TRUE }, ++ ++ { CAN_RECEIVE_SOME_NAME, CAN_RECEIVE_SOME_PATH, CAN_RECEIVE_SOME_IFACE, CAN_RECEIVE_SOME_SIGNAL, TRUE }, ++ ++ /* Before GHSA-r7hp-698j-2h6c was fixed, all of these would receive the broadcast, ++ * but that was unintended */ ++ { CAN_RECEIVE_SOME_NAME, EXAMPLE_PATH, CAN_RECEIVE_SOME_IFACE, CAN_RECEIVE_SOME_SIGNAL, FALSE }, ++ { CAN_RECEIVE_SOME_NAME, CAN_RECEIVE_SOME_PATH, EXAMPLE_IFACE, CAN_RECEIVE_SOME_SIGNAL, FALSE }, ++ { CAN_RECEIVE_SOME_NAME, CAN_RECEIVE_SOME_PATH, CAN_RECEIVE_SOME_IFACE, EXAMPLE_SIGNAL, FALSE }, ++ { CAN_RECEIVE_SOME_NAME, EXAMPLE_PATH, EXAMPLE_IFACE, EXAMPLE_SIGNAL, FALSE }, ++}; ++ ++static void ++test_receive (Fixture *f, ++ gconstpointer context G_GNUC_UNUSED) ++{ ++ alarm (30); ++ fixture_start_proxy (f); ++ ++ for (size_t i = 0; i < G_N_ELEMENTS (receive_tests); i++) ++ { ++ g_autoptr(GAsyncResult) result = NULL; ++ g_autoptr(GVariant) tuple = NULL; ++ g_autoptr(GError) error = NULL; ++ const Connection *sender; ++ const ReceiveTest *t = &receive_tests[i]; ++ int n_unicasts_before; ++ int n_broadcasts_before; ++ int n_calls_before; ++ ++ g_test_message ("#%zu: sandboxed connection %s be allowed to receive broadcast from %s:%s.%s on %s", ++ i, ++ t->can_receive_broadcast ? "should" : "should not", ++ t->path, ++ t->iface, ++ t->member, ++ t->name); ++ ++ sender = g_hash_table_lookup (f->connections_by_name, t->name); ++ g_assert_nonnull (sender); ++ ++ n_calls_before = g_atomic_int_get (&f->proxied.n_method_calls); ++ n_unicasts_before = g_atomic_int_get (&f->proxied.n_unicast_signals); ++ n_broadcasts_before = g_atomic_int_get (&f->proxied.n_broadcasts); ++ ++ /* The sandboxed recipient is only sometimes allowed to receive ++ * broadcasts. We do this first, because D-Bus preserves message ++ * order, therefore by the time we have received the unicast signal ++ * and/or the method call, it's guaranteed that this broadcast ++ * has been processed (and received, or not, as appropriate). */ ++ g_dbus_connection_emit_signal (sender->conn, ++ NULL, ++ t->path, ++ t->iface, ++ t->member, ++ NULL, ++ &error); ++ g_assert_no_error (error); ++ ++ /* The sandboxed recipient is always allowed to receive ++ * unicast signals. */ ++ g_dbus_connection_emit_signal (sender->conn, ++ f->proxied.unique_name, ++ t->path, ++ t->iface, ++ t->member, ++ NULL, ++ &error); ++ g_assert_no_error (error); ++ ++ /* The sandboxed recipient is always allowed to receive ++ * method calls. */ ++ g_dbus_connection_call (sender->conn, ++ f->proxied.unique_name, ++ "/", ++ DBUS_INTERFACE_PEER, ++ "Ping", ++ NULL, ++ G_VARIANT_TYPE ("()"), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, ++ NULL, /* cancellable */ ++ ready_cb, ++ &result); ++ ++ while (result == NULL) ++ g_main_context_iteration (NULL, TRUE); ++ ++ tuple = g_dbus_connection_call_finish (sender->conn, result, &error); ++ g_assert_no_error (error); ++ g_assert_nonnull (tuple); ++ ++ g_assert_cmpint (g_atomic_int_get (&f->proxied.n_method_calls), ==, n_calls_before + 1); ++ g_assert_cmpint (g_atomic_int_get (&f->proxied.n_unicast_signals), ==, n_unicasts_before + 1); ++ ++ if (t->can_receive_broadcast) ++ g_assert_cmpint (g_atomic_int_get (&f->proxied.n_broadcasts), ==, n_broadcasts_before + 1); ++ else ++ g_assert_cmpint (g_atomic_int_get (&f->proxied.n_broadcasts), ==, n_broadcasts_before); ++ } ++} ++ + static void + teardown (Fixture *f, + gconstpointer context G_GNUC_UNUSED) +@@ -757,6 +894,7 @@ main (int argc, + g_test_add ("/basics", Fixture, NULL, setup, test_basics, teardown); + g_test_add ("/call", Fixture, NULL, setup, test_call, teardown); + g_test_add ("/own", Fixture, NULL, setup, test_own, teardown); ++ g_test_add ("/receive", Fixture, NULL, setup, test_receive, teardown); + + return g_test_run (); + }