kdbus.h: add KDBUS_CMD_BUS_CREATOR_INFO
authorDaniel Mack <daniel@zonque.org>
Wed, 22 Oct 2014 16:01:19 +0000 (18:01 +0200)
committerDaniel Mack <daniel@zonque.org>
Wed, 22 Oct 2014 16:03:38 +0000 (18:03 +0200)
Add a call to return metadata on the task that created a bus, at the
moment it did so. The call behaves similar to KDBUS_CMD_CONN_INFO, and
shares the same dispatcher code in handle.c.

While at it, factor out bus-related test functions to their own file,
and also add some code test the new ioctl.

Signed-off-by: Daniel Mack <daniel@zonque.org>
bus.c
bus.h
handle.c
kdbus.h
kdbus.txt
test/Makefile
test/test-bus.c [new file with mode: 0644]
test/test-connection.c

diff --git a/bus.c b/bus.c
index 89b1d53a71e7d8024f18e9809543e0603371bdc4..919a243d1e115eadc1858ff78195f0bc4049093b 100644 (file)
--- a/bus.c
+++ b/bus.c
@@ -28,6 +28,7 @@
 #include "domain.h"
 #include "endpoint.h"
 #include "item.h"
+#include "metadata.h"
 #include "names.h"
 #include "policy.h"
 
@@ -95,6 +96,7 @@ static void __kdbus_bus_free(struct kref *kref)
        kdbus_name_registry_free(bus->name_registry);
        kdbus_domain_unref(bus->domain);
        kdbus_policy_db_clear(&bus->policy_db);
+       kdbus_meta_free(bus->meta);
        kfree(bus->name);
        kfree(bus);
 }
@@ -207,6 +209,55 @@ static struct kdbus_bus *kdbus_bus_find(struct kdbus_domain *domain,
        return bus;
 }
 
+/**
+ * kdbus_cmd_bus_creator_info() - get information on a bus creator
+ * @conn:      The querying connection
+ * @cmd_info:  The command buffer, as passed in from the ioctl
+ *
+ * Gather information on the creator of the bus @conn is connected to.
+ *
+ * Return: 0 on success, error otherwise.
+ */
+int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn,
+                              struct kdbus_cmd_conn_info *cmd_info)
+{
+       struct kdbus_bus *bus = conn->bus;
+       struct kdbus_pool_slice *slice;
+       struct kdbus_conn_info info = {};
+       int ret;
+
+       info.size = sizeof(info) + bus->meta->size;
+       info.id = bus->id;
+       info.flags = bus->bus_flags;
+
+       if (!kdbus_meta_ns_eq(conn->meta, bus->meta))
+               return -EPERM;
+
+       ret = kdbus_pool_slice_alloc(conn->pool, &slice, info.size);
+       if (ret < 0)
+               return ret;
+
+       ret = kdbus_pool_slice_copy(slice, 0, &info, sizeof(info));
+       if (ret < 0)
+               goto exit_free_slice;
+
+       ret = kdbus_pool_slice_copy(slice, sizeof(info), bus->meta->data,
+                                   bus->meta->size);
+       if (ret < 0)
+               goto exit_free_slice;
+
+       /* write back the offset */
+       cmd_info->offset = kdbus_pool_slice_offset(slice);
+       kdbus_pool_slice_flush(slice);
+       kdbus_pool_slice_make_public(slice);
+
+       return 0;
+
+exit_free_slice:
+       kdbus_pool_slice_free(slice);
+       return ret;
+}
+
 /**
  * kdbus_bus_new() - create a new bus
  * @domain:            The domain to work on
@@ -272,6 +323,24 @@ int kdbus_bus_new(struct kdbus_domain *domain,
        /* generate unique bus id */
        generate_random_uuid(b->id128);
 
+       /* cache the metadata/credentials of the creator */
+       ret = kdbus_meta_new(&b->meta);
+       if (ret < 0)
+               return ret;
+
+       ret = kdbus_meta_append(b->meta, NULL, 0,
+                               KDBUS_ATTACH_CREDS      |
+                               KDBUS_ATTACH_TID_COMM   |
+                               KDBUS_ATTACH_PID_COMM   |
+                               KDBUS_ATTACH_EXE        |
+                               KDBUS_ATTACH_CMDLINE    |
+                               KDBUS_ATTACH_CGROUP     |
+                               KDBUS_ATTACH_CAPS       |
+                               KDBUS_ATTACH_SECLABEL   |
+                               KDBUS_ATTACH_AUDIT);
+       if (ret < 0)
+               goto exit_free;
+
        b->name = kstrdup(name, GFP_KERNEL);
        if (!b->name) {
                ret = -ENOMEM;
@@ -322,6 +391,7 @@ exit_free_reg:
 exit_free_name:
        kfree(b->name);
 exit_free:
+       kdbus_meta_free(b->meta);
        kdbus_policy_db_clear(&b->policy_db);
        kdbus_domain_unref(b->domain);
        kfree(b);
diff --git a/bus.h b/bus.h
index 44bbe15ca146f1a621e5879fb1f439884291948c..5891c80709615b3c2993244b4a9a2eaa23a3f2d4 100644 (file)
--- a/bus.h
+++ b/bus.h
@@ -48,6 +48,7 @@
  * @conn_rwlock:       Read/Write lock for all lists of child connections
  * @conn_hash:         Map of connection IDs
  * @monitors_list:     Connections that monitor this bus
+ * @meta:              Meta information about the bus creator
  *
  * A bus provides a "bus" endpoint / device node.
  *
@@ -81,6 +82,8 @@ struct kdbus_bus {
        struct rw_semaphore conn_rwlock;
        DECLARE_HASHTABLE(conn_hash, 8);
        struct list_head monitors_list;
+
+       struct kdbus_meta *meta;
 };
 
 int kdbus_bus_make_user(const struct kdbus_cmd_make *make,
@@ -91,6 +94,8 @@ int kdbus_bus_new(struct kdbus_domain *domain,
                  const struct kdbus_bloom_parameter *bloom,
                  umode_t mode, kuid_t uid, kgid_t gid,
                  struct kdbus_bus **bus);
+int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn,
+                              struct kdbus_cmd_conn_info *cmd_info);
 struct kdbus_bus *kdbus_bus_ref(struct kdbus_bus *bus);
 struct kdbus_bus *kdbus_bus_unref(struct kdbus_bus *bus);
 void kdbus_bus_disconnect(struct kdbus_bus *bus);
index 3d59415e29c50c0843aa854407fd62371ccac3b6..08645fcb3fd416c8471698504544a4ac5ced277c 100644 (file)
--- a/handle.c
+++ b/handle.c
@@ -843,7 +843,8 @@ static long kdbus_handle_ioctl_ep_connected(struct file *file, unsigned int cmd,
                break;
        }
 
-       case KDBUS_CMD_CONN_INFO: {
+       case KDBUS_CMD_CONN_INFO:
+       case KDBUS_CMD_BUS_CREATOR_INFO: {
                struct kdbus_cmd_conn_info *cmd_info;
 
                /* return the properties of a connection */
@@ -860,7 +861,11 @@ static long kdbus_handle_ioctl_ep_connected(struct file *file, unsigned int cmd,
                if (ret < 0)
                        break;
 
-               ret = kdbus_cmd_conn_info(conn, cmd_info);
+               if (cmd == KDBUS_CMD_CONN_INFO)
+                       ret = kdbus_cmd_conn_info(conn, cmd_info);
+               else
+                       ret = kdbus_cmd_bus_creator_info(conn, cmd_info);
+
                if (ret < 0)
                        break;
 
diff --git a/kdbus.h b/kdbus.h
index 50b4ec41b318178bcc93ed02d10ff4c79620ece0..5d2526cfdbcd162d261df95aa00a20031a10d180 100644 (file)
--- a/kdbus.h
+++ b/kdbus.h
@@ -856,6 +856,8 @@ struct kdbus_cmd_match {
  * @KDBUS_CMD_CONN_UPDATE:     Update the properties of a connection. Used to
  *                             update the metadata subscription mask and
  *                             policy.
+ * @KDBUS_CMD_BUS_CREATOR_INFO:        Retrieve information of the creator of the bus
+ *                             a connection is attached to.
  * @KDBUS_CMD_ENDPOINT_UPDATE: Update the properties of a custom enpoint. Used
  *                             to update the policy.
  * @KDBUS_CMD_MATCH_ADD:       Install a match which broadcast messages should
@@ -894,6 +896,8 @@ enum kdbus_ioctl_type {
                                              struct kdbus_cmd_conn_info),
        KDBUS_CMD_CONN_UPDATE =         _IOW(KDBUS_IOCTL_MAGIC, 0x61,
                                             struct kdbus_cmd_update),
+       KDBUS_CMD_BUS_CREATOR_INFO =    _IOWR(KDBUS_IOCTL_MAGIC, 0x62,
+                                             struct kdbus_cmd_conn_info),
 
        KDBUS_CMD_ENDPOINT_UPDATE =     _IOW(KDBUS_IOCTL_MAGIC, 0x71,
                                             struct kdbus_cmd_update),
index 11da3acf9f24716482866b9dc16a770a682aba15..dfe665b860a53480f208c088e2b378fa33f2c09c 100644 (file)
--- a/kdbus.txt
+++ b/kdbus.txt
@@ -598,7 +598,42 @@ Once the caller is finished with parsing the return buffer, it needs to call
 KDBUS_CMD_FREE for the offset.
 
 
-6.5 Updating connection details
+6.5 Getting information about a connection's bus creator
+--------------------------------------------------------
+
+The KDBUS_CMD_BUS_CREATOR_INFO ioctl takes the same struct as
+KDBUS_CMD_CONN_INFO but is used to retrieve information about the creator of
+the bus the connection is attached to. The metadata returned by this call is
+collected during the creation of the bus and is never altered afterwards, so
+it provides pristine information on the task that created the bus, at the
+moment when it did so.
+
+In response to this call, a slice in the connection's pool is allocated and
+filled with an object of type struct kdbus_conn_info, pointed to by the ioctl's
+'offset' field.
+
+struct kdbus_conn_info {
+  __u64 size;
+    The overall size of the struct, including all its items.
+
+  __u64 id;
+    The bus' ID
+
+  __u64 flags;
+    The bus' flags as specified when it was created.
+
+  __u64 kernel_flags;
+    Valid flags for this command, returned by the kernel upon each call.
+
+  struct kdbus_item items[0];
+    Metadata information is stored in items here.
+};
+
+Once the caller is finished with parsing the return buffer, it needs to call
+KDBUS_CMD_FREE for the offset.
+
+
+6.6 Updating connection details
 -------------------------------
 
 Some of a connection's details can be updated with the KDBUS_CMD_CONN_UPDATE
index 0c2ccc15bd2f4c879b0bc1d255328b9e81bcc78c..aa9179e266353730e7571340b9c411302efa75a2 100644 (file)
@@ -22,6 +22,7 @@ OBJS= \
        kdbus-test.o            \
        test-activator.o        \
        test-benchmark.o        \
+       test-bus.o              \
        test-chat.o             \
        test-connection.o       \
        test-daemon.o           \
diff --git a/test/test-bus.c b/test/test-bus.c
new file mode 100644 (file)
index 0000000..f74baa9
--- /dev/null
@@ -0,0 +1,117 @@
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <errno.h>
+#include <assert.h>
+#include <limits.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <stdbool.h>
+
+#include "kdbus-util.h"
+#include "kdbus-enum.h"
+#include "kdbus-test.h"
+
+static int test_bus_creator_info(const char *bus_path)
+{
+       int ret;
+       struct kdbus_conn *conn;
+       struct kdbus_cmd_conn_info cmd = {};
+
+       cmd.size = sizeof(cmd);
+
+       conn = kdbus_hello(bus_path, 0, NULL, 0);
+       ASSERT_RETURN(conn);
+
+       ret = ioctl(conn->fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
+       ASSERT_RETURN_VAL(ret == 0, ret);
+
+       ret = kdbus_free(conn, cmd.offset);
+       ASSERT_RETURN_VAL(ret == 0, ret);
+
+       return 0;
+}
+
+int kdbus_test_bus_make(struct kdbus_test_env *env)
+{
+       struct {
+               struct kdbus_cmd_make head;
+
+               /* bloom size item */
+               struct {
+                       uint64_t size;
+                       uint64_t type;
+                       struct kdbus_bloom_parameter bloom;
+               } bs;
+
+               /* name item */
+               uint64_t n_size;
+               uint64_t n_type;
+               char name[64];
+       } bus_make;
+       char s[PATH_MAX];
+       int ret;
+       uid_t uid;
+
+       env->control_fd = open("/dev/" KBUILD_MODNAME "/control",
+                              O_RDWR|O_CLOEXEC);
+       ASSERT_RETURN(env->control_fd >= 0);
+
+       memset(&bus_make, 0, sizeof(bus_make));
+
+       bus_make.bs.size = sizeof(bus_make.bs);
+       bus_make.bs.type = KDBUS_ITEM_BLOOM_PARAMETER;
+       bus_make.bs.bloom.size = 64;
+       bus_make.bs.bloom.n_hash = 1;
+
+       bus_make.n_type = KDBUS_ITEM_MAKE_NAME;
+
+       uid = getuid();
+
+       /* missing uid prefix */
+       snprintf(bus_make.name, sizeof(bus_make.name), "foo");
+       bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
+       bus_make.head.size = sizeof(struct kdbus_cmd_make) +
+                            sizeof(bus_make.bs) + bus_make.n_size;
+       ret = ioctl(env->control_fd, KDBUS_CMD_BUS_MAKE, &bus_make);
+       ASSERT_RETURN(ret == -1 && errno == EINVAL);
+
+       /* non alphanumeric character */
+       snprintf(bus_make.name, sizeof(bus_make.name), "%u-blah@123", uid);
+       bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
+       bus_make.head.size = sizeof(struct kdbus_cmd_make) +
+                            sizeof(bus_make.bs) + bus_make.n_size;
+       ret = ioctl(env->control_fd, KDBUS_CMD_BUS_MAKE, &bus_make);
+       ASSERT_RETURN(ret == -1 && errno == EINVAL);
+
+       /* '-' at the end */
+       snprintf(bus_make.name, sizeof(bus_make.name), "%u-blah-", uid);
+       bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
+       bus_make.head.size = sizeof(struct kdbus_cmd_make) +
+                            sizeof(bus_make.bs) + bus_make.n_size;
+       ret = ioctl(env->control_fd, KDBUS_CMD_BUS_MAKE, &bus_make);
+       ASSERT_RETURN(ret == -1 && errno == EINVAL);
+
+       /* create a new bus */
+       snprintf(bus_make.name, sizeof(bus_make.name), "%u-blah-1", uid);
+       bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
+       bus_make.head.size = sizeof(struct kdbus_cmd_make) +
+                            sizeof(bus_make.bs) + bus_make.n_size;
+       ret = ioctl(env->control_fd, KDBUS_CMD_BUS_MAKE, &bus_make);
+       ASSERT_RETURN(ret == 0);
+       snprintf(s, sizeof(s), "/dev/" KBUILD_MODNAME "/%u-blah-1/bus", uid);
+       ASSERT_RETURN(access(s, F_OK) == 0);
+
+       ret = test_bus_creator_info(s);
+       ASSERT_RETURN(ret == 0);
+
+       /* can't use the same fd for bus make twice */
+       ret = ioctl(env->control_fd, KDBUS_CMD_BUS_MAKE, &bus_make);
+       ASSERT_RETURN(ret == -1 && errno == EBADFD);
+
+       return TEST_OK;
+}
index f4517949f4d01aeefebf1ae1637b211541770dbc..2e024e2ea6e2492a9b49700f8dd2022e4b6819d0 100644 (file)
 #include "kdbus-enum.h"
 #include "kdbus-test.h"
 
-int kdbus_test_bus_make(struct kdbus_test_env *env)
-{
-       struct {
-               struct kdbus_cmd_make head;
-
-               /* bloom size item */
-               struct {
-                       uint64_t size;
-                       uint64_t type;
-                       struct kdbus_bloom_parameter bloom;
-               } bs;
-
-               /* name item */
-               uint64_t n_size;
-               uint64_t n_type;
-               char name[64];
-       } bus_make;
-       char s[PATH_MAX];
-       int ret;
-       uid_t uid;
-
-       env->control_fd = open("/dev/" KBUILD_MODNAME "/control",
-                              O_RDWR|O_CLOEXEC);
-       ASSERT_RETURN(env->control_fd >= 0);
-
-       memset(&bus_make, 0, sizeof(bus_make));
-
-       bus_make.bs.size = sizeof(bus_make.bs);
-       bus_make.bs.type = KDBUS_ITEM_BLOOM_PARAMETER;
-       bus_make.bs.bloom.size = 64;
-       bus_make.bs.bloom.n_hash = 1;
-
-       bus_make.n_type = KDBUS_ITEM_MAKE_NAME;
-
-       uid = getuid();
-
-       /* missing uid prefix */
-       snprintf(bus_make.name, sizeof(bus_make.name), "foo");
-       bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
-       bus_make.head.size = sizeof(struct kdbus_cmd_make) +
-                            sizeof(bus_make.bs) + bus_make.n_size;
-       ret = ioctl(env->control_fd, KDBUS_CMD_BUS_MAKE, &bus_make);
-       ASSERT_RETURN(ret == -1 && errno == EINVAL);
-
-       /* non alphanumeric character */
-       snprintf(bus_make.name, sizeof(bus_make.name), "%u-blah@123", uid);
-       bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
-       bus_make.head.size = sizeof(struct kdbus_cmd_make) +
-                            sizeof(bus_make.bs) + bus_make.n_size;
-       ret = ioctl(env->control_fd, KDBUS_CMD_BUS_MAKE, &bus_make);
-       ASSERT_RETURN(ret == -1 && errno == EINVAL);
-
-       /* '-' at the end */
-       snprintf(bus_make.name, sizeof(bus_make.name), "%u-blah-", uid);
-       bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
-       bus_make.head.size = sizeof(struct kdbus_cmd_make) +
-                            sizeof(bus_make.bs) + bus_make.n_size;
-       ret = ioctl(env->control_fd, KDBUS_CMD_BUS_MAKE, &bus_make);
-       ASSERT_RETURN(ret == -1 && errno == EINVAL);
-
-       /* create a new bus */
-       snprintf(bus_make.name, sizeof(bus_make.name), "%u-blah-1", uid);
-       bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
-       bus_make.head.size = sizeof(struct kdbus_cmd_make) +
-                            sizeof(bus_make.bs) + bus_make.n_size;
-       ret = ioctl(env->control_fd, KDBUS_CMD_BUS_MAKE, &bus_make);
-       ASSERT_RETURN(ret == 0);
-       snprintf(s, sizeof(s), "/dev/" KBUILD_MODNAME "/%u-blah-1/bus", uid);
-       ASSERT_RETURN(access(s, F_OK) == 0);
-
-       /* can't use the same fd for bus make twice */
-       ret = ioctl(env->control_fd, KDBUS_CMD_BUS_MAKE, &bus_make);
-       ASSERT_RETURN(ret == -1 && errno == EBADFD);
-
-       return TEST_OK;
-}
-
 int kdbus_test_hello(struct kdbus_test_env *env)
 {
        struct kdbus_cmd_hello hello;