chiark / gitweb /
sd-bus: suppress installing local bus matches server side
authorLennart Poettering <lennart@poettering.net>
Wed, 17 Jun 2015 09:42:39 +0000 (11:42 +0200)
committerSven Eden <yamakuzure@gmx.net>
Tue, 14 Mar 2017 09:03:03 +0000 (10:03 +0100)
Matches that can only match against messages from the
org.freedesktop.DBus.Local service (or the local interfaces or path)
should never be installed server side, suppress them hence.

Similar, on kdbus matches that can only match driver messages shouldn't
be passed to the kernel.

src/libelogind/sd-bus/bus-internal.h
src/libelogind/sd-bus/bus-match.c
src/libelogind/sd-bus/bus-match.h
src/libelogind/sd-bus/bus-slot.c
src/libelogind/sd-bus/sd-bus.c
src/libelogind/sd-bus/test-bus-match.c

index 2ee0eabc021487a83fa1482cad782a6551ac79a3..a8e1eb1f386b24f325b3275316ec8edb2dd686b8 100644 (file)
@@ -141,6 +141,7 @@ struct sd_bus_slot {
         void *userdata;
         BusSlotType type:5;
         bool floating:1;
+        bool match_added:1;
         char *description;
 
         LIST_FIELDS(sd_bus_slot, slots);
index 7c5264fad4481ca15571cc5fe80b4d35bb2c92a1..132b37526eb12ba93f7d0c1e6a7bc1f2abb71861 100644 (file)
@@ -1149,3 +1149,40 @@ void bus_match_dump(struct bus_match_node *node, unsigned level) {
         for (c = node->child; c; c = c->next)
                 bus_match_dump(c, level + 1);
 }
+
+enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, unsigned n_components) {
+        bool found_driver = false;
+        unsigned i;
+
+        if (n_components <= 0)
+                return BUS_MATCH_GENERIC;
+
+        assert(components);
+
+        /* Checks whether the specified match can only match the
+         * pseudo-service for local messages, which we detect by
+         * sender, interface or path. If a match is not restricted to
+         * local messages, then we check if it only matches on the
+         * driver. */
+
+        for (i = 0; i < n_components; i++) {
+                const struct bus_match_component *c = components + i;
+
+                if (c->type == BUS_MATCH_SENDER) {
+                        if (streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
+                                return BUS_MATCH_LOCAL;
+
+                        if (streq_ptr(c->value_str, "org.freedesktop.DBus"))
+                                found_driver = true;
+                }
+
+                if (c->type == BUS_MATCH_INTERFACE && streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
+                        return BUS_MATCH_LOCAL;
+
+                if (c->type == BUS_MATCH_PATH && streq_ptr(c->value_str, "/org/freedesktop/DBus/Local"))
+                        return BUS_MATCH_LOCAL;
+        }
+
+        return found_driver ? BUS_MATCH_DRIVER : BUS_MATCH_GENERIC;
+
+}
index af5f65d073c67f3974c73fad6bea11db623aecab..56516be9faa0fcd5df16fb66429d02ea628a5883 100644 (file)
@@ -73,6 +73,12 @@ struct bus_match_component {
         char *value_str;
 };
 
+enum bus_match_scope {
+        BUS_MATCH_GENERIC,
+        BUS_MATCH_LOCAL,
+        BUS_MATCH_DRIVER,
+};
+
 int bus_match_run(sd_bus *bus, struct bus_match_node *root, sd_bus_message *m);
 
 int bus_match_add(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, struct match_callback *callback);
@@ -90,3 +96,5 @@ enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n
 int bus_match_parse(const char *match, struct bus_match_component **_components, unsigned *_n_components);
 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components);
 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components);
+
+enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, unsigned n_components);
index 8060e9882cccd9429945eb1f62ce606abe7d2cb6..c45247756691fcee116d0d50d35d661502217768 100644 (file)
@@ -89,7 +89,7 @@ void bus_slot_disconnect(sd_bus_slot *slot) {
 
         case BUS_MATCH_CALLBACK:
 
-                if (slot->bus->bus_client)
+                if (slot->match_added)
                         bus_remove_match_internal(slot->bus, slot->match_callback.match_string, slot->match_callback.cookie);
 
                 slot->bus->match_callbacks_modified = true;
index 05395830f7092c686aae121313f0e5876fb7ddcb..57c09d9cb3ac9e71887870873af9fca31ddd4a46 100644 (file)
@@ -2949,22 +2949,35 @@ _public_ int sd_bus_add_match(
         s->match_callback.cookie = ++bus->match_cookie;
 
         if (bus->bus_client) {
+                enum bus_match_scope scope;
 
-                if (!bus->is_kernel) {
-                        /* When this is not a kernel transport, we
-                         * store the original match string, so that we
-                         * can use it to remove the match again */
+                scope = bus_match_get_scope(components, n_components);
 
-                        s->match_callback.match_string = strdup(match);
-                        if (!s->match_callback.match_string) {
-                                r = -ENOMEM;
-                                goto finish;
+                /* Do not install server-side matches for matches
+                 * against the local service, interface or bus
+                 * path. Also, when on kdbus don't install driver
+                 * matches server side. */
+                if (scope == BUS_MATCH_GENERIC ||
+                    (!bus->is_kernel && scope == BUS_MATCH_DRIVER)) {
+
+                        if (!bus->is_kernel) {
+                                /* When this is not a kernel transport, we
+                                 * store the original match string, so that we
+                                 * can use it to remove the match again */
+
+                                s->match_callback.match_string = strdup(match);
+                                if (!s->match_callback.match_string) {
+                                        r = -ENOMEM;
+                                        goto finish;
+                                }
                         }
-                }
 
-                r = bus_add_match_internal(bus, s->match_callback.match_string, components, n_components, s->match_callback.cookie);
-                if (r < 0)
-                        goto finish;
+                        r = bus_add_match_internal(bus, s->match_callback.match_string, components, n_components, s->match_callback.cookie);
+                        if (r < 0)
+                                goto finish;
+
+                        s->match_added = true;
+                }
         }
 
         bus->match_callbacks_modified = true;
index 40c67046da41c0cb722a1eee0832889d258c2a52..a1687b1c7bb81f835b3fbfec61649f003837abac 100644 (file)
@@ -77,6 +77,15 @@ static int match_add(sd_bus_slot *slots, struct bus_match_node *root, const char
         return r;
 }
 
+static void test_match_scope(const char *match, enum bus_match_scope scope) {
+        struct bus_match_component *components = NULL;
+        unsigned n_components = 0;
+
+        assert_se(bus_match_parse(match, &components, &n_components) >= 0);
+        assert_se(bus_match_get_scope(components, n_components) == scope);
+        bus_match_parse_free(components, n_components);
+}
+
 int main(int argc, char *argv[]) {
         struct bus_match_node root = {
                 .type = BUS_MATCH_ROOT,
@@ -142,5 +151,12 @@ int main(int argc, char *argv[]) {
 
         bus_match_free(&root);
 
+        test_match_scope("interface='foobar'", BUS_MATCH_GENERIC);
+        test_match_scope("", BUS_MATCH_GENERIC);
+        test_match_scope("interface='org.freedesktop.DBus.Local'", BUS_MATCH_LOCAL);
+        test_match_scope("sender='org.freedesktop.DBus.Local'", BUS_MATCH_LOCAL);
+        test_match_scope("member='gurke',path='/org/freedesktop/DBus/Local'", BUS_MATCH_LOCAL);
+        test_match_scope("arg2='piep',sender='org.freedesktop.DBus',member='waldo'", BUS_MATCH_DRIVER);
+
         return 0;
 }