struct kdbus_cmd_info),
KDBUS_CMD_LIST = _IOR(KDBUS_IOCTL_MAGIC, 0x86,
struct kdbus_cmd_list),
+ KDBUS_CMD_UPDATE_METADATA = _IO(KDBUS_IOCTL_MAGIC, 0x89),
KDBUS_CMD_SEND = _IOW(KDBUS_IOCTL_MAGIC, 0x90,
struct kdbus_cmd_send),
cnt += kdbus_meta_emit_stack_kvec(&bus->meta, conn, &kvec[cnt], &meta_stack, attach_flags, &size);
if (attach_flags & KDBUS_ATTACH_AUXGROUPS) {
unsigned pay_size;
- pay = kdbus_meta_payload_new(bus->meta.auxgroups_alloc_order);
- if (!pay) {
+ if (!(pay = kdbus_meta_payload_new(bus->meta.auxgroups_alloc_order))) {
ret = -ENOMEM;
goto exit;
}
*/
#define DISABLE_KDBUS_POLICY
+static wur int kdbus_conn_meta_update(struct kdbus_conn *__restrict__ conn, bool first_time);
+
static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep,
struct file *file,
struct kdbus_cmd_hello *hello,
have_meta_fake = creds || pids || seclabel;
{
- struct kdbus_meta_payload *meta_payload = kdbus_meta_payload_new(0);
- unsigned meta_size;
- unsigned meta_items_offset;
- unsigned conn_desc_item_size = 0;
- unsigned conn_desc_len;
- if (!meta_payload)
- return ERR_PTR(-ENOMEM);
-
- /* privileged processes can impersonate somebody else */
- if (have_meta_fake) {
- meta_items_offset = offsetof(typeof(*conn), meta_fake.meta_items);
- ret = kdbus_meta_fake_collect(&meta_payload, seclabel);
- } else {
- meta_items_offset = offsetof(typeof(*conn), meta.meta_items);
- ret = kdbus_meta_proc_collect(&meta_payload, KDBUS_ATTACH_MASK_ALL & ~KDBUS_ATTACH_SECLABEL);
+ unsigned seclabel_len;
+ unsigned seclabel_item_size = 0;
+ unsigned conn_description_len;
+ unsigned conn_description_item_size = 0;
+ unsigned meta_items_offset = have_meta_fake
+ ? offsetof(typeof(*conn), meta_fake.meta_items)
+ : offsetof(typeof(*conn), meta.conn_description);
+ BUILD_BUG_ON(offsetof(typeof(*conn), meta_fake.meta_items) % 8);
+ BUILD_BUG_ON(offsetof(typeof(*conn), meta.conn_description) % 8);
+ if (seclabel) {
+ seclabel_len = strlen(seclabel);
+ seclabel_item_size = KDBUS_ITEM_SIZE(1+seclabel_len);
}
- if (ret >= 0) {
- if (conn_description) {
- ret |= KDBUS_ATTACH_CONN_DESCRIPTION;
- conn_desc_item_size = KDBUS_ITEM_SIZE(1+(conn_desc_len = strlen(conn_description)));
- }
- meta_size = kdbus_meta_payload_size(meta_payload);
- if ((conn = kmalloc(meta_items_offset + meta_size + conn_desc_item_size, GFP_KERNEL)))
- memcpy((void*)((uintptr_t)conn + meta_items_offset), kdbus_meta_payload_ptr(meta_payload), meta_size);
- else
- ret = -ENOMEM;
+ if (conn_description) {
+ conn_description_len = strlen(conn_description);
+ conn_description_item_size = KDBUS_ITEM_SIZE(1+conn_description_len);
}
- kdbus_meta_payload_free(meta_payload);
- if (ret < 0)
- return ERR_PTR(ret);
+
+ if (!(conn = kmalloc(meta_items_offset + seclabel_item_size + conn_description_item_size, GFP_KERNEL)))
+ return ERR_PTR(-ENOMEM);
BUILD_BUG_ON(offsetof(typeof(*conn), meta) != offsetof(typeof(*conn), meta_fake));
memset(conn, 0, offsetof(typeof(*conn), meta)); /* meta needs no init */
+ if (seclabel) {
+ kdbus_write_string_item((struct kdbus_item *)((uintptr_t)conn + meta_items_offset), KDBUS_ITEM_SECLABEL, seclabel, seclabel_len);
+ meta_items_offset += conn_description_item_size;
+ conn->meta_valid = KDBUS_ATTACH_SECLABEL;
+ }
if (conn_description) {
- struct kdbus_item *item = conn->description = (struct kdbus_item *)((uintptr_t)conn + meta_items_offset + meta_size);
- item->size = conn_desc_item_size;
- item->type = KDBUS_ITEM_CONN_DESCRIPTION;
- kdbus_copy_string(item->str, conn_description, conn_desc_len);
- ret |= KDBUS_ATTACH_CONN_DESCRIPTION;
+ kdbus_write_string_item(conn->description = (struct kdbus_item *)((uintptr_t)conn + meta_items_offset), KDBUS_ITEM_CONN_DESCRIPTION, conn_description, conn_description_len);
+ conn->meta_valid |= KDBUS_ATTACH_CONN_DESCRIPTION;
}
-
- conn->meta_valid = ret | KDBUS_ATTACH_NAMES;
}
conn->kref.refcount.counter = 1; /* no need for atomicity yet */
INIT_LIST_HEAD(&conn->names_list);
INIT_LIST_HEAD(&conn->dequeued_reply_list);
INIT_LIST_HEAD(&conn->enqueued_reply_list);
- conn->request_quota.counter = 1+KDBUS_CONN_MAX_REQUESTS_PENDING; /* atomicity not required due to locks */ /*atomic_set(&conn->request_count, 0);*/ /* already zeroed */
+ conn->request_quota.counter = 1+KDBUS_CONN_MAX_REQUESTS_PENDING; /* atomicity not required due to locks */
/*atomic_set(&conn->lost_count, 0);*/ /* already zeroed */
- INIT_DELAYED_WORK(&conn->work, kdbus_reply_list_scan_work);
conn->cred = get_cred(file->f_cred);
conn->pid = get_pid(task_pid(current));
get_fs_root(current->fs, &conn->root_path);
ret = have_meta_fake
? kdbus_dst_sensitive_meta_fake_collect(&conn->meta_fake.meta, creds, pids)
- : kdbus_dst_sensitive_meta_collect(&conn->meta.meta, KDBUS_ATTACH_MASK_ALL);
+ : kdbus_conn_meta_update(conn, 1);
if (ret < 0)
goto exit_unref;
- conn->meta_valid |= ret;
+ conn->meta_valid |= have_meta_fake ? ret : KDBUS_ATTACH_NAMES;
if ((ret = kdbus_pool_init(&conn->pool, conn_description, hello->pool_size)))
goto exit_unref;
kdbus_pool_slice_publish(&conn->pool, slice, &hello->offset, &hello->items_size);
kdbus_pool_slice_release(&conn->pool, slice);
+ INIT_DELAYED_WORK(&conn->work, kdbus_reply_list_scan_work);
+
return conn;
exit_slice:
kdbus_user_unref(conn->user);
}
- BUILD_BUG_ON(offsetof(typeof(conn->meta.meta), common));
- BUILD_BUG_ON(offsetof(typeof(conn->meta_fake.meta), common));
- BUILD_BUG_ON(offsetof(typeof(*conn), meta_fake.meta) != offsetof(typeof(*conn), meta.meta));
- kdbus_dst_sensitive_meta_common_destroy(&conn->meta.meta.common, conn->meta_valid);
- if (!conn->have_meta_fake)
- kdbus_dst_sensitive_meta_real_destroy(&conn->meta.meta, conn->meta_valid);
+
+ if (conn->have_meta_fake)
+ kdbus_dst_sensitive_meta_common_destroy(&conn->meta_fake.meta.common, conn->meta_valid);
+ else
+ kdbus_conn_meta_free(conn->meta.meta);
kdbus_match_db_destroy(&conn->match_db);
kdbus_pool_destroy(&conn->pool);
unsigned users;
users = max(KDBUS_ALIGN8(id) + 8, id);
- quota = krealloc(c->quota, users * sizeof(*quota), GFP_KERNEL);
- if (!quota)
+ if (!(quota = krealloc(c->quota, users * sizeof(*quota), GFP_KERNEL)))
return -ENOMEM;
do kdbus_quota_init("a[n_quota]); while (++n_quota < users);
struct kdbus_name_entry *entry = NULL;
struct kdbus_name_owner *owner = NULL;
struct kdbus_conn *owner_conn = NULL;
- struct kdbus_item *meta_items;
struct kdbus_info info;
struct kdbus_cmd_info *cmd;
struct kdbus_bus *bus = conn->ep->bus;
struct kdbus_meta_payload *meta_payload = NULL;
+ struct kdbus_conn_meta *meta = NULL;
struct kvec kvec[1/*info*/ + MAX_META_EMIT_VECS_CONN];
unsigned cnt = 0;
- const char *name;
unsigned size;
int ret;
- attach_flags_t attach_flags, valid_flags;
- #ifdef CONFIG_SECURITY
- attach_flags_t missing_flags;
- #endif
+ attach_flags_t attach_flags, valid;
+ bool fake;
struct kdbus_arg argv[] = {
{ .type = KDBUS_ITEM_NAME },
if ((ret = kdbus_sanitize_attach_flags(cmd->attach_flags, &attach_flags)))
goto exit;
- name = argv[0].item ? argv[0].item->str : NULL;
-
- if (name) {
+ if (argv[0].item) {
+ char const *name = argv[0].item->str;
entry = kdbus_name_lookup_unlocked(&bus->name_registry, name);
if (entry)
owner = kdbus_name_get_owner(entry);
ret = -ESRCH;
goto exit;
}
-
owner_conn = owner->conn;
+ kdbus_assert(owner_conn);
} else if (cmd->id > 0) {
owner_conn = kdbus_bus_find_conn_by_id(bus, cmd->id);
if (!owner_conn || !kdbus_conn_policy_see(conn, current_cred(),
goto exit;
}
- valid_flags = atomic_attach_flags_read(&owner_conn->attach_flags_send) & owner_conn->meta_valid;
- #ifdef CONFIG_SECURITY
- missing_flags = attach_flags & KDBUS_ATTACH_SECLABEL;
- #endif
- attach_flags &= valid_flags;
+ valid = owner_conn->meta_valid;
+ if (!(fake = owner_conn->have_meta_fake)) {
+ rcu_read_lock();
+ meta = rcu_dereference(owner_conn->meta.meta);
+ kdbus_assert(meta);
+ kdbus_conn_meta_ref(meta);
+ rcu_read_unlock();
+ valid |= meta->valid;
+ }
+
+ attach_flags &= atomic_attach_flags_read(&owner_conn->attach_flags_send) & valid;
attach_flags = kdbus_sanitize_exe_flag(attach_flags, conn);
info.id = owner_conn->id;
kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info));
size = sizeof(info);
- kdbus_assert(1 <= cnt);
- kdbus_assert(cnt <= 2);
- if (2 == cnt) {
- kdbus_assert((uintptr_t)&meta_stack <= (uintptr_t)kvec[1].iov_base);
- kdbus_assert((uintptr_t)kvec[1].iov_base < (uintptr_t)&meta_stack + sizeof(meta_stack));
- kdbus_assert(kvec[1].iov_len <= (uintptr_t)&meta_stack + sizeof(meta_stack) - (uintptr_t)kvec[1].iov_base);
- }
-
- #define DO_META(INFIX) do {\
- cnt += kdbus_meta_emit_stack##INFIX##_kvec(&owner_conn->meta##INFIX.meta, conn, &kvec[cnt], &meta_stack, attach_flags, &size);\
- meta_items = owner_conn->meta##INFIX.meta_items;\
- } while (0)
-
- if (owner_conn->have_meta_fake)
- DO_META(_fake);
- else {
- DO_META();
- #undef DO_META
- if (attach_flags & (KDBUS_ATTACH_AUXGROUPS|KDBUS_ATTACH_NAMES)
- #ifdef CONFIG_SECURITY
- || missing_flags
- #endif
- ) {
+ if (fake) {
+ cnt += kdbus_meta_emit_stack_fake_kvec(&owner_conn->meta_fake.meta, conn, &kvec[cnt], &meta_stack, attach_flags, &size);
+ cnt += kdbus_meta_emit_kvecs(&kvec[cnt], owner_conn->meta_fake.meta_items, attach_flags & (KDBUS_ATTACH_SECLABEL|KDBUS_ATTACH_CONN_DESCRIPTION), &size);
+ } else {
+ cnt += kdbus_meta_emit_stack_kvec(&meta->meta, conn, &kvec[cnt], &meta_stack, attach_flags, &size);
+ if (attach_flags & (KDBUS_ATTACH_AUXGROUPS|KDBUS_ATTACH_NAMES)) {
unsigned pay_size;
- meta_payload = kdbus_meta_payload_new(attach_flags & KDBUS_ATTACH_AUXGROUPS ? owner_conn->meta.meta.auxgroups_alloc_order : 0);
- if (!meta_payload) {
+ if (!(meta_payload = kdbus_meta_payload_new(attach_flags & KDBUS_ATTACH_AUXGROUPS ? meta->meta.auxgroups_alloc_order : 0))) {
ret = -ENOMEM;
goto exit;
}
- if (attach_flags & KDBUS_ATTACH_AUXGROUPS) /* not fake */
- kdbus_meta_payload_collect_auxgroups_preallocated(meta_payload, &owner_conn->meta.meta, conn);
+ if (attach_flags & KDBUS_ATTACH_AUXGROUPS)
+ kdbus_meta_payload_collect_auxgroups_preallocated(meta_payload, &meta->meta, conn);
if (attach_flags & KDBUS_ATTACH_NAMES) {
if (0 > (ret = kdbus_meta_payload_collect_names(&meta_payload, owner_conn)))
goto exit;
ret = 0;
}
- #ifdef CONFIG_SECURITY
- if (missing_flags && 0 > (ret = kdbus_meta_payload_collect_seclabel(&meta_payload)))
- goto exit;
- ret = 0;
- #endif
if ((pay_size = kdbus_meta_payload_size(meta_payload))) {
kdbus_assert(!(pay_size % 8));
kdbus_kvec_set(&kvec[cnt++], kdbus_meta_payload_ptr(meta_payload), pay_size);
size = KDBUS_ALIGN8(size) + pay_size;
}
}
+ cnt += kdbus_meta_emit_kvecs(&kvec[cnt], meta->meta_items, attach_flags & KDBUS_ATTACH_MASK_PROC_DST_AGNOSTIC, &size);
+ cnt += kdbus_meta_emit_kvecs(&kvec[cnt], owner_conn->meta.conn_description, attach_flags & KDBUS_ATTACH_CONN_DESCRIPTION, &size);
}
- cnt += kdbus_meta_emit_kvecs(&kvec[cnt], meta_items, attach_flags & (KDBUS_ATTACH_MASK_PROC_DST_AGNOSTIC|KDBUS_ATTACH_CONN_DESCRIPTION), &size);
kdbus_assert(cnt <= sizeof(kvec)/sizeof(kvec[0]));
info.size = size;
size = KDBUS_ALIGN8(size);
up_read(&bus->name_registry.rwlock);
if (slice)
kdbus_pool_slice_release(&conn->pool, slice);
- if (meta_payload)
- kdbus_meta_payload_free(meta_payload);
+ if (meta) {
+ kdbus_conn_meta_unref(meta);
+ if (meta_payload)
+ kdbus_meta_payload_free(meta_payload);
+ }
return kdbus_args_clear(&args, ret);
}
return kdbus_args_clear(&args, ret);
}
+static wur int kdbus_conn_meta_update(struct kdbus_conn *__restrict__ conn, bool first_time)
+{
+ struct kdbus_meta_payload *meta_payload;
+ struct kdbus_conn_meta *meta;
+ int ret;
+
+ kdbus_assert(conn);
+ kdbus_assert(!conn->have_meta_fake);
+
+ if (!(meta_payload = kdbus_meta_payload_new(0)))
+ return -ENOMEM;
+ if (0 <= (ret = kdbus_meta_proc_collect(&meta_payload, KDBUS_ATTACH_MASK_ALL))) {
+ unsigned pay_size = kdbus_meta_payload_size(meta_payload);
+ if (!(meta = kmalloc(sizeof(*meta) + pay_size, GFP_KERNEL)))
+ ret = -ENOMEM;
+ else {
+ meta->kref.refcount.counter = 1; /* no need for atomicity yet */
+ meta->valid = ret | kdbus_dst_sensitive_meta_collect(&meta->meta, KDBUS_ATTACH_MASK_ALL);
+ memcpy(meta->meta_items, kdbus_meta_payload_ptr(meta_payload), pay_size);
+ }
+ }
+ kdbus_meta_payload_free(meta_payload);
+ if (ret < 0)
+ return ret;
+
+ if (first_time)
+ conn->meta.meta = meta;
+ else {
+ struct kdbus_conn_meta *old_meta;
+ mutex_lock(&conn->lock);
+ old_meta = conn->meta.meta;
+ rcu_assign_pointer(conn->meta.meta, meta);
+ synchronize_rcu();
+ mutex_unlock(&conn->lock);
+ kdbus_conn_meta_unref(old_meta);
+ }
+
+ return 0;
+}
+
+/**
+ * kdbus_cmd_update_metadata() - handle KDBUS_CMD_UPDATE_METADATA
+ * @conn: connection to operate on
+ *
+ * Return: >=0 on success, negative error code on failure.
+ */
+int kdbus_cmd_update_metadata(struct kdbus_conn *conn)
+{
+ if (conn->have_meta_fake)
+ return -EOPNOTSUPP;
+ return kdbus_conn_meta_update(conn, 0);
+}
+
/**
* kdbus_cmd_send() - handle KDBUS_CMD_SEND
* @conn: connection to operate on
struct kdbus_name_entry;
struct kdbus_quota;
+struct kdbus_conn_meta {
+ struct kref kref;
+ attach_flags_t valid;
+ struct kdbus_dst_sensitive_meta meta;
+ struct kdbus_item meta_items[0];
+};
+
+void kdbus_conn_meta_free(struct kdbus_conn_meta *meta);
+void kdbus_conn_meta_ref(struct kdbus_conn_meta *meta);
+void kdbus_conn_meta_unref(struct kdbus_conn_meta *meta);
+
/**
* struct kdbus_conn - connection to a bus
* @kref: Reference count
union {
struct {
- struct kdbus_dst_sensitive_meta meta;
- struct kdbus_item meta_items[0];
+ struct kdbus_conn_meta *meta; /* rcu-protected and refcounted, contains its own meta_valid and both dst-sensitive and insensitive metadata */
+ struct kdbus_item conn_description[0]; /* conn_description or nothing */
} meta;
struct {
struct kdbus_dst_sensitive_meta_fake meta;
- struct kdbus_item meta_items[0];
+ struct kdbus_item meta_items[0]; /* seclabel, conn_description */
} meta_fake;
};
};
wur int kdbus_cmd_byebye_unlocked(struct kdbus_conn *conn, void __user *argp);
wur int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp);
wur int kdbus_cmd_update(struct kdbus_conn *conn, void __user *argp);
+wur int kdbus_cmd_update_metadata(struct kdbus_conn *conn);
wur int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp);
wur int kdbus_cmd_recv(struct kdbus_conn *conn, void __user *argp);
wur int kdbus_cmd_free(struct kdbus_conn *conn, void __user *argp);
struct kdbus_node *node;
int ret;
- node = kzalloc(sizeof(*node), GFP_KERNEL);
- if (!node)
+ if (!(node = kzalloc(sizeof(*node), GFP_KERNEL)))
return ERR_PTR(-ENOMEM);
kdbus_node_init(node, KDBUS_NODE_CONTROL);
struct kdbus_domain *d;
int ret;
- d = kzalloc(sizeof(*d), GFP_KERNEL);
- if (!d)
+ if (!(d = kzalloc(sizeof(*d), GFP_KERNEL)))
return ERR_PTR(-ENOMEM);
kdbus_node_init(&d->node, KDBUS_NODE_DOMAIN);
}
}
- u = kzalloc(sizeof(*u), GFP_KERNEL);
- if (!u) {
+ if (!(u = kzalloc(sizeof(*u), GFP_KERNEL))) {
ret = -ENOMEM;
goto exit;
}
if (is_custom && (ret = kdbus_verify_uid_prefix(name, bus->domain->user_namespace, uid)))
return ERR_PTR(ret);
- e = kzalloc(sizeof(*e), GFP_KERNEL);
- if (!e)
+ if (!(e = kzalloc(sizeof(*e), GFP_KERNEL)))
return ERR_PTR(-ENOMEM);
kdbus_node_init(&e->node, KDBUS_NODE_ENDPOINT);
{
struct inode *inode;
- inode = iget_locked(sb, node->id);
- if (!inode)
+ if (!(inode = iget_locked(sb, node->id)))
return ERR_PTR(-ENOMEM);
if (!(inode->i_state & I_NEW))
return inode;
return PTR_ERR(inode);
sb->s_root = d_make_root(inode);
- if (!sb->s_root) {
- /* d_make_root iput()s the inode on failure */
+ if (!sb->s_root) /* d_make_root iput()s the inode on failure */
return -ENOMEM;
- }
/* sb holds domain reference */
sb->s_root->d_fsdata = &domain->node;
args->cmd = (void*)args->cmd_buf;
else if (!(args->cmd = kmalloc(aligned_user_size, GFP_TEMPORARY)))
return -ENOMEM;
- if (IS_ERR(args->cmd))
- return PTR_ERR(args->cmd);
+ if (IS_ERR(args->cmd))
+ return PTR_ERR(args->cmd);
/* pad with trailing zeroes to alignment of 8 */
*(u64*)((uintptr_t)args->cmd + aligned_user_size - 8) = 0;
if (!kdbus_node_acquire(node))
return -ESHUTDOWN;
- handle = kzalloc(sizeof(*handle), GFP_KERNEL);
- if (!handle) {
+ if (!(handle = kzalloc(sizeof(*handle), GFP_KERNEL))) {
ret = -ENOMEM;
goto exit;
}
case KDBUS_CMD_UPDATE:
ret = kdbus_cmd_update(conn, buf);
break;
+ case KDBUS_CMD_UPDATE_METADATA:
+ ret = kdbus_cmd_update_metadata(conn);
+ break;
case KDBUS_CMD_MATCH_ADD:
ret = kdbus_cmd_match_add(conn, buf);
break;
case KDBUS_CMD_NAME_ACQUIRE:
case KDBUS_CMD_NAME_RELEASE:
case KDBUS_CMD_LIST:
+ case KDBUS_CMD_UPDATE_METADATA:
case KDBUS_CMD_CONN_INFO:
case KDBUS_CMD_BUS_CREATOR_INFO:
case KDBUS_CMD_UPDATE:
sizeof (struct kdbus_reply),
0, 0, NULL);
- kdbus_dir = kobject_create_and_add(KBUILD_MODNAME, fs_kobj);
- if (!kdbus_dir)
+ if (!(kdbus_dir = kobject_create_and_add(KBUILD_MODNAME, fs_kobj)))
return -ENOMEM;
if ((ret = kdbus_fs_init())) {
kernel_size = 0;
}
- entry = kmalloc(sizeof(*entry) + kernel_size + (user_size<0 ? 0 : user_size), GFP_KERNEL);
- if (!entry) {
+ ;
+ if (!(entry = kmalloc(sizeof(*entry) + kernel_size + (user_size<0 ? 0 : user_size), GFP_KERNEL))) {
ret = -ENOMEM;
goto exit;
}
fds = &fds_stack_buffer[0];
else {
order = kdbus_page_alloc_order(n_total_fds * sizeof(*fds));
- fds = (typeof(fds))__get_free_pages(GFP_TEMPORARY, order);
- if (!fds)
+ if (!(fds = (typeof(fds))__get_free_pages(GFP_TEMPORARY, order)))
return -ENOMEM;
}
kdbus_dst_sensitive_meta_real_destroy(meta, valid);
}
+static void __kdbus_conn_meta_free(struct kref *kref)
+{
+ struct kdbus_conn_meta *meta = container_of(kref, struct kdbus_conn_meta, kref);
+ kdbus_dst_sensitive_meta_destroy(&meta->meta, meta->valid);
+ kfree(meta);
+}
+
+void kdbus_conn_meta_free(struct kdbus_conn_meta *meta)
+{
+ kdbus_assert(meta);
+ kdbus_assert(1 == meta->kref.refcount.counter);
+ __kdbus_conn_meta_free(&meta->kref);
+}
+
+void kdbus_conn_meta_ref(struct kdbus_conn_meta *meta)
+{
+ kdbus_assert(meta);
+ kref_get(&meta->kref);
+}
+
+void kdbus_conn_meta_unref(struct kdbus_conn_meta *meta)
+{
+ kdbus_assert(meta);
+ kref_put(&meta->kref, __kdbus_conn_meta_free);
+}
+
static void kdbus_meta_export_caps(struct kdbus_meta_caps *__restrict__ out,
const struct cred *__restrict__ cred,
struct user_namespace *__restrict__ user_ns)
return 0;
}
-static void kdbus_meta_payload_write_string_item_preallocated(struct kdbus_meta_payload *__restrict__ pay, kdbus_item_type_t type, char const *__restrict__ str, unsigned len)
+void kdbus_write_string_item(struct kdbus_item *__restrict__ item, kdbus_item_type_t type, char const *__restrict__ str, unsigned len)
{
- struct kdbus_item * __restrict__ item = kdbus_meta_payload_item(pay);
unsigned item_size = KDBUS_ITEM_HEADER_SIZE + len+1;
item->size = item_size;
item->type = type;
kdbus_copy_string(item->str, str, len);
- kdbus_meta_payload_advance(pay, KDBUS_ALIGN8(item_size));
+}
+
+static void kdbus_meta_payload_write_string_item_preallocated(struct kdbus_meta_payload *__restrict__ pay, kdbus_item_type_t type, char const *__restrict__ str, unsigned len)
+{
+ struct kdbus_item * __restrict__ item = kdbus_meta_payload_item(pay);
+ kdbus_write_string_item(item, type, str, len);
+ kdbus_meta_payload_advance(pay, KDBUS_ALIGN8(KDBUS_ITEM_HEADER_SIZE + len+1));
}
static wur int kdbus_meta_payload_write_string_item(struct kdbus_meta_payload *__restrict__ *__restrict__ pptr, kdbus_item_type_t type, char const *__restrict__ str)
}
#ifdef CONFIG_SECURITY
-wur int kdbus_meta_payload_collect_seclabel(struct kdbus_meta_payload * __restrict__ * __restrict__ pptr)
+static wur int kdbus_meta_payload_collect_seclabel(struct kdbus_meta_payload * __restrict__ * __restrict__ pptr)
{
for (;;) {
typeof(*pptr) pay;
#ifdef CONFIG_CGROUPS
if (what & KDBUS_ATTACH_CGROUP) {
char *s;
- tmp_page = (typeof(tmp_page))__get_free_page(GFP_TEMPORARY);
- if (!tmp_page)
+ if (!(tmp_page = (typeof(tmp_page))__get_free_page(GFP_TEMPORARY)))
return -ENOMEM;
if ((s = task_cgroup_path(current, tmp_page, PAGE_SIZE))) {
if ((ret = kdbus_meta_payload_write_string_item(pptr, KDBUS_ITEM_CGROUP, s))) {
return valid;
}
-/**
- * kdbus_meta_fake_collect() - Fill fake metadata from faked credentials
- * @mf: Fake metadata object
- * @seclabel: Seclabel to set, may be %NULL
- *
- * Return: valid flags on success, negative error code on failure.
- */
-int kdbus_meta_fake_collect(struct kdbus_meta_payload * __restrict__ * __restrict__ pptr,
- const char * __restrict__ seclabel)
-{
- int ret;
- if (!seclabel)
- return 0;
- if ((ret = kdbus_meta_payload_write_string_item(pptr, KDBUS_ITEM_SECLABEL, seclabel)))
- return ret;
- return KDBUS_ATTACH_SECLABEL;
-}
-
void kdbus_collect_timestamp(struct kdbus_timestamp *ts)
{
ts->monotonic_ns = ktime_get_ns();
/* bus info */
#define MAX_META_EMIT_VECS_BUS (1/* DST_SENSITIVE generated on stack*/+1/*AUXGROUPS in dynamically allocated buffer*/+_CONTIGUOUS_IOVEC_COUNT_(_MAX_META_EMIT_CONT_ITEM_COUNT_BUS_))
/* conn info */
-#define MAX_META_EMIT_VECS_CONN (1/*CAPS CREDS PID generated on stack*/+1/*AUXGROUPS+NAMES in dynamically allocated buffer*/+_CONTIGUOUS_IOVEC_COUNT_(_MAX_META_EMIT_CONT_ITEM_COUNT_BUS_+1/*CONN_DESCRIPTION*/))
+#define MAX_META_EMIT_VECS_CONN (1/*CAPS CREDS PID generated on stack*/+1/*CONN_DESCRIPTION*/+1/*AUXGROUPS+NAMES in dynamically allocated buffer*/+_CONTIGUOUS_IOVEC_COUNT_(_MAX_META_EMIT_CONT_ITEM_COUNT_BUS_))
#define N_RESERVED_STAGING_USER_PARTS_BEFORE_PAYLOAD\
(1 /* iovec to copy kdbus_msg.size */\
}
static inline wur struct kdbus_meta_payload *kdbus_meta_payload_new_offset_later(unsigned order) {
var(p, (struct kdbus_meta_payload *)__get_free_pages(GFP_TEMPORARY, order));
- p->alloc_order = order;
+ if (p)
+ p->alloc_order = order;
return p;
}
static inline wur struct kdbus_meta_payload *kdbus_meta_payload_new(unsigned order) {
return (struct kdbus_item *)((uintptr_t)load + load->meta_offset);
}
+void kdbus_write_string_item(struct kdbus_item *__restrict__ item, kdbus_item_type_t type, char const *__restrict__ str, unsigned len);
+
wur int kdbus_meta_proc_collect(struct kdbus_meta_payload *__restrict__ *__restrict__ pptr, attach_flags_t what);
-wur int kdbus_meta_fake_collect(struct kdbus_meta_payload *__restrict__ *__restrict__ pptr, const char *__restrict__ seclabel);
-/* KDBUS_ATTACH_SECLABEL if collected, 0 if not supported, <0 if error */
-wur int kdbus_meta_payload_collect_seclabel(struct kdbus_meta_payload * __restrict__ * __restrict__ pptr);
wur unsigned _kdbus_meta_emit_(struct k_or_io_vec vec, struct kdbus_item *meta_item, attach_flags_t what, unsigned *size, unsigned total_meta_name_size);
if (conn->name_count >= KDBUS_CONN_MAX_NAMES)
return ERR_PTR(-E2BIG);
- owner = kmalloc(sizeof(*owner), GFP_KERNEL);
- if (!owner)
+ if (!(owner = kmalloc(sizeof(*owner), GFP_KERNEL)))
return ERR_PTR(-ENOMEM);
owner->flags = flags & KDBUS_NAME_SAVED_MASK;
namelen = strlen(name_str);
- name = kmalloc(sizeof(*name) + namelen + 1, GFP_KERNEL);
- if (!name)
+ if (!(name = kmalloc(sizeof(*name) + namelen + 1, GFP_KERNEL)))
return ERR_PTR(-ENOMEM);
name->name_id = ++r->name_seq_last;
return -EINVAL;
if (name) {
- node->name = kstrdup(name, GFP_KERNEL);
- if (!node->name)
+ if (!(node->name = kstrdup(name, GFP_KERNEL)))
return -ENOMEM;
-
node->hash = kdbus_node_name_hash(name);
}
int ret;
struct kdbus_policy_db_entry_access *a;
- a = kzalloc(sizeof(*a), GFP_KERNEL);
- if (!a)
+ if (!(a = kzalloc(sizeof(*a), GFP_KERNEL)))
return ERR_PTR(-ENOMEM);
ret = -EINVAL;
goto exit;
}
- e = kzalloc(sizeof(*e), GFP_KERNEL);
- if (!e) {
+ if (!(e = kzalloc(sizeof(*e), GFP_KERNEL))) {
ret = -ENOMEM;
goto exit;
}
e->owner = owner;
hlist_add_head(&e->hentry, &entries);
- e->name = kstrdup(item->str, GFP_KERNEL);
- if (!e->name) {
+ if (!(e->name = kstrdup(item->str, GFP_KERNEL))) {
ret = -ENOMEM;
goto exit;
}
s = rb_entry(found, struct kdbus_pool_slice, rb_node);
/* split-off the remainder of the size to its own slice */
- s_new = kdbus_pool_slice_new(pool, s->off + slice_size,
- s->size - slice_size);
- if (!s_new) {
+ if (!(s_new = kdbus_pool_slice_new(pool, s->off + slice_size, s->size - slice_size))) {
ret = -ENOMEM;
goto exit_unlock;
}
int ret;
if (name) {
- n = kasprintf(GFP_KERNEL, KBUILD_MODNAME "-conn:%s", name);
- if (!n) {
+ if (!(n = kasprintf(GFP_KERNEL, KBUILD_MODNAME "-conn:%s", name))) {
ret = -ENOMEM;
goto exit_fail;
}
goto exit_put_shmem;
/* allocate first slice spanning the entire pool */
- s = kdbus_pool_slice_new(p, 0, size);
- if (!s) {
+ if (!(s = kdbus_pool_slice_new(p, 0, size))) {
ret = -ENOMEM;
goto exit_put_write;
}
goto exit_inc_request_quota;
}
- r = kmem_cache_alloc(kdbus_reply_cachep, GFP_KERNEL);
- if (!r) {
+ if (!(r = kmem_cache_alloc(kdbus_reply_cachep, GFP_KERNEL))) {
ret = -ENOMEM;
goto exit_inc_request_quota;
}
return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
}
+static inline wur int kdbus_cmd_update_metadata(int fd)
+{
+ int ret = ioctl(fd, KDBUS_CMD_UPDATE_METADATA);
+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
+}
+
static inline wur int kdbus_cmd_send(int conn_fd, struct kdbus_cmd_send *cmd)
{
int ret = ioctl(conn_fd, KDBUS_CMD_SEND, cmd);
char *busname;
};
-pthread_mutex_t global_print_lock = PTHREAD_MUTEX_INITIALIZER;
-
static const struct kdbus_test tests[] = {
{
.name = "bus-make",
free(cmd);
return -EIO;
}
+ ASSERT_ZERO(kdbus_info_dump(cmd, info));
if (offset) {
*offset = cmd->offset;
return buf;
}
-wur int kdbus_msg_dump(const struct kdbus_msg *msg) {
- const struct kdbus_item *item = msg->items;
- char buf_src[32];
- char buf_dst[32];
- uint64_t timeout = 0;
- uint64_t cookie_reply = 0;
- int ret = 0;
-
- if (msg->flags & KDBUS_MSG_EXPECT_REPLY)
- timeout = msg->timeout_ns;
- else
- cookie_reply = msg->cookie_reply;
-
- kdbus_printf("MESSAGE(%p): %s (%llu bytes) flags=0x%08llx, %s → %s, "
- "cookie=%llu, timeout=%llu cookie_reply=%llu priority=%lli\n",
- msg,
- enum_PAYLOAD(msg->payload_type), (unsigned long long)msg->size,
- (unsigned long long)msg->flags,
- msg_id(msg->src_id, buf_src), msg_id(msg->dst_id, buf_dst),
- (unsigned long long)msg->cookie, (unsigned long long)timeout,
- (unsigned long long)cookie_reply, (long long)msg->priority);
-
- KDBUS_ITEM_FOREACH(item, msg, items) {
- if (item->size < KDBUS_ITEM_HEADER_SIZE) {
- kdbus_printf(" +%s (%llu bytes) invalid data record\n",
- enum_MSG(item->type), item->size);
- return -EINVAL;
- }
-
- switch (item->type) {
- case KDBUS_ITEM_PAYLOAD_OFF: {
- char *s;
-
- if (item->vec.offset == ~0ULL)
- s = "[\\0-bytes]";
- else
- s = (char *)msg + item->vec.offset;
-
- kdbus_printf(" +%s (%llu bytes) off=%llu size=%llu '%s'\n",
- enum_MSG(item->type), item->size,
- (unsigned long long)item->vec.offset,
- (unsigned long long)item->vec.size, s);
- break;
- }
-
- case KDBUS_ITEM_FDS: {
- int i, n = (item->size - KDBUS_ITEM_HEADER_SIZE) /
- sizeof(int);
-
- kdbus_printf(" +%s (%llu bytes, %d fds)\n",
- enum_MSG(item->type), item->size, n);
-
- for (i = 0; i < n; i++)
- kdbus_printf(" fd[%d] = %d\n",
- i, item->fds[i]);
-
- break;
- }
-
- case KDBUS_ITEM_PAYLOAD_MEMFD: {
- char *buf;
- off_t size;
-
- buf = mmap(NULL, item->memfd.size, PROT_READ,
- MAP_PRIVATE, item->memfd.fd, 0);
- if (buf == MAP_FAILED) {
- kdbus_printf("mmap() fd=%i size=%llu failed: %m\n",
- item->memfd.fd, item->memfd.size);
- break;
- }
-
- if (sys_memfd_get_size(item->memfd.fd, &size) < 0) {
- kdbus_printf("KDBUS_CMD_MEMFD_SIZE_GET failed: %m\n");
- break;
- }
-
- kdbus_printf(" +%s (%llu bytes) fd=%i size=%llu filesize=%llu '0x%llx'\n",
- enum_MSG(item->type), item->size, item->memfd.fd,
- (unsigned long long)item->memfd.size,
- (unsigned long long)size, (unsigned long long)(size >= 8 ? *(unsigned long long *)buf : size >= 4 ? *(unsigned *)buf : *buf));
- munmap(buf, item->memfd.size);
- break;
- }
-
+static wur bool kdbus_dump_meta_item(struct kdbus_item const *item) {
+ switch (item->type) {
case KDBUS_ITEM_CREDS:
kdbus_printf(" +%s (%llu bytes) uid=%lld, euid=%lld, suid=%lld, fsuid=%lld, "
"gid=%lld, egid=%lld, sgid=%lld, fsgid=%lld\n",
break;
}
- case KDBUS_ITEM_NAME:
case KDBUS_ITEM_PID_COMM:
case KDBUS_ITEM_TID_COMM:
case KDBUS_ITEM_EXE:
kdbus_printf("\n");
break;
}
+ defaul: return 0;
+ }
+ return 1;
+}
+
+wur int kdbus_info_dump(struct kdbus_cmd_info const *cmd, struct kdbus_info const *info) {
+ struct kdbus_item const *item;
+ kdbus_printf("CONN_INFO cmd(%p): (%llu bytes) flags=0x%08llx return_flags=0x%08llx attach_flags=0x%08llx id=%llu, "
+ "offset=%llu, size=%llu\n",
+ cmd, (unsigned long long)cmd->size,
+ (unsigned long long)cmd->flags,
+ (unsigned long long)cmd->return_flags,
+ (unsigned long long)cmd->attach_flags,
+ (unsigned long long)cmd->id,
+ (unsigned long long)cmd->offset, (unsigned long long)cmd->info_size);
+ kdbus_printf("CONN_INFO info(%p): (%llu bytes) id=%llu flags=0x%08llx\n",
+ info, (unsigned long long)cmd->size, (unsigned long long)cmd->id, (unsigned long long)cmd->flags);
+
+ KDBUS_ITEM_FOREACH(item, info, items) {
+ if (item->size < KDBUS_ITEM_HEADER_SIZE) {
+ kdbus_printf(" +%s (%llu bytes) invalid data record\n",
+ enum_MSG(item->type), item->size);
+ return -EINVAL;
+ }
+ if (!kdbus_dump_meta_item(item))
+ return TEST_ERR;
+ }
+ return 0;
+}
+
+wur int kdbus_msg_dump(const struct kdbus_msg *msg) {
+ const struct kdbus_item *item = msg->items;
+ char buf_src[32];
+ char buf_dst[32];
+ uint64_t timeout = 0;
+ uint64_t cookie_reply = 0;
+ int ret = 0;
+
+ if (msg->flags & KDBUS_MSG_EXPECT_REPLY)
+ timeout = msg->timeout_ns;
+ else
+ cookie_reply = msg->cookie_reply;
+
+ kdbus_printf("MESSAGE(%p): %s (%llu bytes) flags=0x%08llx, %s → %s, "
+ "cookie=%llu, timeout=%llu cookie_reply=%llu priority=%lli\n",
+ msg,
+ enum_PAYLOAD(msg->payload_type), (unsigned long long)msg->size,
+ (unsigned long long)msg->flags,
+ msg_id(msg->src_id, buf_src), msg_id(msg->dst_id, buf_dst),
+ (unsigned long long)msg->cookie, (unsigned long long)timeout,
+ (unsigned long long)cookie_reply, (long long)msg->priority);
+
+ KDBUS_ITEM_FOREACH(item, msg, items) {
+ if (item->size < KDBUS_ITEM_HEADER_SIZE) {
+ kdbus_printf(" +%s (%llu bytes) invalid data record\n",
+ enum_MSG(item->type), item->size);
+ return -EINVAL;
+ }
+
+ if (kdbus_dump_meta_item(item))
+ continue;
+
+ switch (item->type) {
+ case KDBUS_ITEM_PAYLOAD_OFF: {
+ char *s;
+
+ if (item->vec.offset == ~0ULL)
+ s = "[\\0-bytes]";
+ else
+ s = (char *)msg + item->vec.offset;
+
+ kdbus_printf(" +%s (%llu bytes) off=%llu size=%llu '%s'\n",
+ enum_MSG(item->type), item->size,
+ (unsigned long long)item->vec.offset,
+ (unsigned long long)item->vec.size, s);
+ break;
+ }
+
+ case KDBUS_ITEM_FDS: {
+ int i, n = (item->size - KDBUS_ITEM_HEADER_SIZE) /
+ sizeof(int);
+
+ kdbus_printf(" +%s (%llu bytes, %d fds)\n",
+ enum_MSG(item->type), item->size, n);
+
+ for (i = 0; i < n; i++)
+ kdbus_printf(" fd[%d] = %d\n",
+ i, item->fds[i]);
+
+ break;
+ }
+
+ case KDBUS_ITEM_PAYLOAD_MEMFD: {
+ char *buf;
+ off_t size;
+
+ buf = mmap(NULL, item->memfd.size, PROT_READ,
+ MAP_PRIVATE, item->memfd.fd, 0);
+ if (buf == MAP_FAILED) {
+ kdbus_printf("mmap() fd=%i size=%llu failed: %m\n",
+ item->memfd.fd, item->memfd.size);
+ break;
+ }
+
+ if (sys_memfd_get_size(item->memfd.fd, &size) < 0) {
+ kdbus_printf("KDBUS_CMD_MEMFD_SIZE_GET failed: %m\n");
+ break;
+ }
+
+ kdbus_printf(" +%s (%llu bytes) fd=%i size=%llu filesize=%llu '0x%llx'\n",
+ enum_MSG(item->type), item->size, item->memfd.fd,
+ (unsigned long long)item->memfd.size,
+ (unsigned long long)size, (unsigned long long)(size >= 8 ? *(unsigned long long *)buf : size >= 4 ? *(unsigned *)buf : *buf));
+ munmap(buf, item->memfd.size);
+ break;
+ }
+
+ case KDBUS_ITEM_NAME:
+ kdbus_printf(" +%s (%llu bytes) '%s' (%zu)\n",
+ enum_MSG(item->type), item->size,
+ item->str, strlen(item->str));
+ break;
case KDBUS_ITEM_TIMESTAMP:
kdbus_printf(" +%s (%llu bytes) seq=%llu realtime=%lluns monotonic=%lluns\n",
struct kdbus_msg **msg_out, uint64_t *offset);
wur int kdbus_free(const struct kdbus_conn *conn, uint64_t offset);
wur int kdbus_free_msg(struct kdbus_conn const *conn, struct kdbus_msg *msg);
+wur int kdbus_info_dump(struct kdbus_cmd_info const *cmd, struct kdbus_info const *info);
wur int kdbus_msg_dump(const struct kdbus_msg *msg);
wur int kdbus_create_bus(int control_fd, const char *name,
uint64_t owner_meta, char **path);
wur int config_user_ns_is_enabled(void);
wur int config_auditsyscall_is_enabled(void);
wur int config_cgroups_is_enabled(void);
-wur int config_security_is_enabled(void);
\ No newline at end of file
+wur int config_security_is_enabled(void);
return TEST_OK;
}
+static wur int get_label(char *buf, unsigned buf_size)
+{
+ int len=0;
+ int fd = open("/proc/self/attr/current", O_RDONLY);
+ if (fd < 0)
+ return -errno;
+ do len = read(fd, buf, buf_size); while (len < 0 && (EAGAIN==errno || EINTR==errno));
+ if (len < 0)
+ return -errno;
+ if (len == buf_size)
+ return -ENAMETOOLONG;
+ buf[len] = 0;
+ if (0 > close(fd))
+ return -errno;
+ return len;
+}
+
static wur int set_label(char const *label)
{
- int fd = open("/proc/self/attr/current", O_RDWR);
+ int fd = open("/proc/self/attr/current", O_WRONLY);
ASSERT_RETURN(fd,>=,0);
int l = strlen(label);
ASSERT_NONZERO(l);
wur int kdbus_test_dynamic_seclabel(struct kdbus_test_env *env)
{
+ char old_label[65536];
char const *labels[] = {"System::Privileged", "UserTest"};
+ char const *prev_label = old_label;
unsigned i;
+ ASSERT_RETURN(0,<=,get_label(old_label, sizeof(old_label)));
+
for (i=TABSIZE(labels); --i;) {
char const *label = labels[i];
ASSERT_ZERO(set_label(label));
ASSERT_ZERO(assert_label(label, msg->items));
kdbus_msg_free(msg);
}
+ ASSERT_ZERO(assert_info_label(env->conn, env->conn->id, prev_label));
+ ASSERT_ZERO(kdbus_cmd_update_metadata(env->conn->fd));
ASSERT_ZERO(assert_info_label(env->conn, env->conn->id, label));
+ prev_label = label;
}
RUN_FORKED(({
struct kdbus_msg *msg;
ASSERT_ZERO(kdbus_msg_recv_poll(env->conn, 500, &msg, NULL));
ASSERT_RETURN(i,==,msg->cookie-1);
- ASSERT_ZERO(set_label(labels[i]));
ASSERT_ZERO(assert_label("wuj", msg->items));
+ ASSERT_ZERO(set_label(labels[i]));
+ ASSERT_ZERO(kdbus_cmd_update_metadata(env->conn->fd));
ASSERT_ZERO(kdbus_msg_send_reply(env->conn, i+1, msg->src_id));
ASSERT_ZERO(assert_info_label(env->conn, msg->src_id, "wuj"));
kdbus_msg_free(msg);