From af18ce31c583e66b5a5c419a20cf9cd2bc133e63 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 22 Oct 2014 18:01:19 +0200 Subject: [PATCH] kdbus.h: add KDBUS_CMD_BUS_CREATOR_INFO 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 --- bus.c | 70 ++++++++++++++++++++++++ bus.h | 5 ++ handle.c | 9 +++- kdbus.h | 4 ++ kdbus.txt | 37 ++++++++++++- test/Makefile | 1 + test/test-bus.c | 117 +++++++++++++++++++++++++++++++++++++++++ test/test-connection.c | 77 --------------------------- 8 files changed, 240 insertions(+), 80 deletions(-) create mode 100644 test/test-bus.c diff --git a/bus.c b/bus.c index 89b1d53..919a243 100644 --- 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 44bbe15..5891c80 100644 --- 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); diff --git a/handle.c b/handle.c index 3d59415..08645fc 100644 --- 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 50b4ec4..5d2526c 100644 --- 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), diff --git a/kdbus.txt b/kdbus.txt index 11da3ac..dfe665b 100644 --- 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 diff --git a/test/Makefile b/test/Makefile index 0c2ccc1..aa9179e 100644 --- a/test/Makefile +++ b/test/Makefile @@ -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 index 0000000..f74baa9 --- /dev/null +++ b/test/test-bus.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/test/test-connection.c b/test/test-connection.c index f451794..2e024e2 100644 --- a/test/test-connection.c +++ b/test/test-connection.c @@ -16,83 +16,6 @@ #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; -- 2.34.1