Hello, I've prepared xdg-dbus-proxy 0.1.4-3+deb12u2 for bookworm-security, and it's ready for review.
Trixie already has this fix in DSA-6510-1 (0.1.6-1+deb13u3). The debdiff against deb12u1 is attached. This is CVE-2026-94422. The fix is the three proxy commits from 0.1.9 that DSA-6510-1 already shipped: - e5702fca4dba: only a method return or an error counts as a reply. - fc027f759316: make the direction of each message explicit. The destination check is the commit after this. - e4465a0dfe96: the reply has to go back to the caller that sent the request. From the sandbox, we match the serial and the caller. From the bus, just the serial. There's only one client on that side, and it has no unique name until Hello succeeds. The three reply tests from 0.1.9 are included: 4427d5d0eb6d, e7f2f89bb305 and 78045ceec133. They were written for the 0.1.8 test harness, which this package doesn't have, so I backported those cases to the existing test. A real method return and a real error still come through. A method call or a signal that only quotes the reply serial does not, and neither does a reply aimed at a different peer. #1148782 was already closed by the Trixie upload, so I left it out of this changelog. Here is my Salsa fork: https://salsa.debian.org/tsimonq2/xdg-dbus-proxy/-/tree/debian/bookworm Here is the Debusine work request: https://debusine.debian.net/debian/developers/work-request/1507567/ Feedback is welcome. If nothing showstopping comes up, I'll upload this and issue the DLA on Friday evening (October 23rd, 2026). Best regards, Simon Quigley [email protected]
diff -Nru xdg-dbus-proxy-0.1.4/debian/changelog xdg-dbus-proxy-0.1.4/debian/changelog --- xdg-dbus-proxy-0.1.4/debian/changelog 2026-04-15 14:27:48.000000000 -0500 +++ xdg-dbus-proxy-0.1.4/debian/changelog 2026-10-20 15:44:51.000000000 -0500 @@ -1,3 +1,16 @@ +xdg-dbus-proxy (0.1.4-3+deb12u2) bookworm-security; urgency=high + + * Non-maintainer upload by the LTS Team. + * CVE-2026-94422: only a method return or an error counts as a reply. + * CVE-2026-94422: name which side each message is travelling toward. + * CVE-2026-94422: only accept a reply going back to the original + caller. + * Add basic reply coverage from 4427d5d0eb6d on the existing test. + * Reject a method call or signal that only quotes a reply serial. + * Reject a reply that is aimed at a different peer. + + -- Simon Quigley <[email protected]> Tue, 20 Oct 2026 15:44:51 -0500 + xdg-dbus-proxy (0.1.4-3+deb12u1) bookworm-security; urgency=high * d/gbp.conf: Configure for bookworm diff -Nru xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-1.patch xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-1.patch --- xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-1.patch 1969-12-31 18:00:00.000000000 -0600 +++ xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-1.patch 2026-10-20 15:43:58.000000000 -0500 @@ -0,0 +1,153 @@ +Origin: https://github.com/flatpak/xdg-dbus-proxy/commit/e5702fca4dba9600721921fbca2dbc39dc5ca400 +Reviewed-by: Simon Quigley <[email protected]> +Last-Update: 2026-10-20 + +Backported to 0.1.4. parse_header keeps its serial-offset +arguments. + +From e5702fca4dba9600721921fbca2dbc39dc5ca400 Mon Sep 17 00:00:00 2001 +From: Simon McVittie <[email protected]> +Date: Mon, 7 Sep 2026 15:06:35 +0100 +Subject: [PATCH] proxy: Don't assume that only returns and errors have a + reply-serial + +The D-Bus session bus (which is not designed to be a security boundary) +does not actually prevent the "in reply to" field from being set on +method calls and signals, even though that makes little sense. + +We must not treat messages as being a legitimate reply unless they +are genuinely of a message type that acts as a reply: otherwise, a +malicious sandboxed app could receive a method call, delay or suppress +the reply, and send back its own method call or unicast signal that +pretends to be a reply to the method call, which could trick the +caller into doing something undesirable (potentially arbitrary +code execution, depending on the caller). + +Partially addresses CVE-2026-94422 + +Helps: CVE-2026-94422 +Helps: https://github.com/flatpak/xdg-dbus-proxy/security/advisories/GHSA-2cgv-pwcq-wvpq +Signed-off-by: Simon McVittie <[email protected]> +--- + flatpak-proxy.c | 45 ++++++++++++++++++++++++++++++--------------- + 1 file changed, 30 insertions(+), 15 deletions(-) + +--- a/flatpak-proxy.c 2026-10-20 15:41:01.388811196 -0500 ++++ b/flatpak-proxy.c +@@ -230,7 +230,6 @@ + const char *destination; + const char *sender; + const char *signature; +- gboolean has_reply_serial; + guint32 reply_serial; + guint32 unix_fds; + } Header; +@@ -1146,6 +1145,22 @@ + g_free (header); + } + ++static gboolean ++is_reply (Header *header) ++{ ++ switch (header->type) ++ { ++ case G_DBUS_MESSAGE_TYPE_METHOD_RETURN: ++ case G_DBUS_MESSAGE_TYPE_ERROR: ++ return TRUE; ++ ++ case G_DBUS_MESSAGE_TYPE_METHOD_CALL: ++ case G_DBUS_MESSAGE_TYPE_SIGNAL: ++ default: ++ return FALSE; ++ } ++} ++ + static Header * + parse_header (Buffer *buffer, guint32 serial_offset, guint32 reply_serial_offset, guint32 hello_serial) + { +@@ -1153,6 +1168,7 @@ + guint32 offset, end_offset; + guint8 header_type; + guint32 reply_serial_pos = 0; ++ gboolean has_reply_serial = FALSE; + const char *signature; + + g_autoptr(Header) header = g_new0 (Header, 1); +@@ -1246,7 +1262,7 @@ + if (offset + 4 > end_offset) + return NULL; + +- header->has_reply_serial = TRUE; ++ has_reply_serial = TRUE; + reply_serial_pos = offset; + header->reply_serial = read_uint32 (header, &buffer->data[offset]); + offset += 4; +@@ -1298,12 +1314,12 @@ + break; + + case G_DBUS_MESSAGE_TYPE_METHOD_RETURN: +- if (!header->has_reply_serial) ++ if (!has_reply_serial) + return NULL; + break; + + case G_DBUS_MESSAGE_TYPE_ERROR: +- if (header->error_name == NULL || !header->has_reply_serial) ++ if (header->error_name == NULL || !has_reply_serial) + return NULL; + break; + +@@ -1329,10 +1345,16 @@ + } + + if (reply_serial_offset > 0 && +- header->has_reply_serial && ++ has_reply_serial && + header->reply_serial > hello_serial + reply_serial_offset) + write_uint32 (header, &buffer->data[reply_serial_pos], header->reply_serial - reply_serial_offset); + ++ /* Invariant: every reply has a reply serial. ++ * (Note that the converse is not true: it is technically possible to ++ * send a method call or signal that claims to be a reply.) */ ++ if (is_reply (header)) ++ g_assert (has_reply_serial); ++ + return g_steal_pointer (&header); + } + +@@ -1684,7 +1706,7 @@ + + g_autoptr(GList) filters = NULL; + +- if (header->has_reply_serial) ++ if (is_reply (header)) + { + ExpectedReplyType expected_reply = + steal_expected_reply (&client->bus_side, +@@ -2381,7 +2403,7 @@ + if (client->proxy->log_messages) + print_incoming_header (header); + +- if (header->has_reply_serial) ++ if (is_reply (header)) + { + expected_reply = steal_expected_reply (get_other_side (side), header->reply_serial); + +@@ -2490,15 +2512,8 @@ + } + else /* Not reply */ + { +- +- /* Don't allow reply types with no reply_serial */ +- if (header->type == G_DBUS_MESSAGE_TYPE_METHOD_RETURN || +- header->type == G_DBUS_MESSAGE_TYPE_ERROR) +- { +- if (client->proxy->log_messages) +- g_print ("*Invalid reply*\n"); +- g_clear_pointer (&buffer, buffer_unref); +- } ++ g_assert (header->type != G_DBUS_MESSAGE_TYPE_METHOD_RETURN); ++ g_assert (header->type != G_DBUS_MESSAGE_TYPE_ERROR); + + /* We filter all NameOwnerChanged signal according to the policy */ + if (message_is_name_owner_changed (client, header)) diff -Nru xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-2.patch xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-2.patch --- xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-2.patch 1969-12-31 18:00:00.000000000 -0600 +++ xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-2.patch 2026-10-20 15:43:58.000000000 -0500 @@ -0,0 +1,144 @@ +Origin: https://github.com/flatpak/xdg-dbus-proxy/commit/fc027f759316fb2a6c45648200b6f100202eb84e +Reviewed-by: Simon Quigley <[email protected]> +Last-Update: 2026-10-20 + +Backported to 0.1.4. The client serial check stays the +existing last_serial test. + +From fc027f759316fb2a6c45648200b6f100202eb84e Mon Sep 17 00:00:00 2001 +From: Simon McVittie <[email protected]> +Date: Mon, 7 Sep 2026 15:14:08 +0100 +Subject: [PATCH] proxy: Make it clearer which direction messages are going in + +Helps: CVE-2026-94422 +Helps: https://github.com/flatpak/xdg-dbus-proxy/security/advisories/GHSA-2cgv-pwcq-wvpq +Signed-off-by: Simon McVittie <[email protected]> +--- + flatpak-proxy.c | 40 +++++++++++++++++++++++++++++++--------- + 1 file changed, 31 insertions(+), 9 deletions(-) + +--- a/flatpak-proxy.c 2026-10-20 15:41:01.390273988 -0500 ++++ b/flatpak-proxy.c +@@ -1026,6 +1026,13 @@ + GUINT_TO_POINTER (type)); + } + ++/* ++ * @side: Either the bus or the sandboxed client ++ * @serial: The reply_serial field of the reply ++ * ++ * Returns: The type of the matching reply, or %EXPECTED_REPLY_NONE ++ * if no match was found. ++ */ + static ExpectedReplyType + steal_expected_reply (ProxySide *side, guint32 serial) + { +@@ -1698,6 +1705,9 @@ + g_strcmp0 (header->interface, "org.freedesktop.DBus.Introspectable") == 0; + } + ++/* ++ * @header: an outgoing message from the sandboxed client to the bus ++ */ + static BusHandler + get_dbus_method_handler (FlatpakProxyClient *client, Header *header) + { +@@ -2206,11 +2216,17 @@ + } + + ++/* ++ * Called when we received @buffer from the client side of @client: ++ * it's an outgoing message from the sandboxed client to the bus. ++ */ + static void + got_buffer_from_client (FlatpakProxyClient *client, ProxySide *side, Buffer *buffer) + { + ExpectedReplyType expecting_reply = EXPECTED_REPLY_NONE; + ++ g_assert (side == &client->client_side); ++ + if (client->authenticated && client->proxy->filter) + { + g_autoptr(Header) header = NULL; +@@ -2222,12 +2238,12 @@ + if (header == NULL) + { + g_warning ("Invalid message header format"); +- side_closed (side); ++ side_closed (&client->client_side); + buffer_unref (buffer); + return; + } + +- if (!update_socket_messages (side, buffer, header)) ++ if (!update_socket_messages (&client->client_side, buffer, header)) + return; + + /* Make sure the client is not playing games with the serials, as that +@@ -2235,7 +2251,7 @@ + if (header->serial <= client->last_serial) + { + g_warning ("Invalid client serial"); +- side_closed (side); ++ side_closed (&client->client_side); + buffer_unref (buffer); + return; + } +@@ -2366,7 +2382,7 @@ + } + + if (buffer != NULL && expecting_reply != EXPECTED_REPLY_NONE) +- queue_expected_reply (side, header->serial, expecting_reply); ++ queue_expected_reply (&client->client_side, header->serial, expecting_reply); + } + + if (buffer) +@@ -2376,9 +2392,15 @@ + queue_initial_name_ops (client); + } + ++/* ++ * Called when we received @buffer from the bus side of @client: ++ * it's an incoming message from the bus to the sandboxed client. ++ */ + static void + got_buffer_from_bus (FlatpakProxyClient *client, ProxySide *side, Buffer *buffer) + { ++ g_assert (side == &client->bus_side); ++ + if (client->authenticated && client->proxy->filter) + { + g_autoptr(Header) header = NULL; +@@ -2393,11 +2415,11 @@ + { + g_warning ("Invalid message header format"); + buffer_unref (buffer); +- side_closed (side); ++ side_closed (&client->bus_side); + return; + } + +- if (!update_socket_messages (side, buffer, header)) ++ if (!update_socket_messages (&client->bus_side, buffer, header)) + return; + + if (client->proxy->log_messages) +@@ -2405,7 +2427,7 @@ + + if (is_reply (header)) + { +- expected_reply = steal_expected_reply (get_other_side (side), header->reply_serial); ++ expected_reply = steal_expected_reply (&client->client_side, header->reply_serial); + + switch (expected_reply) + { +@@ -2553,7 +2575,7 @@ + flatpak_proxy_client_update_unique_id_policy (client, header->sender, FLATPAK_POLICY_SEE); + + if (buffer && client_message_generates_reply (header)) +- queue_expected_reply (side, header->serial, EXPECTED_REPLY_NORMAL); ++ queue_expected_reply (&client->bus_side, header->serial, EXPECTED_REPLY_NORMAL); + } + + if (buffer) diff -Nru xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-3.patch xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-3.patch --- xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-3.patch 1969-12-31 18:00:00.000000000 -0600 +++ xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-3.patch 2026-10-20 15:43:58.000000000 -0500 @@ -0,0 +1,365 @@ +Origin: https://github.com/flatpak/xdg-dbus-proxy/commit/e4465a0dfe96da3b39929a30a1ac3a22b16223e3 +Reviewed-by: Simon Quigley <[email protected]> +Last-Update: 2026-10-20 + +Backported to 0.1.4. The serial offset handling is unchanged. + +From e4465a0dfe96da3b39929a30a1ac3a22b16223e3 Mon Sep 17 00:00:00 2001 +From: Simon McVittie <[email protected]> +Date: Mon, 7 Sep 2026 15:15:10 +0100 +Subject: [PATCH] proxy: Only allow replies to go to the correct destination + +If peer `:1.0` (perhaps a MPRIS client) calls a method on the sandboxed +process with serial number 3, then it's invalid for the sandboxed process +to send a reply to an unrelated peer `:1.1`, even if that forged reply +has also been marked as "in reply to serial number 3". + +This introduces an asymmetry into the tracking of expected replies, +so move the data structures used for that tracking from the ProxySide +into the Client. When the bus side calls a method on the sandboxed side, +we need to track (serial, caller) pairs to enforce that the reply goes +back to the original caller. However, when the sandboxed side calls a +method on the bus side, we don't need to to track the caller because +there is only one possible caller on the sandboxed side. We also +*can't* track the caller on the sandboxed side, because to do that we +would need to know its D-Bus unique name, and until it has successfully +called Hello() no such name has been assigned. + +Resolves CVE-2026-94422 when combined with earlier fixes. + +Helps: CVE-2026-94422 +Helps: https://github.com/flatpak/xdg-dbus-proxy/security/advisories/GHSA-2cgv-pwcq-wvpq +Signed-off-by: Simon McVittie <[email protected]> +--- + flatpak-proxy.c | 204 +++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 183 insertions(+), 21 deletions(-) + +--- a/flatpak-proxy.c 2026-10-20 15:41:01.391585566 -0500 ++++ b/flatpak-proxy.c +@@ -123,9 +123,7 @@ + * Once authenticated we receive incoming messages one at a time, + * and then we demarshal the message headers to make routing decisions. + * This means we trust the bus to do message format validation, etc. +- * (because we don't parse the body). Also we assume that the bus verifies +- * reply_serials, i.e. that a reply can only be sent once and by the real +- * recipient of an previously sent method call. ++ * (because we don't parse the body). + * + * We don't however trust the serials from the client. We verify that + * they are strictly increasing to make sure the code is not confused +@@ -258,6 +256,61 @@ + static void header_free (Header *header); + G_DEFINE_AUTOPTR_CLEANUP_FUNC (Header, header_free) + ++/* ++ * A pending method call from @caller on the bus to the client, ++ * for which we expect a reply from the client back to @caller, ++ * represented as a single memory block. ++ */ ++typedef struct ++{ ++ guint32 serial; ++ char caller[]; ++} ExpectedReplyFromClient; ++ ++static ExpectedReplyFromClient * ++expected_reply_from_client_new (guint32 serial, ++ const char *caller) ++{ ++ ExpectedReplyFromClient *ret; ++ size_t len; ++ ++ /* A missing destination on the method call means a method call from ++ * the message bus itself (unlikely, but possible). ++ * We represent this as the empty string (which is not a valid bus name) ++ * to avoid needing a separate representation for NULL. */ ++ if (caller == NULL) ++ caller = ""; ++ ++ len = strlen (caller) + 1; ++ ++ ret = g_malloc0 (sizeof (*ret) + len); ++ ret->serial = serial; ++ memcpy (&ret->caller, caller, len); ++ return ret; ++} ++ ++/* Because it's a single memory block, we can just g_free() it. */ ++#define expected_reply_from_client_free g_free ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (ExpectedReplyFromClient, expected_reply_from_client_free) ++ ++static gboolean ++expected_reply_from_client_equal (const void *v1, ++ const void *v2) ++{ ++ const ExpectedReplyFromClient *left = v1; ++ const ExpectedReplyFromClient *right = v2; ++ ++ return left->serial == right->serial && g_str_equal (&left->caller, &right->caller); ++} ++ ++static guint ++expected_reply_from_client_hash (const void *v) ++{ ++ const ExpectedReplyFromClient *self = v; ++ ++ return self->serial ^ g_str_hash (&self->caller); ++} ++ + typedef struct + { + gboolean got_first_byte; /* always true on bus side */ +@@ -274,8 +327,6 @@ + + GList *buffers; /* to be sent */ + GList *control_messages; +- +- GHashTable *expected_replies; + } ProxySide; + + struct FlatpakProxyClient +@@ -290,6 +341,31 @@ + ProxySide client_side; + ProxySide bus_side; + ++ /* (element-type ExpectedReplyFromClient ExpectedReplyType) ++ * Map from message serial number and caller to expected replies. ++ * If this map contains ++ * { { serial, caller }: EXPECTED_REPLY_FOO }, ++ * then it means that @caller on the bus sent a method call to the ++ * sandboxed client with SERIAL=serial. ++ * This means that in future we're expecting the sandboxed client to ++ * respond with a message back to @caller with REPLY_SERIAL=serial. */ ++ GHashTable *expected_replies_from_client; ++ ++ /* (element-type guint ExpectedReplyType) ++ * Map from message serial number to expected reply type. ++ * If this map contains ++ * { serial: EXPECTED_REPLY_FOO }, ++ * then it means that the sandboxed client sent a method call to the ++ * bus with SERIAL=serial. ++ * This means that in future we're expecting something on the bus to ++ * respond with a message that has REPLY_SERIAL=serial. ++ * This direction is simpler than the other way round because we don't ++ * need to distinguish between destinations: we trust the bus, ++ * and there is only one possible destination on the sandboxed client ++ * side anyway. ++ */ ++ GHashTable *expected_replies_from_bus; ++ + /* Filtering data: */ + guint32 serial_offset; + guint32 hello_serial; +@@ -392,8 +468,6 @@ + g_source_destroy (side->in_source); + if (side->out_source) + g_source_destroy (side->out_source); +- +- g_hash_table_destroy (side->expected_replies); + } + + static void +@@ -409,6 +483,8 @@ + g_hash_table_destroy (client->get_owner_reply); + g_hash_table_destroy (client->unique_id_policy); + g_hash_table_destroy (client->unique_id_owned_names); ++ g_hash_table_destroy (client->expected_replies_from_bus); ++ g_hash_table_destroy (client->expected_replies_from_client); + + free_side (&client->client_side); + free_side (&client->bus_side); +@@ -432,7 +508,6 @@ + side->header_buffer.size = 16; + side->header_buffer.pos = 0; + side->current_read_buffer = &side->header_buffer; +- side->expected_replies = g_hash_table_new (g_direct_hash, g_direct_equal); + } + + static void +@@ -446,6 +521,11 @@ + client->get_owner_reply = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); + client->unique_id_policy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + client->unique_id_owned_names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) string_list_free); ++ client->expected_replies_from_client = g_hash_table_new_full (expected_reply_from_client_hash, ++ expected_reply_from_client_equal, ++ expected_reply_from_client_free, ++ NULL); ++ client->expected_replies_from_bus = g_hash_table_new (g_direct_hash, g_direct_equal); + } + + static FlatpakProxyClient * +@@ -1018,34 +1098,102 @@ + return retval; + } + ++/* ++ * A method call was received from the sandboxed client, ++ * with serial number @serial. ++ * We now expect a reply from the bus side, of type @type. ++ * We do not need to track the expected destination, ++ * because there is only one destination on the client side ++ * (and we don't know its name until we have delivered the Hello reply). ++ */ + static void +-queue_expected_reply (ProxySide *side, guint32 serial, ExpectedReplyType type) ++queue_expected_reply_from_bus (FlatpakProxyClient *client, ++ guint32 serial, ++ ExpectedReplyType type) + { +- g_hash_table_replace (side->expected_replies, ++ g_return_if_fail (serial != 0); ++ g_return_if_fail (type != EXPECTED_REPLY_NONE); ++ ++ g_hash_table_replace (client->expected_replies_from_bus, + GUINT_TO_POINTER (serial), + GUINT_TO_POINTER (type)); + } + + /* +- * @side: Either the bus or the sandboxed client ++ * A method call was received from sender @caller on the bus, ++ * with serial number @serial. ++ * We now expect a reply from the sandboxed client of type @type. ++ */ ++static void ++queue_expected_reply_from_client (FlatpakProxyClient *client, ++ guint32 serial, ++ const char *caller, ++ ExpectedReplyType type) ++{ ++ g_return_if_fail (serial != 0); ++ g_return_if_fail (caller == NULL || caller[0] != '\0'); ++ g_return_if_fail (type != EXPECTED_REPLY_NONE); ++ ++ g_hash_table_replace (client->expected_replies_from_client, ++ expected_reply_from_client_new (serial, caller), ++ GUINT_TO_POINTER (type)); ++} ++ ++/* ++ * @client: The client + * @serial: The reply_serial field of the reply + * + * Returns: The type of the matching reply, or %EXPECTED_REPLY_NONE + * if no match was found. + */ + static ExpectedReplyType +-steal_expected_reply (ProxySide *side, guint32 serial) ++steal_expected_reply_from_bus (FlatpakProxyClient *client, ++ guint32 serial) + { + ExpectedReplyType type; + +- type = GPOINTER_TO_UINT (g_hash_table_lookup (side->expected_replies, ++ g_return_val_if_fail (serial != 0, EXPECTED_REPLY_NONE); ++ ++ type = GPOINTER_TO_UINT (g_hash_table_lookup (client->expected_replies_from_bus, + GUINT_TO_POINTER (serial))); + if (type) +- g_hash_table_remove (side->expected_replies, ++ g_hash_table_remove (client->expected_replies_from_bus, + GUINT_TO_POINTER (serial)); + return type; + } + ++/* ++ * @client: The client ++ * @serial: The reply_serial field of the reply ++ * @caller: Only match pending method calls that came from @caller ++ * (and therefore the reply should be sent to @caller). ++ * ++ * Returns: The type of the matching reply, or %EXPECTED_REPLY_NONE ++ * if no match was found. ++ */ ++static ExpectedReplyType ++steal_expected_reply_from_client (FlatpakProxyClient *client, ++ guint32 serial, ++ const char *caller) ++{ ++ g_autoptr(ExpectedReplyFromClient) key = NULL; ++ void *type; ++ ++ g_return_val_if_fail (serial != 0, EXPECTED_REPLY_NONE); ++ g_return_val_if_fail (caller == NULL || caller[0] != '\0', EXPECTED_REPLY_NONE); ++ ++ key = expected_reply_from_client_new (serial, caller); ++ ++ if (g_hash_table_lookup_extended (client->expected_replies_from_client, key, ++ NULL, &type)) ++ { ++ g_hash_table_remove (client->expected_replies_from_client, key); ++ return GPOINTER_TO_UINT (type); ++ } ++ ++ return EXPECTED_REPLY_NONE; ++} ++ + + static void + queue_outgoing_buffer (ProxySide *side, Buffer *buffer) +@@ -1716,11 +1864,17 @@ + + g_autoptr(GList) filters = NULL; + ++ /* If the message claims to be a reply to a method call with serial number n, ++ * we allow if and only if there is indeed a pending method call from ++ * the reply's destination, with serial number n, and it has not yet had ++ * its reply */ + if (is_reply (header)) + { + ExpectedReplyType expected_reply = +- steal_expected_reply (&client->bus_side, +- header->reply_serial); ++ steal_expected_reply_from_client (client, ++ header->reply_serial, ++ header->destination); ++ + if (expected_reply == EXPECTED_REPLY_NONE) + return HANDLE_DENY; + +@@ -2089,7 +2243,7 @@ + g_object_unref (message); + + queue_outgoing_buffer (&client->bus_side, buffer); +- queue_expected_reply (&client->client_side, client->last_serial, reply_type); ++ queue_expected_reply_from_bus (client, client->last_serial, reply_type); + } + + /* After the first Hello message we need to synthesize a bunch of messages to synchronize the +@@ -2382,7 +2536,7 @@ + } + + if (buffer != NULL && expecting_reply != EXPECTED_REPLY_NONE) +- queue_expected_reply (&client->client_side, header->serial, expecting_reply); ++ queue_expected_reply_from_bus (client, header->serial, expecting_reply); + } + + if (buffer) +@@ -2427,7 +2581,14 @@ + + if (is_reply (header)) + { +- expected_reply = steal_expected_reply (&client->client_side, header->reply_serial); ++ /* If the client previously made a method call out to the bus ++ * with serial number n, we allow one reply to come from ++ * the bus "in reply to: n" back to the client. ++ * We allow any destination - this is OK, because we trust ++ * the bus, and in any case there is only one valid destination ++ * on the client side (it's the sandboxed client). */ ++ expected_reply = steal_expected_reply_from_bus (client, ++ header->reply_serial); + + switch (expected_reply) + { +@@ -2574,8 +2735,10 @@ + if (buffer && header->sender && header->sender[0] == ':') + flatpak_proxy_client_update_unique_id_policy (client, header->sender, FLATPAK_POLICY_SEE); + ++ /* Remember that the sandboxed client is allowed to send a single ++ * reply back to header->sender, marked "in reply to" header->serial. */ + if (buffer && client_message_generates_reply (header)) +- queue_expected_reply (&client->bus_side, header->serial, EXPECTED_REPLY_NORMAL); ++ queue_expected_reply_from_client (client, header->serial, header->sender, EXPECTED_REPLY_NORMAL); + } + + if (buffer) diff -Nru xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-tests-1.patch xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-tests-1.patch --- xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-tests-1.patch 1969-12-31 18:00:00.000000000 -0600 +++ xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-tests-1.patch 2026-10-20 15:43:58.000000000 -0500 @@ -0,0 +1,241 @@ +Origin: https://github.com/flatpak/xdg-dbus-proxy/commit/4427d5d0eb6d6a4aaf8ca04e446f2a96461ef0c9 +Reviewed-by: Simon Quigley <[email protected]> +Last-Update: 2026-10-20 + +Replayed on the existing fixture. The 0.1.8 harness is not +included. + +From 4427d5d0eb6d6a4aaf8ca04e446f2a96461ef0c9 Mon Sep 17 00:00:00 2001 +From: Simon McVittie <[email protected]> +Date: Mon, 7 Sep 2026 15:01:14 +0100 +Subject: [PATCH] tests: Add basic test coverage for reply handling + +Helps: CVE-2026-94422 +Helps: https://github.com/flatpak/xdg-dbus-proxy/security/advisories/GHSA-2cgv-pwcq-wvpq +Signed-off-by: Simon McVittie <[email protected]> +--- + tests/test-proxy.c | 145 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 145 insertions(+) + +--- a/tests/test-proxy.c ++++ b/tests/test-proxy.c +@@ -191,6 +191,211 @@ + g_assert_true (found); + } + ++ ++typedef struct ++{ ++ int n_method_calls; ++ int n_unicast_signals; ++ int n_broadcasts; ++ int n_returns; ++ int n_errors; ++} ReplyCounts; ++ ++static GDBusMessage * ++reply_count_filter (GDBusConnection *conn, ++ GDBusMessage *message, ++ gboolean incoming, ++ gpointer user_data) ++{ ++ ReplyCounts *counts = user_data; ++ ++ if (!incoming) ++ return message; ++ ++ switch (g_dbus_message_get_message_type (message)) ++ { ++ case G_DBUS_MESSAGE_TYPE_METHOD_CALL: ++ /* Swallow the call under test so GDBus does not answer it and ++ * consume the proxy's expected-reply slot before we forge one. */ ++ if (g_strcmp0 (g_dbus_message_get_interface (message), "com.example.Ignore") == 0 && ++ g_strcmp0 (g_dbus_message_get_member (message), "Ignore") == 0) ++ { ++ g_object_unref (message); ++ return NULL; ++ } ++ counts->n_method_calls++; ++ break; ++ ++ case G_DBUS_MESSAGE_TYPE_SIGNAL: ++ if (g_dbus_message_get_destination (message) == NULL) ++ counts->n_broadcasts++; ++ else ++ counts->n_unicast_signals++; ++ break; ++ ++ case G_DBUS_MESSAGE_TYPE_METHOD_RETURN: ++ counts->n_returns++; ++ break; ++ ++ case G_DBUS_MESSAGE_TYPE_ERROR: ++ counts->n_errors++; ++ break; ++ ++ case G_DBUS_MESSAGE_TYPE_INVALID: ++ default: ++ break; ++ } ++ ++ return message; ++} ++ ++/* A call through the proxy and back, so earlier messages have been delivered. */ ++static void ++flush_through_proxy (GDBusConnection *caller, ++ const char *sandbox_name) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(GVariant) ignored = NULL; ++ ++ ignored = g_dbus_connection_call_sync (caller, ++ sandbox_name, ++ "/", ++ "com.example.Flush", ++ "Flush", ++ NULL, ++ G_VARIANT_TYPE ("()"), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, ++ NULL, ++ &error); ++ g_assert_null (ignored); ++ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD); ++} ++ ++typedef struct ++{ ++ const char *label; ++ GDBusMessageType type; ++} ReplyCase; ++ ++/* 4427d5d0eb6d, replayed on the 0.1.4 fixture. */ ++static const ReplyCase reply_cases[] = ++{ ++ { "method return is delivered", G_DBUS_MESSAGE_TYPE_METHOD_RETURN }, ++ { "error is delivered", G_DBUS_MESSAGE_TYPE_ERROR }, ++}; ++ ++static void ++test_reply (Fixture *f, ++ gconstpointer context G_GNUC_UNUSED) ++{ ++ g_autoptr(GSubprocessLauncher) launcher = NULL; ++ g_autoptr(GError) error = NULL; ++ g_autoptr(GDBusConnection) caller = NULL; ++ ReplyCounts caller_counts = { 0, }; ++ ReplyCounts sandbox_counts = { 0, }; ++ int sync_pipe[PIPE_FDS]; ++ char buf; ++ ssize_t bytes_read; ++ const char *sandbox_name; ++ const char *caller_name; ++ gsize i; ++ ++ alarm (60); ++ ++ g_unix_open_pipe (sync_pipe, FD_CLOEXEC, &error); ++ g_assert_no_error (error); ++ f->sync_pipe = sync_pipe[READ_END]; ++ ++ launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE); ++ g_subprocess_launcher_take_fd (launcher, sync_pipe[WRITE_END], 3); ++ sync_pipe[WRITE_END] = -1; ++ ++ f->proxy = g_subprocess_launcher_spawn (launcher, &error, ++ f->proxy_path, ++ "--fd=3", ++ f->dbus_address, ++ f->proxy_socket, ++ "--filter", ++ NULL); ++ g_assert_no_error (error); ++ g_assert_nonnull (f->proxy); ++ ++ 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); ++ g_assert_no_error (error); ++ g_dbus_connection_add_filter (f->proxied_conn, reply_count_filter, &sandbox_counts, NULL); ++ sandbox_name = g_dbus_connection_get_unique_name (f->proxied_conn); ++ ++ caller = g_dbus_connection_new_for_address_sync (f->dbus_address, ++ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT ++ | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION, ++ NULL, NULL, &error); ++ g_assert_no_error (error); ++ g_dbus_connection_add_filter (caller, reply_count_filter, &caller_counts, NULL); ++ caller_name = g_dbus_connection_get_unique_name (caller); ++ ++ for (i = 0; i < G_N_ELEMENTS (reply_cases); i++) ++ { ++ const ReplyCase *t = &reply_cases[i]; ++ g_autoptr(GDBusMessage) call = NULL; ++ g_autoptr(GDBusMessage) probe = NULL; ++ guint32 call_serial = 0; ++ ReplyCounts caller_before; ++ ++ g_test_message ("#%zu: %s", i, t->label); ++ ++ call = g_dbus_message_new_method_call (sandbox_name, "/", ++ "com.example.Ignore", "Ignore"); ++ g_dbus_connection_send_message (caller, call, ++ G_DBUS_SEND_MESSAGE_FLAGS_NONE, ++ &call_serial, &error); ++ g_assert_no_error (error); ++ g_assert_cmpuint (call_serial, !=, 0); ++ flush_through_proxy (caller, sandbox_name); ++ ++ caller_before = caller_counts; ++ ++ switch (t->type) ++ { ++ case G_DBUS_MESSAGE_TYPE_METHOD_RETURN: ++ probe = g_dbus_message_new_method_reply (call); ++ g_dbus_message_set_destination (probe, caller_name); ++ break; ++ ++ case G_DBUS_MESSAGE_TYPE_ERROR: ++ probe = g_dbus_message_new_method_error (call, "com.example.No", "no"); ++ g_dbus_message_set_destination (probe, caller_name); ++ break; ++ ++ case G_DBUS_MESSAGE_TYPE_SIGNAL: ++ case G_DBUS_MESSAGE_TYPE_METHOD_CALL: ++ case G_DBUS_MESSAGE_TYPE_INVALID: ++ default: ++ g_assert_not_reached (); ++ } ++ ++ g_dbus_message_set_reply_serial (probe, call_serial); ++ g_dbus_connection_send_message (f->proxied_conn, probe, ++ G_DBUS_SEND_MESSAGE_FLAGS_NONE, ++ NULL, &error); ++ g_assert_no_error (error); ++ flush_through_proxy (caller, sandbox_name); ++ ++ if (t->type == G_DBUS_MESSAGE_TYPE_METHOD_RETURN) ++ g_assert_cmpint (caller_counts.n_returns, ==, caller_before.n_returns + 1); ++ else ++ g_assert_cmpint (caller_counts.n_errors, ==, caller_before.n_errors + 2); ++ } ++ ++ g_dbus_connection_close_sync (caller, NULL, NULL); ++} ++ + static void + teardown (Fixture *f, + gconstpointer context G_GNUC_UNUSED) +@@ -260,6 +465,7 @@ + g_test_init (&argc, &argv, NULL); + + g_test_add ("/basics", Fixture, NULL, setup, test_basics, teardown); ++ g_test_add ("/reply", Fixture, NULL, setup, test_reply, teardown); + + return g_test_run (); + } diff -Nru xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-tests-2.patch xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-tests-2.patch --- xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-tests-2.patch 1969-12-31 18:00:00.000000000 -0600 +++ xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-tests-2.patch 2026-10-20 15:43:58.000000000 -0500 @@ -0,0 +1,106 @@ +Origin: https://github.com/flatpak/xdg-dbus-proxy/commit/e7f2f89bb305f27e6191a8c3d7a1085924ab00e5 +Reviewed-by: Simon Quigley <[email protected]> +Last-Update: 2026-10-20 + +Replayed on the existing fixture. The 0.1.8 harness is not +included. + +From e7f2f89bb305f27e6191a8c3d7a1085924ab00e5 Mon Sep 17 00:00:00 2001 +From: Simon McVittie <[email protected]> +Date: Mon, 7 Sep 2026 15:30:32 +0100 +Subject: [PATCH] tests: Assert that "replies" of inappropriate types aren't + accepted + +Regression test for part of CVE-2026-94422 + +Helps: CVE-2026-94422 +Helps: https://github.com/flatpak/xdg-dbus-proxy/security/advisories/GHSA-2cgv-pwcq-wvpq +Signed-off-by: Simon McVittie <[email protected]> +--- + tests/test-proxy.c | 55 ++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 53 insertions(+), 2 deletions(-) + +--- a/tests/test-proxy.c ++++ b/tests/test-proxy.c +@@ -199,6 +199,7 @@ + int n_broadcasts; + int n_returns; + int n_errors; ++ int n_malice; + } ReplyCounts; + + static GDBusMessage * +@@ -212,6 +213,9 @@ + if (!incoming) + return message; + ++ if (g_strcmp0 (g_dbus_message_get_interface (message), "com.example.Malice") == 0) ++ counts->n_malice++; ++ + switch (g_dbus_message_get_message_type (message)) + { + case G_DBUS_MESSAGE_TYPE_METHOD_CALL: +@@ -276,13 +280,18 @@ + { + const char *label; + GDBusMessageType type; ++ gboolean broadcast; + } ReplyCase; + +-/* 4427d5d0eb6d, replayed on the 0.1.4 fixture. */ ++/* 4427d5d0eb6d legitimate replies, e7f2f89bb305 wrong types. ++ * Replayed on the 0.1.4 fixture. */ + static const ReplyCase reply_cases[] = + { +- { "method return is delivered", G_DBUS_MESSAGE_TYPE_METHOD_RETURN }, +- { "error is delivered", G_DBUS_MESSAGE_TYPE_ERROR }, ++ { "method return is delivered", G_DBUS_MESSAGE_TYPE_METHOD_RETURN, FALSE }, ++ { "error is delivered", G_DBUS_MESSAGE_TYPE_ERROR, FALSE }, ++ { "unicast signal is not a reply", G_DBUS_MESSAGE_TYPE_SIGNAL, FALSE }, ++ { "broadcast signal is not a reply", G_DBUS_MESSAGE_TYPE_SIGNAL, TRUE }, ++ { "method call is not a reply", G_DBUS_MESSAGE_TYPE_METHOD_CALL, FALSE }, + }; + + static void +@@ -363,6 +372,17 @@ + + switch (t->type) + { ++ case G_DBUS_MESSAGE_TYPE_SIGNAL: ++ probe = g_dbus_message_new_signal ("/", "com.example.Malice", "ShouldNotBeAllowed"); ++ if (!t->broadcast) ++ g_dbus_message_set_destination (probe, caller_name); ++ break; ++ ++ case G_DBUS_MESSAGE_TYPE_METHOD_CALL: ++ probe = g_dbus_message_new_method_call (caller_name, "/", ++ "com.example.Malice", "ShouldNotBeAllowed"); ++ break; ++ + case G_DBUS_MESSAGE_TYPE_METHOD_RETURN: + probe = g_dbus_message_new_method_reply (call); + g_dbus_message_set_destination (probe, caller_name); +@@ -373,8 +393,6 @@ + g_dbus_message_set_destination (probe, caller_name); + break; + +- case G_DBUS_MESSAGE_TYPE_SIGNAL: +- case G_DBUS_MESSAGE_TYPE_METHOD_CALL: + case G_DBUS_MESSAGE_TYPE_INVALID: + default: + g_assert_not_reached (); +@@ -387,10 +405,13 @@ + g_assert_no_error (error); + flush_through_proxy (caller, sandbox_name); + ++ g_assert_cmpint (caller_counts.n_malice, ==, caller_before.n_malice); + if (t->type == G_DBUS_MESSAGE_TYPE_METHOD_RETURN) + g_assert_cmpint (caller_counts.n_returns, ==, caller_before.n_returns + 1); +- else ++ else if (t->type == G_DBUS_MESSAGE_TYPE_ERROR) + g_assert_cmpint (caller_counts.n_errors, ==, caller_before.n_errors + 2); ++ else ++ g_assert_cmpint (caller_counts.n_errors, ==, caller_before.n_errors + 1); + } + + g_dbus_connection_close_sync (caller, NULL, NULL); diff -Nru xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-tests-3.patch xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-tests-3.patch --- xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-tests-3.patch 1969-12-31 18:00:00.000000000 -0600 +++ xdg-dbus-proxy-0.1.4/debian/patches/CVE-2026-94422-tests-3.patch 2026-10-20 15:43:58.000000000 -0500 @@ -0,0 +1,158 @@ +Origin: https://github.com/flatpak/xdg-dbus-proxy/commit/78045ceec1330bd40c91a44d1b89e2bf108410fe +Reviewed-by: Simon Quigley <[email protected]> +Last-Update: 2026-10-20 + +Replayed on the existing fixture. The 0.1.8 harness is not +included. + +From 78045ceec1330bd40c91a44d1b89e2bf108410fe Mon Sep 17 00:00:00 2001 +From: Simon McVittie <[email protected]> +Date: Mon, 7 Sep 2026 15:33:04 +0100 +Subject: [PATCH] tests: Assert that forged replies cannot be sent to wrong + destination + +Reproduces part of CVE-2026-94422 + +Helps: CVE-2026-94422 +Helps: https://github.com/flatpak/xdg-dbus-proxy/security/advisories/GHSA-2cgv-pwcq-wvpq +Signed-off-by: Simon McVittie <[email protected]> +--- + tests/test-proxy.c | 97 ++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 86 insertions(+), 11 deletions(-) + +--- a/tests/test-proxy.c ++++ b/tests/test-proxy.c +@@ -281,17 +281,23 @@ + const char *label; + GDBusMessageType type; + gboolean broadcast; ++ gboolean misdirected; ++ gboolean allowed; + } ReplyCase; + +-/* 4427d5d0eb6d legitimate replies, e7f2f89bb305 wrong types. +- * Replayed on the 0.1.4 fixture. */ ++/* 4427d5d0eb6d legitimate replies, e7f2f89bb305 wrong types, ++ * 78045ceec133 wrong destination. Replayed on the 0.1.4 fixture. */ + static const ReplyCase reply_cases[] = + { +- { "method return is delivered", G_DBUS_MESSAGE_TYPE_METHOD_RETURN, FALSE }, +- { "error is delivered", G_DBUS_MESSAGE_TYPE_ERROR, FALSE }, +- { "unicast signal is not a reply", G_DBUS_MESSAGE_TYPE_SIGNAL, FALSE }, +- { "broadcast signal is not a reply", G_DBUS_MESSAGE_TYPE_SIGNAL, TRUE }, +- { "method call is not a reply", G_DBUS_MESSAGE_TYPE_METHOD_CALL, FALSE }, ++ { "method return is delivered", G_DBUS_MESSAGE_TYPE_METHOD_RETURN, FALSE, FALSE, TRUE }, ++ { "error is delivered", G_DBUS_MESSAGE_TYPE_ERROR, FALSE, FALSE, TRUE }, ++ { "unicast signal is not a reply", G_DBUS_MESSAGE_TYPE_SIGNAL, FALSE, FALSE, FALSE }, ++ { "broadcast signal is not a reply", G_DBUS_MESSAGE_TYPE_SIGNAL, TRUE, FALSE, FALSE }, ++ { "method call is not a reply", G_DBUS_MESSAGE_TYPE_METHOD_CALL, FALSE, FALSE, FALSE }, ++ { "unicast signal to someone else is not a reply", G_DBUS_MESSAGE_TYPE_SIGNAL, FALSE, TRUE, FALSE }, ++ { "method call to someone else is not a reply", G_DBUS_MESSAGE_TYPE_METHOD_CALL, FALSE, TRUE, FALSE }, ++ { "method return to someone else is not a reply", G_DBUS_MESSAGE_TYPE_METHOD_RETURN, FALSE, TRUE, FALSE }, ++ { "error to someone else is not a reply", G_DBUS_MESSAGE_TYPE_ERROR, FALSE, TRUE, FALSE }, + }; + + static void +@@ -301,13 +307,16 @@ + g_autoptr(GSubprocessLauncher) launcher = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GDBusConnection) caller = NULL; ++ g_autoptr(GDBusConnection) other = NULL; + ReplyCounts caller_counts = { 0, }; ++ ReplyCounts other_counts = { 0, }; + ReplyCounts sandbox_counts = { 0, }; + int sync_pipe[PIPE_FDS]; + char buf; + ssize_t bytes_read; + const char *sandbox_name; + const char *caller_name; ++ const char *other_name; + gsize i; + + alarm (60); +@@ -349,13 +358,23 @@ + g_dbus_connection_add_filter (caller, reply_count_filter, &caller_counts, NULL); + caller_name = g_dbus_connection_get_unique_name (caller); + ++ other = g_dbus_connection_new_for_address_sync (f->dbus_address, ++ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT ++ | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION, ++ NULL, NULL, &error); ++ g_assert_no_error (error); ++ g_dbus_connection_add_filter (other, reply_count_filter, &other_counts, NULL); ++ other_name = g_dbus_connection_get_unique_name (other); ++ + for (i = 0; i < G_N_ELEMENTS (reply_cases); i++) + { + const ReplyCase *t = &reply_cases[i]; + g_autoptr(GDBusMessage) call = NULL; + g_autoptr(GDBusMessage) probe = NULL; ++ const char *dest; + guint32 call_serial = 0; + ReplyCounts caller_before; ++ ReplyCounts other_before; + + g_test_message ("#%zu: %s", i, t->label); + +@@ -369,28 +388,34 @@ + flush_through_proxy (caller, sandbox_name); + + caller_before = caller_counts; ++ other_before = other_counts; ++ dest = t->misdirected ? other_name : caller_name; + + switch (t->type) + { + case G_DBUS_MESSAGE_TYPE_SIGNAL: + probe = g_dbus_message_new_signal ("/", "com.example.Malice", "ShouldNotBeAllowed"); + if (!t->broadcast) +- g_dbus_message_set_destination (probe, caller_name); ++ g_dbus_message_set_destination (probe, dest); + break; + + case G_DBUS_MESSAGE_TYPE_METHOD_CALL: +- probe = g_dbus_message_new_method_call (caller_name, "/", ++ probe = g_dbus_message_new_method_call (dest, "/", + "com.example.Malice", "ShouldNotBeAllowed"); + break; + + case G_DBUS_MESSAGE_TYPE_METHOD_RETURN: + probe = g_dbus_message_new_method_reply (call); +- g_dbus_message_set_destination (probe, caller_name); ++ g_dbus_message_set_destination (probe, dest); ++ if (t->misdirected) ++ g_dbus_message_set_body (probe, g_variant_new ("(s)", "blocked")); + break; + + case G_DBUS_MESSAGE_TYPE_ERROR: + probe = g_dbus_message_new_method_error (call, "com.example.No", "no"); +- g_dbus_message_set_destination (probe, caller_name); ++ g_dbus_message_set_destination (probe, dest); ++ if (t->misdirected) ++ g_dbus_message_set_body (probe, g_variant_new ("(s)", "blocked")); + break; + + case G_DBUS_MESSAGE_TYPE_INVALID: +@@ -405,16 +430,20 @@ + g_assert_no_error (error); + flush_through_proxy (caller, sandbox_name); + ++ g_assert_cmpint (other_counts.n_malice, ==, other_before.n_malice); + g_assert_cmpint (caller_counts.n_malice, ==, caller_before.n_malice); +- if (t->type == G_DBUS_MESSAGE_TYPE_METHOD_RETURN) ++ if (t->allowed && t->type == G_DBUS_MESSAGE_TYPE_METHOD_RETURN) + g_assert_cmpint (caller_counts.n_returns, ==, caller_before.n_returns + 1); +- else if (t->type == G_DBUS_MESSAGE_TYPE_ERROR) ++ else ++ g_assert_cmpint (caller_counts.n_returns, ==, caller_before.n_returns); ++ if (t->allowed && t->type == G_DBUS_MESSAGE_TYPE_ERROR) + g_assert_cmpint (caller_counts.n_errors, ==, caller_before.n_errors + 2); + else + g_assert_cmpint (caller_counts.n_errors, ==, caller_before.n_errors + 1); + } + + g_dbus_connection_close_sync (caller, NULL, NULL); ++ g_dbus_connection_close_sync (other, NULL, NULL); + } + + static void diff -Nru xdg-dbus-proxy-0.1.4/debian/patches/series xdg-dbus-proxy-0.1.4/debian/patches/series --- xdg-dbus-proxy-0.1.4/debian/patches/series 2026-04-15 14:27:48.000000000 -0500 +++ xdg-dbus-proxy-0.1.4/debian/patches/series 2026-10-20 15:43:58.000000000 -0500 @@ -2,3 +2,9 @@ Fix-GVariant-reference-leaks.patch flatpak-proxy-Use-g_autoptr-in-validate_arg0_match.patch Improve-detection-of-eavesdrop-true.patch +CVE-2026-94422-1.patch +CVE-2026-94422-2.patch +CVE-2026-94422-3.patch +CVE-2026-94422-tests-1.patch +CVE-2026-94422-tests-2.patch +CVE-2026-94422-tests-3.patch
OpenPGP_signature.asc
Description: OpenPGP digital signature
