From a87931c257a6bb1b7c104623beadd9b14d766ca6 Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Fri, 8 Mar 2024 19:28:15 +0000
Subject: [PATCH 04/18] tests: Add support for subscribing to signals from a
 well-known name

Signed-off-by: Simon McVittie <smcv@collabora.com>

CVE: CVE-2024-34397
Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/a87931c257a6bb1b7c104623beadd9b14d766ca6]
Signed-off-by: Peter Marko <peter.marko@siemens.com>
---
 gio/tests/gdbus-subscribe.c | 133 ++++++++++++++++++++++++++++++++++--
 1 file changed, 126 insertions(+), 7 deletions(-)

diff --git a/gio/tests/gdbus-subscribe.c b/gio/tests/gdbus-subscribe.c
index 3f53e1d7f..3d2a14e03 100644
--- 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_unique_name =
       /* 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_unique_name =
   },
 };
 
+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             *f,
   GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER];
   const char *sender;
 
-  if (subscribe->sender != TEST_CONN_NONE)
+  if (subscribe->string_sender != NULL)
     {
-      sender = f->unique_names[subscribe->sender];
+      sender = subscribe->string_sender;
+      g_test_message ("\tSender: %s", sender);
+    }
+  else if (subscribe->unique_sender != TEST_CONN_NONE)
+    {
+      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
@@ -689,6 +765,43 @@ fixture_emit_signal (Fixture              *f,
   connection_wait_for_bus (f->conns[signal->sender]);
 }
 
+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,
@@ -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();
 }
-- 
2.30.2

