#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);
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)
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;
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;
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;
}