refactoring: manage kdbus commands 49/202549/6
authorAdrian Szyndela <adrian.s@samsung.com>
Fri, 29 Mar 2019 14:53:31 +0000 (15:53 +0100)
committerAdrian Szyndela <adrian.s@samsung.com>
Wed, 3 Apr 2019 07:07:01 +0000 (09:07 +0200)
This introduces helper class kdbus_command which makes it easy
to allocate stack space for kdbus commands, including space needed
for optional items.

Change-Id: If4b9ab6cbc92f4705b21373af3d94f9d88a7fd6a

src/kdbus.cpp

index cdf4429..c920145 100644 (file)
 
 #define MAX_DBUS_NAME_LEN 255
 
+constexpr uint64_t KDBUS_ITEM_HEADER_SIZE = offsetof(kdbus_item, data);
+constexpr uint64_t KDBUS_ITEM_SIZE(uint64_t s) { return KDBUS_ITEM_HEADER_SIZE + s; }
+constexpr uint64_t KDBUS_ITEM_SIZE_ALIGN(uint64_t s) { return ALIGN8(KDBUS_ITEM_SIZE(s)); }
+
+/*
+ * kdbus_command:
+ * A placeholder for kdbus_cmd_* commands designed to easily allocate them on the stack.
+ * It creates a stack buffer of appropriate size, emplaces a command in the buffer
+ * and initializes 'size' and 'flags' fields.
+ * Template parameters are:
+ * T - one of kdbus_cmd_*
+ * buffer_additional_size - size of maximum additional space needed for the command;
+ *                        by default it is 0, which means that only space needed for the command
+ *                        itself will be allocated
+ */
+template <typename T, size_t buffer_additional_size = 0>
+class kdbus_command {
+       static constexpr size_t cmd_size = ALIGN8(sizeof(T));
+       static constexpr size_t buffer_size = cmd_size + buffer_additional_size;
+       alignas(T) uint8_t buffer[buffer_size];
+public:
+       /* By default commands are initialized with no flags set, and size equal to
+        * the maximum buffer size.
+        * Parameter items_size may be used to assign some smaller value to the size,
+        * e.g. it may be set to 0, if users would like to increment command size by themselves.
+        */
+       explicit kdbus_command(uint64_t flags = 0, size_t items_size = buffer_additional_size) {
+               auto cmd = get();
+               cmd->size = cmd_size + items_size;
+               cmd->flags = flags;
+       }
+       T *get() { return reinterpret_cast<T*>(buffer); }
+};
+
+int kdbus_free_by_offset(kdbus_connection *conn, __u64 offset);
+
 static int kdbus_open_bus(kdbus_connection *conn, const char *path)
 {
        conn->fd = open(path, O_RDWR|O_NOCTTY|O_LARGEFILE|O_CLOEXEC);
@@ -50,40 +86,26 @@ static int kdbus_hello(struct kdbus_connection *conn,
                                           uint64_t attach_flags_send,
                                           uint64_t attach_flags_recv)
 {
-       struct kdbus_cmd_hello* cmd;
-       struct kdbus_cmd_free cmd_free;
-       struct kdbus_item* item;
-       size_t size = ALIGN8(sizeof(struct kdbus_cmd_hello)) + ALIGN8(offsetof(struct kdbus_item, data) + sizeof(CONNECTION_LABEL));
-
-       cmd = static_cast<struct kdbus_cmd_hello *>(calloc(1, size));
-       if (!cmd)
-               goto err;
-       cmd->size = size;
-       cmd->flags = hello_flags;
+       kdbus_command<kdbus_cmd_hello, KDBUS_ITEM_SIZE_ALIGN(sizeof(CONNECTION_LABEL))> command(hello_flags);
+       auto cmd = command.get();
+
        cmd->attach_flags_send = attach_flags_send;
        cmd->attach_flags_recv = attach_flags_recv;
        cmd->pool_size = KDBUS_POOL_SIZE;
 
-       item = cmd->items;
+       struct kdbus_item *item = cmd->items;
        item->size = offsetof(struct kdbus_item, data) + sizeof(CONNECTION_LABEL);
        item->type = KDBUS_ITEM_CONN_DESCRIPTION;
        memcpy(item->str, CONNECTION_LABEL, sizeof(CONNECTION_LABEL));
        if (ioctl(conn->fd, KDBUS_CMD_HELLO, cmd) < 0)
-               goto err;
+               return -errno;
 
        conn->pool = static_cast<char *>(mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, conn->fd, 0));
        if (MAP_FAILED == conn->pool)
-               goto err;
+               return -errno;
 
-       cmd_free.offset = cmd->offset;
-       cmd_free.size = sizeof(struct kdbus_cmd_free);
-       ioctl(conn->fd, KDBUS_CMD_FREE, &cmd_free);
-       free(cmd);
+       kdbus_free_by_offset(conn, cmd->offset);
        return 0;
-
-err:
-       free(cmd);
-       return -errno;
 }
 
 void kdbus_shared_init_fd(kdbus_connection *conn, int fd)
@@ -133,11 +155,6 @@ static uint64_t kdbus_unique_id(char const *name)
        return res;
 }
 
-union kdbus_cmd_union {
-       struct kdbus_cmd_info cmd_info;
-       uint8_t _buffer_[sizeof(struct kdbus_cmd_info) + offsetof(struct kdbus_item, data) + ALIGN8(MAX_DBUS_NAME_LEN+1)];
-};
-
 static void set_item_info(struct kdbus_item *item, const char *str, __u64 str_length, __u64 type)
 {
        item->size = (__u64)offsetof(struct kdbus_item, data) + str_length + (__u64)1;
@@ -151,51 +168,44 @@ int kdbus_get_conn_info(kdbus_connection *conn,
                                                struct kdbus_cmd_param *info,
                                                conn_info_type conn_info_type)
 {
+       kdbus_command<kdbus_cmd_info, KDBUS_ITEM_SIZE_ALIGN(ALIGN8(MAX_DBUS_NAME_LEN+1))> command(0, 0);
+       auto cmd = command.get();
+
        char const *label = NULL;
-       int r;
        uid_t uid_n = UID_INVALID;
        gid_t gid_n = GID_INVALID;
-       union kdbus_cmd_union cmd;
-
-       struct kdbus_info *conn_info;
-       struct kdbus_item *item;
-       uintptr_t items_end;
 
-       cmd.cmd_info.flags = 0;
+       cmd->flags = 0;
        if (conn_info_type == POLICY_CONN_INFO_ALL)
-               cmd.cmd_info.attach_flags = (KDBUS_ATTACH_CREDS | KDBUS_ATTACH_NAMES | KDBUS_ATTACH_SECLABEL);
+               cmd->attach_flags = (KDBUS_ATTACH_CREDS | KDBUS_ATTACH_NAMES | KDBUS_ATTACH_SECLABEL);
        else
-               cmd.cmd_info.attach_flags = KDBUS_ATTACH_NAMES;
+               cmd->attach_flags = KDBUS_ATTACH_NAMES;
 
        if (kdbus_is_unique_id(destination)) {
-               cmd.cmd_info.size = sizeof(cmd.cmd_info);
-               cmd.cmd_info.id = kdbus_unique_id(destination);
+               cmd->id = kdbus_unique_id(destination);
        } else {
-               unsigned int l = strlen(destination);
-               cmd.cmd_info.size = sizeof(struct kdbus_cmd_info) + offsetof(struct kdbus_item, data) + ALIGN8(l+1);
-               cmd.cmd_info.id = 0;
-               set_item_info(cmd.cmd_info.items, destination, l, KDBUS_ITEM_NAME);
+               auto l = strlen(destination);
+               cmd->size += KDBUS_ITEM_SIZE_ALIGN(ALIGN8(l+1));
+               cmd->id = 0;
+               set_item_info(cmd->items, destination, l, KDBUS_ITEM_NAME);
        }
-       r = ioctl(conn->fd, KDBUS_CMD_CONN_INFO, &cmd.cmd_info);
-       if (r < 0) {
+       if (ioctl(conn->fd, KDBUS_CMD_CONN_INFO, cmd) < 0) {
                if (errno == ENXIO || errno == ESRCH)
                        return DBUSPOLICY_RESULT_DEST_NOT_AVAILABLE;
 
                return DBUSPOLICY_RESULT_KDBUS_ERROR;
        }
 
-       info->free_offset = cmd.cmd_info.offset;
+       info->free_offset = cmd->offset;
 
-       conn_info = (struct kdbus_info *) ((uint8_t *) conn->pool + cmd.cmd_info.offset);
-       items_end = (uintptr_t)conn_info + (unsigned)conn_info->size;
-
-       static_assert((unsigned)KDBUS_ITEM_CREDS == KDBUS_ITEM_CREDS, "KDBUS_ITEM_CREDS not preserved when cast to unsigned");
-       static_assert((unsigned)KDBUS_ITEM_SECLABEL == KDBUS_ITEM_SECLABEL, "KDBUS_ITEM_SECLABEL not preserved when cast to unsigned");
-       static_assert((unsigned)KDBUS_ITEM_OWNED_NAME == KDBUS_ITEM_OWNED_NAME, "KDBUS_ITEM_OWNED_NAME not preserved when cast to unsigned");
+       auto conn_info = reinterpret_cast<struct kdbus_info *>((uint8_t *) conn->pool + cmd->offset);
+       uintptr_t items_end = (uintptr_t)conn_info + (size_t)conn_info->size;
 
        info->names_num = 0;
-       for (item = conn_info->items; (uintptr_t)item < items_end; item = (typeof(item))ALIGN8((uintptr_t)item + (unsigned)item->size)) {
-               switch ((unsigned)item->type) {
+       for (auto item = conn_info->items;
+                       (uintptr_t)item < items_end;
+                       item = reinterpret_cast<decltype(item)>(ALIGN8((uintptr_t)item + (size_t)item->size))) {
+               switch (item->type) {
                case KDBUS_ITEM_CREDS:
                        uid_n = item->creds.euid;
                        gid_n = item->creds.egid;
@@ -213,18 +223,19 @@ int kdbus_get_conn_info(kdbus_connection *conn,
        info->uid_n = uid_n;
        info->gid_n = gid_n;
 
-       return r;
+       return 0;
 }
 
 int kdbus_free_by_offset(kdbus_connection *conn, __u64 offset)
 {
-       struct kdbus_cmd_free cmd;
-       cmd.size = sizeof(cmd);
-       cmd.flags = 0;
-       cmd.offset = offset;
+       kdbus_command<kdbus_cmd_free> command;
+       auto cmd = command.get();
+       cmd->offset = offset;
 
-       if (ioctl(conn->fd, KDBUS_CMD_FREE, &cmd) != 0)
+       if (ioctl(conn->fd, KDBUS_CMD_FREE, cmd) != 0) {
+               LOGE("failed KDBUS_CMD_FREE");
                return errno;
+       }
 
        return 0;
 }