summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2015-01-11 02:16:19 +0100
committerDavid Herrmann <dh.herrmann@gmail.com>2015-01-11 02:16:19 +0100
commit8d411f94a321e109d3c9ed27659f021fba619793 (patch)
treee746ce1e8ffbe469b4a041acf842c9713a8afc5c
parent9b5e106d113aafe9005ff24246ebb244e3fd0b80 (diff)
downloadkdbus-bus-8d411f94a321e109d3c9ed27659f021fba619793.tar.gz
kdbus-bus-8d411f94a321e109d3c9ed27659f021fba619793.tar.bz2
kdbus-bus-8d411f94a321e109d3c9ed27659f021fba619793.zip
metadata: major overhaul to fix several bugs
The current metadata implementation suffers from several bugs: 1) If we run GET_CONN_INFO, we take the metadata object of the connection and try to augment it with owned-names and the connection-description. We do this unlocked on a _shared_ metadata object. This breaks parallel GET_CONN_INFO calls as someone else might be calling kdbus_meta_export() in parallel. 2) If we send a broadcast, we create a new metadata object that we fill with information. Then, for each target, we collect further information and queue it on the target. However, if a message is queued on target A and it already tries to dequeue it while the broadcast still continues on target B, we again get a collect vs. export race. As I assumed we use faked-metadata as base for messages, too, I started to split the metadata object into meta_proc and meta_conn. This turned out to be not needed, but I thought it's a nice split and allows us to reduce bus->meta and conn->meta to meta_proc, instead of meta_conn. If people don't like it, we can revert it again. But the added code is minimal. Anyway, the real fixes of this commit are: * meta objects have a lock now. This lock is held during updates *only*. During export, we only retrieve the "collected" flag and then can be sure that we can access the properly collected fields without races and without holding the lock. * meta objects distinguish "collected" and "valid" flags now. This fixes a race where we try to add owned-names, but a connection doesn't own names. On the next broadcast target, we try again and at this time the connection owns names. Thus, we would send the message with different information to different targets. To avoid this, we now set "collected" when we collected a flag without errors, but we only set "valid" if we collected it *AND* it is non-empty. This way, we will never collect a field twice, even if it was empty the first time. * get-conn-info now uses a temporary kdbus_meta_conn object to collect the connection related metadata. This is a one-time object, as the data is no longer valid afterwards. * Lots of random error-path fixes I was too lazy to commit separately (as they were mostly overwritten by further rewrites). * Reduce "struct file *exe" to "struct path exe". We really only ever accessed exe->f_path, so no need to pin the whole file. It's enough to pin the underlying inode via the path. Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
-rw-r--r--bus.c49
-rw-r--r--bus.h4
-rw-r--r--connection.c58
-rw-r--r--connection.h2
-rw-r--r--message.c37
-rw-r--r--message.h6
-rw-r--r--metadata.c1298
-rw-r--r--metadata.h40
-rw-r--r--notify.c3
-rw-r--r--queue.c12
-rw-r--r--queue.h6
11 files changed, 890 insertions, 625 deletions
diff --git a/bus.c b/bus.c
index 2227c4fbb85..f7c0ce48d10 100644
--- a/bus.c
+++ b/bus.c
@@ -49,7 +49,7 @@ static void kdbus_bus_free(struct kdbus_node *node)
kdbus_name_registry_free(bus->name_registry);
kdbus_domain_unref(bus->domain);
kdbus_policy_db_clear(&bus->policy_db);
- kdbus_meta_unref(bus->meta);
+ kdbus_meta_proc_unref(bus->creator_meta);
kfree(bus);
}
@@ -189,25 +189,25 @@ struct kdbus_bus *kdbus_bus_new(struct kdbus_domain *domain,
goto exit_unref;
/* cache the metadata/credentials of the creator */
- b->meta = kdbus_meta_new();
- if (IS_ERR(b->meta)) {
- ret = PTR_ERR(b->meta);
- b->meta = NULL;
+ b->creator_meta = kdbus_meta_proc_new();
+ if (IS_ERR(b->creator_meta)) {
+ ret = PTR_ERR(b->creator_meta);
+ b->creator_meta = NULL;
goto exit_unref;
}
- ret = kdbus_meta_add_current(b->meta,
- KDBUS_ATTACH_CREDS |
- KDBUS_ATTACH_PIDS |
- KDBUS_ATTACH_AUXGROUPS |
- 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);
+ ret = kdbus_meta_proc_collect(b->creator_meta,
+ KDBUS_ATTACH_CREDS |
+ KDBUS_ATTACH_PIDS |
+ KDBUS_ATTACH_AUXGROUPS |
+ 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_unref;
@@ -415,9 +415,9 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus,
* requested metadata. It's up to the receiver to drop
* messages that lack expected metadata.
*/
- kdbus_meta_add_current(kmsg->meta, attach_flags);
- kdbus_meta_add_conn_info(kmsg->meta,
- conn_src, attach_flags);
+ kdbus_meta_proc_collect(kmsg->proc_meta, attach_flags);
+ kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, conn_src,
+ attach_flags);
} else {
/*
* Check if there is a policy db that prevents the
@@ -471,9 +471,9 @@ void kdbus_bus_eavesdrop(struct kdbus_bus *bus,
attach_flags = kdbus_meta_calc_attach_flags(conn_src,
conn_dst);
- kdbus_meta_add_current(kmsg->meta, attach_flags);
- kdbus_meta_add_conn_info(kmsg->meta,
- conn_src, attach_flags);
+ kdbus_meta_proc_collect(kmsg->proc_meta, attach_flags);
+ kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, conn_src,
+ attach_flags);
}
ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL);
@@ -514,7 +514,8 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn,
/* mask out what information the bus owner wants to pass us */
attach_flags = cmd_info->flags & bus->attach_flags_owner;
- meta_items = kdbus_meta_export(bus->meta, attach_flags, &meta_size);
+ meta_items = kdbus_meta_export(bus->creator_meta, NULL, attach_flags,
+ &meta_size);
if (IS_ERR(meta_items))
return PTR_ERR(meta_items);
diff --git a/bus.h b/bus.h
index cc469f56ce7..65458436bed 100644
--- a/bus.h
+++ b/bus.h
@@ -46,7 +46,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
+ * @meta_proc: Meta information about the bus creator
*
* A bus provides a "bus" endpoint node.
*
@@ -78,7 +78,7 @@ struct kdbus_bus {
DECLARE_HASHTABLE(conn_hash, 8);
struct list_head monitors_list;
- struct kdbus_meta *meta;
+ struct kdbus_meta_proc *creator_meta;
};
struct kdbus_kmsg;
diff --git a/connection.c b/connection.c
index c1d561b72a3..654fc831267 100644
--- a/connection.c
+++ b/connection.c
@@ -605,7 +605,6 @@ int kdbus_cmd_msg_send(struct kdbus_conn *conn_src,
}
kmsg->seq = atomic64_inc_return(&bus->domain->msg_seq_last);
- kdbus_meta_add_timestamp(kmsg->meta, kmsg->seq);
if (msg->dst_id == KDBUS_DST_ID_BROADCAST) {
kdbus_bus_broadcast(bus, conn_src, kmsg);
@@ -617,7 +616,7 @@ int kdbus_cmd_msg_send(struct kdbus_conn *conn_src,
* Lock the destination name so it will not get dropped or
* moved between activator/implementer while we try to queue a
* message. We also rely on this to read-lock the entire
- * registry so kdbus_meta_add_current() will have a consistent
+ * registry so kdbus_meta_conn_collect() will have a consistent
* view of all acquired names on both connections.
* If kdbus_name_lock() gets changed to a per-name lock, we
* really need to read-lock the whole registry here.
@@ -719,7 +718,8 @@ int kdbus_cmd_msg_send(struct kdbus_conn *conn_src,
* metadata
*/
if (!conn_src->faked_meta) {
- ret = kdbus_meta_add_current(kmsg->meta, attach_flags);
+ ret = kdbus_meta_proc_collect(kmsg->proc_meta,
+ attach_flags);
if (ret < 0)
goto exit_unref;
}
@@ -728,8 +728,8 @@ int kdbus_cmd_msg_send(struct kdbus_conn *conn_src,
* If requested, then we always send the current
* description and owned names of source connection
*/
- ret = kdbus_meta_add_conn_info(kmsg->meta,
- conn_src, attach_flags);
+ ret = kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, conn_src,
+ attach_flags);
if (ret < 0)
goto exit_unref;
@@ -986,7 +986,7 @@ static void __kdbus_conn_free(struct kref *kref)
kdbus_policy_remove_owner(&conn->ep->bus->policy_db, conn);
- kdbus_meta_unref(conn->meta);
+ kdbus_meta_proc_unref(conn->meta);
kdbus_match_db_free(conn->match_db);
kdbus_pool_free(conn->pool);
kdbus_ep_unref(conn->ep);
@@ -1177,6 +1177,7 @@ int kdbus_conn_move_messages(struct kdbus_conn *conn_dst,
int kdbus_cmd_conn_info(struct kdbus_conn *conn,
struct kdbus_cmd_info *cmd_info)
{
+ struct kdbus_meta_conn *conn_meta = NULL;
struct kdbus_pool_slice *slice = NULL;
struct kdbus_name_entry *entry = NULL;
struct kdbus_conn *owner_conn = NULL;
@@ -1227,15 +1228,23 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn,
attach_flags = cmd_info->flags &
atomic64_read(&owner_conn->attach_flags_send);
- ret = kdbus_meta_add_conn_info(owner_conn->meta, owner_conn,
- attach_flags);
+ conn_meta = kdbus_meta_conn_new();
+ if (IS_ERR(conn_meta)) {
+ ret = PTR_ERR(conn_meta);
+ conn_meta = NULL;
+ goto exit;
+ }
+
+ ret = kdbus_meta_conn_collect(conn_meta, NULL, owner_conn,
+ attach_flags);
if (ret < 0)
goto exit;
- meta_items = kdbus_meta_export(owner_conn->meta, attach_flags,
- &meta_size);
+ meta_items = kdbus_meta_export(owner_conn->meta, conn_meta,
+ attach_flags, &meta_size);
if (IS_ERR(meta_items)) {
ret = PTR_ERR(meta_items);
+ meta_items = NULL;
goto exit;
}
@@ -1258,6 +1267,7 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn,
kdbus_pool_slice_release(slice);
exit:
kfree(meta_items);
+ kdbus_meta_conn_unref(conn_meta);
kdbus_conn_unref(owner_conn);
kdbus_name_unlock(conn->ep->bus->name_registry, entry);
@@ -1581,7 +1591,7 @@ struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep,
BUILD_BUG_ON(sizeof(bus->id128) != sizeof(hello->id128));
memcpy(hello->id128, bus->id128, sizeof(hello->id128));
- conn->meta = kdbus_meta_new();
+ conn->meta = kdbus_meta_proc_new();
if (IS_ERR(conn->meta)) {
ret = PTR_ERR(conn->meta);
conn->meta = NULL;
@@ -1590,24 +1600,24 @@ struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep,
/* privileged processes can impersonate somebody else */
if (creds || pids || seclabel) {
- ret = kdbus_meta_add_fake(conn->meta, creds, pids, seclabel);
+ ret = kdbus_meta_proc_fake(conn->meta, creds, pids, seclabel);
if (ret < 0)
goto exit_unref;
conn->faked_meta = true;
} else {
- ret = kdbus_meta_add_current(conn->meta,
- KDBUS_ATTACH_CREDS |
- KDBUS_ATTACH_PIDS |
- KDBUS_ATTACH_AUXGROUPS |
- 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);
+ ret = kdbus_meta_proc_collect(conn->meta,
+ KDBUS_ATTACH_CREDS |
+ KDBUS_ATTACH_PIDS |
+ KDBUS_ATTACH_AUXGROUPS |
+ 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_unref;
}
diff --git a/connection.h b/connection.h
index cde20038212..ff25931a4dd 100644
--- a/connection.h
+++ b/connection.h
@@ -96,7 +96,7 @@ struct kdbus_conn {
struct delayed_work work;
struct kdbus_name_entry *activator_of;
struct kdbus_match_db *match_db;
- struct kdbus_meta *meta;
+ struct kdbus_meta_proc *meta;
struct kdbus_pool *pool;
struct kdbus_domain_user *user;
const struct cred *cred;
diff --git a/message.c b/message.c
index 305bad8b5e5..959f58f0f81 100644
--- a/message.c
+++ b/message.c
@@ -113,7 +113,8 @@ kdbus_msg_resources_unref(struct kdbus_msg_resources *r)
void kdbus_kmsg_free(struct kdbus_kmsg *kmsg)
{
kdbus_msg_resources_unref(kmsg->res);
- kdbus_meta_unref(kmsg->meta);
+ kdbus_meta_conn_unref(kmsg->conn_meta);
+ kdbus_meta_proc_unref(kmsg->proc_meta);
kfree(kmsg->iov);
kfree(kmsg);
}
@@ -128,6 +129,7 @@ struct kdbus_kmsg *kdbus_kmsg_new(size_t extra_size)
{
struct kdbus_kmsg *m;
size_t size;
+ int ret;
size = sizeof(struct kdbus_kmsg) + KDBUS_ITEM_SIZE(extra_size);
m = kzalloc(size, GFP_KERNEL);
@@ -137,13 +139,23 @@ struct kdbus_kmsg *kdbus_kmsg_new(size_t extra_size)
m->msg.size = size - KDBUS_KMSG_HEADER_SIZE;
m->msg.items[0].size = KDBUS_ITEM_SIZE(extra_size);
- m->meta = kdbus_meta_new();
- if (IS_ERR(m->meta)) {
- kfree(m);
- return ERR_CAST(m->meta);
+ m->proc_meta = kdbus_meta_proc_new();
+ if (IS_ERR(m->proc_meta)) {
+ ret = PTR_ERR(m->proc_meta);
+ goto exit;
+ }
+
+ m->conn_meta = kdbus_meta_conn_new();
+ if (IS_ERR(m->conn_meta)) {
+ ret = PTR_ERR(m->conn_meta);
+ goto exit;
}
return m;
+
+exit:
+ kdbus_kmsg_free(m);
+ return ERR_PTR(ret);
}
static int kdbus_handle_check_file(struct file *file)
@@ -486,10 +498,17 @@ struct kdbus_kmsg *kdbus_kmsg_new_from_cmd(struct kdbus_conn *conn,
memset(m, 0, KDBUS_KMSG_HEADER_SIZE);
- m->meta = kdbus_meta_new();
- if (IS_ERR(m->meta)) {
- ret = PTR_ERR(m->meta);
- m->meta = NULL;
+ m->proc_meta = kdbus_meta_proc_new();
+ if (IS_ERR(m->proc_meta)) {
+ ret = PTR_ERR(m->proc_meta);
+ m->proc_meta = NULL;
+ goto exit_free;
+ }
+
+ m->conn_meta = kdbus_meta_conn_new();
+ if (IS_ERR(m->conn_meta)) {
+ ret = PTR_ERR(m->conn_meta);
+ m->conn_meta = NULL;
goto exit_free;
}
diff --git a/message.h b/message.h
index c9554e10a29..28f1893b002 100644
--- a/message.h
+++ b/message.h
@@ -93,7 +93,8 @@ kdbus_msg_resources_unref(struct kdbus_msg_resources *r);
* @iov: Array of iovec, describing the payload to copy
* @iov_count: Number of array members in @iov
* @pool_size: Overall size of inlined data referenced by @iov
- * @meta: Appended SCM-like metadata of the sending process
+ * @proc_meta: Appended SCM-like metadata of the sending process
+ * @conn_meta: Appended SCM-like metadata of the sending connection
* @res: Message resources
* @msg: Message from or to userspace
*/
@@ -113,7 +114,8 @@ struct kdbus_kmsg {
size_t iov_count;
u64 pool_size;
- struct kdbus_meta *meta;
+ struct kdbus_meta_proc *proc_meta;
+ struct kdbus_meta_conn *conn_meta;
struct kdbus_msg_resources *res;
/* variable size, must be the last member */
diff --git a/metadata.c b/metadata.c
index ad548c5b267..93393d06fd4 100644
--- a/metadata.c
+++ b/metadata.c
@@ -31,94 +31,76 @@
#include "bus.h"
#include "connection.h"
#include "item.h"
+#include "message.h"
#include "metadata.h"
#include "names.h"
/**
- * struct kdbus_meta - metadata buffer
- * @kref: Reference counter
- * @collected: Flags for already collected and valid data
- * @uid: Task uid
- * @euid: Task euid
- * @suid: Task suid
- * @fsuid: Task fsuid
- * @gid: Task gid
- * @egid: Task egid
- * @sgid: Task sgid
- * @fsgid: Task fsgid
- * @conn_description: Source connection's description
- * @owned_names_items: Array of items with names owned by the source
- * @owned_names_size: Number of bytes in @owned_names_items
- * @audit_loginuid: Audit loginuid
- * @audit_sessionid: Audit session ID
- * @seclabel: LSM security label
- * @auxgrps: Auxiliary groups of the task
- * @n_auxgrps: Number of auxiliary groups
- * @pid: Pinned PID
- * @tgid: Pinned TGID
- * @ppid: Pinned PPID
- * @ts_monotonic_ns: Monotonic timestamp taken at collect time
- * @ts_realtime_ns: Realtime timestamp taken at collect time
- * @seq: Sequence number passed in at collect time
- * @exe: Task's executable file, pinned
- * @cmdline: Task's cmdline
- * @cgroup: Cgroup path
- * @pid_comm: COMM of the TGID
- * @tid_comm: COMM of the PID
+ * struct kdbus_meta_proc - Process metadata
+ * @kref: Reference counting
+ * @lock: Object lock
+ * @collected: Bitmask of collected items
+ * @valid: Bitmask of collected and valid items
+ * @uid: UID of process
+ * @euid: EUID of process
+ * @suid: SUID of process
+ * @fsuid: FSUID of process
+ * @gid: GID of process
+ * @egid: EGID of process
+ * @sgid: SGID of process
+ * @fsgid: FSGID of process
+ * @pid: PID of process
+ * @tgid: TGID of process
+ * @ppid: PPID of process
+ * @auxgrps: Auxiliary groups
+ * @n_auxgrps: Number of items in @auxgrps
+ * @tid_comm: TID comm line
+ * @pid_comm: PID comm line
+ * @exe_path: Executable path
+ * @root_path: Root-FS path
+ * @cmdline: Command-line
+ * @cgroup: Full cgroup path
* @caps: Capabilities
- * @caps_namespace: User namespace, pinned when the metadata was
- * recorded
- * @root_path: Root path, pinned when @exe was recorded
- * @tmp: Temporary buffer
- *
- * Data in this struct is only written by the following functions:
- *
- * kdbus_meta_add_*()
- *
- * All data is stored is the kernel-view of resources and translated into
- * namespaces when kdbus_meta_export() is called.
+ * @caps_namespace: User-namespace of @caps
+ * @seclabel: Seclabel
+ * @audit_loginuid: Audit login-UID
+ * @audit_sessionid: Audit session-ID
*/
-struct kdbus_meta {
+struct kdbus_meta_proc {
struct kref kref;
-
+ struct mutex lock;
u64 collected;
+ u64 valid;
- kuid_t uid;
- kuid_t euid;
- kuid_t suid;
- kuid_t fsuid;
- kgid_t gid;
- kgid_t egid;
- kgid_t sgid;
- kgid_t fsgid;
-
- char *conn_description;
- struct kdbus_item *owned_names_items;
- size_t owned_names_size;
-
- kuid_t audit_loginuid;
- unsigned int audit_sessionid;
+ /* KDBUS_ITEM_CREDS */
+ kuid_t uid, euid, suid, fsuid;
+ kgid_t gid, egid, sgid, fsgid;
- char *seclabel;
+ /* KDBUS_ITEM_PIDS */
+ struct pid *pid;
+ struct pid *tgid;
+ struct pid *ppid;
+ /* KDBUS_ITEM_AUXGROUPS */
kgid_t *auxgrps;
size_t n_auxgrps;
- struct pid *pid;
- struct pid *tgid;
- struct pid *ppid;
+ /* KDBUS_ITEM_TID_COMM */
+ char tid_comm[TASK_COMM_LEN];
+ /* KDBUS_ITEM_PID_COMM */
+ char pid_comm[TASK_COMM_LEN];
- s64 ts_monotonic_ns;
- s64 ts_realtime_ns;
- u64 seq;
+ /* KDBUS_ITEM_EXE */
+ struct path exe_path;
+ struct path root_path;
- struct file *exe;
+ /* KDBUS_ITEM_CMDLINE */
char *cmdline;
- char *cgroup;
- char pid_comm[TASK_COMM_LEN];
- char tid_comm[TASK_COMM_LEN];
+ /* KDBUS_ITEM_CGROUP */
+ char *cgroup;
+ /* KDBUS_ITEM_CAPS */
struct caps {
/* binary compatible to kdbus_caps */
u32 last_cap;
@@ -128,483 +110,686 @@ struct kdbus_meta {
} caps;
struct user_namespace *caps_namespace;
- struct path root_path;
+ /* KDBUS_ITEM_SECLABEL */
+ char *seclabel;
+
+ /* KDBUS_ITEM_AUDIT */
+ kuid_t audit_loginuid;
+ unsigned int audit_sessionid;
+};
+
+/**
+ * struct kdbus_meta_conn
+ * @kref: Reference counting
+ * @lock: Object lock
+ * @collected: Bitmask of collected items
+ * @valid: Bitmask of collected and valid items
+ * @ts: Timestamp values
+ * @owned_names_items: Serialized items for owned names
+ * @owned_names_size: Size of @owned_names_items
+ * @conn_description: Connection description
+ */
+struct kdbus_meta_conn {
+ struct kref kref;
+ struct mutex lock;
+ u64 collected;
+ u64 valid;
+
+ /* KDBUS_ITEM_TIMESTAMP */
+ struct kdbus_timestamp ts;
+
+ /* KDBUS_ITEM_OWNED_NAME */
+ struct kdbus_item *owned_names_items;
+ size_t owned_names_size;
- char tmp[PAGE_SIZE];
+ /* KDBUS_ITEM_CONN_DESCRIPTION */
+ char *conn_description;
};
/**
- * kdbus_meta_new() - create new metadata object
+ * kdbus_meta_proc_new() - Create process metadata object
*
- * Return: a new kdbus_meta object on success, ERR_PTR on failure.
+ * Return: Pointer to new object on success, ERR_PTR on failure.
*/
-struct kdbus_meta *kdbus_meta_new(void)
+struct kdbus_meta_proc *kdbus_meta_proc_new(void)
{
- struct kdbus_meta *m;
+ struct kdbus_meta_proc *mp;
- m = kzalloc(sizeof(*m), GFP_KERNEL);
- if (!m)
+ mp = kzalloc(sizeof(*mp), GFP_KERNEL);
+ if (!mp)
return ERR_PTR(-ENOMEM);
- kref_init(&m->kref);
+ kref_init(&mp->kref);
+ mutex_init(&mp->lock);
- return m;
+ return mp;
}
-static void __kdbus_meta_free(struct kref *kref)
+static void kdbus_meta_proc_free(struct kref *kref)
{
- struct kdbus_meta *meta = container_of(kref, struct kdbus_meta, kref);
-
- if (meta->exe) {
- fput(meta->exe);
- path_put(&meta->root_path);
- }
-
- put_user_ns(meta->caps_namespace);
- put_pid(meta->ppid);
- put_pid(meta->tgid);
- put_pid(meta->pid);
-
- kfree(meta->owned_names_items);
- kfree(meta->conn_description);
- kfree(meta->seclabel);
- kfree(meta->auxgrps);
- kfree(meta->cmdline);
- kfree(meta->cgroup);
- kfree(meta);
+ struct kdbus_meta_proc *mp = container_of(kref, struct kdbus_meta_proc,
+ kref);
+
+ path_put(&mp->exe_path);
+ path_put(&mp->root_path);
+ put_user_ns(mp->caps_namespace);
+ put_pid(mp->ppid);
+ put_pid(mp->tgid);
+ put_pid(mp->pid);
+
+ kfree(mp->seclabel);
+ kfree(mp->auxgrps);
+ kfree(mp->cmdline);
+ kfree(mp->cgroup);
+ kfree(mp);
}
/**
- * kdbus_meta_ref() - ref metadata
- * @meta: Metadata object
+ * kdbus_meta_proc_ref() - Gain reference
+ * @mp: Process metadata object
*
- * Increase the reference count on a given kdbus_meta object
- *
- * Return: NULL
+ * Return: @mp is returned
*/
-struct kdbus_meta *kdbus_meta_ref(struct kdbus_meta *meta)
+struct kdbus_meta_proc *kdbus_meta_proc_ref(struct kdbus_meta_proc *mp)
{
- if (meta)
- kref_get(&meta->kref);
- return meta;
+ if (mp)
+ kref_get(&mp->kref);
+ return mp;
}
/**
- * kdbus_meta_unref() - unref metadata
- * @meta: Metadata object
- *
- * When the last reference is dropped, the internal memory is freed.
+ * kdbus_meta_proc_unref() - Drop reference
+ * @mp: Process metadata object
*
* Return: NULL
*/
-struct kdbus_meta *kdbus_meta_unref(struct kdbus_meta *meta)
+struct kdbus_meta_proc *kdbus_meta_proc_unref(struct kdbus_meta_proc *mp)
{
- if (meta)
- kref_put(&meta->kref, __kdbus_meta_free);
+ if (mp)
+ kref_put(&mp->kref, kdbus_meta_proc_free);
return NULL;
}
-/**
- * kdbus_meta_add_fake() - Fill metadata from faked credentials
- * @meta: Metadata
- * @creds: Creds to set, may be %NULL
- * @pids: PIDs to set, may be %NULL
- * @seclabel: Seclabel to set, may be %NULL
- *
- * This function takes information stored in @creds, @pids and @seclabel and
- * resolves them to kernel-representations, if possible. A call to this function
- * is considered an alternative to calling kdbus_meta_add_current(), which
- * derives the same information from the 'current' task.
- *
- * Return: 0 on success, negative error number otherwise.
- */
-int kdbus_meta_add_fake(struct kdbus_meta *meta,
- const struct kdbus_creds *creds,
- const struct kdbus_pids *pids,
- const char *seclabel)
+static void kdbus_meta_proc_collect_creds(struct kdbus_meta_proc *mp)
{
- if (creds) {
- struct user_namespace *ns = current_user_ns();
+ mp->uid = current_uid();
+ mp->euid = current_euid();
+ mp->suid = current_suid();
+ mp->fsuid = current_fsuid();
- meta->uid = make_kuid(ns, creds->uid);
- meta->euid = make_kuid(ns, creds->euid);
- meta->suid = make_kuid(ns, creds->suid);
- meta->fsuid = make_kuid(ns, creds->fsuid);
+ mp->gid = current_gid();
+ mp->egid = current_egid();
+ mp->sgid = current_sgid();
+ mp->fsgid = current_fsgid();
- meta->gid = make_kgid(ns, creds->gid);
- meta->egid = make_kgid(ns, creds->egid);
- meta->sgid = make_kgid(ns, creds->sgid);
- meta->fsgid = make_kgid(ns, creds->fsgid);
+ mp->valid |= KDBUS_ATTACH_CREDS;
+}
- if ((creds->uid != (uid_t)-1 && !uid_valid(meta->uid)) ||
- (creds->euid != (uid_t)-1 && !uid_valid(meta->euid)) ||
- (creds->suid != (uid_t)-1 && !uid_valid(meta->suid)) ||
- (creds->fsuid != (uid_t)-1 && !uid_valid(meta->fsuid)) ||
- (creds->gid != (gid_t)-1 && !gid_valid(meta->gid)) ||
- (creds->egid != (gid_t)-1 && !gid_valid(meta->egid)) ||
- (creds->sgid != (gid_t)-1 && !gid_valid(meta->sgid)) ||
- (creds->fsgid != (gid_t)-1 && !gid_valid(meta->fsgid)))
- return -EINVAL;
+static void kdbus_meta_proc_collect_pids(struct kdbus_meta_proc *mp)
+{
+ struct task_struct *parent;
- meta->collected |= KDBUS_ATTACH_CREDS;
- }
+ mp->pid = get_pid(task_pid(current));
+ mp->tgid = get_pid(task_tgid(current));
- if (pids) {
- meta->pid = get_pid(find_vpid(pids->tid));
- meta->tgid = get_pid(find_vpid(pids->pid));
- meta->ppid = get_pid(find_vpid(pids->ppid));
+ rcu_read_lock();
+ parent = rcu_dereference(current->real_parent);
+ mp->ppid = get_pid(task_tgid(parent));
+ rcu_read_unlock();
- if ((pids->tid != 0 && !meta->pid) ||
- (pids->pid != 0 && !meta->tgid) ||
- (pids->ppid != 0 && !meta->ppid))
- return -EINVAL;
+ mp->valid |= KDBUS_ATTACH_PIDS;
+}
- meta->collected |= KDBUS_ATTACH_PIDS;
- }
+static int kdbus_meta_proc_collect_auxgroups(struct kdbus_meta_proc *mp)
+{
+ struct group_info *info;
+ size_t i;
- if (seclabel) {
- meta->seclabel = kstrdup(seclabel, GFP_KERNEL);
- if (!meta->seclabel)
+ info = get_current_groups();
+
+ if (info->ngroups > 0) {
+ mp->auxgrps = kmalloc_array(info->ngroups, sizeof(kgid_t),
+ GFP_KERNEL);
+ if (!mp->auxgrps) {
+ put_group_info(info);
return -ENOMEM;
+ }
- meta->collected |= KDBUS_ATTACH_SECLABEL;
+ for (i = 0; i < info->ngroups; i++)
+ mp->auxgrps[i] = GROUP_AT(info, i);
}
+ mp->n_auxgrps = info->ngroups;
+ put_group_info(info);
+ mp->valid |= KDBUS_ATTACH_AUXGROUPS;
+
return 0;
}
-/**
- * kdbus_meta_add_timestamp() - record current time stamp
- * @meta: Metadata object
- * @seq: Message sequence number
- *
- * This function does nothing if the time stamp was already recorded
- * in the metadata object.
- */
-void kdbus_meta_add_timestamp(struct kdbus_meta *meta, u64 seq)
+static void kdbus_meta_proc_collect_tid_comm(struct kdbus_meta_proc *mp)
{
- struct timespec ts;
+ get_task_comm(mp->tid_comm, current);
+ mp->valid |= KDBUS_ATTACH_TID_COMM;
+}
- if (meta->collected & KDBUS_ATTACH_TIMESTAMP)
- return;
+static void kdbus_meta_proc_collect_pid_comm(struct kdbus_meta_proc *mp)
+{
+ get_task_comm(mp->pid_comm, current->group_leader);
+ mp->valid |= KDBUS_ATTACH_PID_COMM;
+}
- ktime_get_ts(&ts);
- meta->ts_monotonic_ns = timespec_to_ns(&ts);
+static void kdbus_meta_proc_collect_exe(struct kdbus_meta_proc *mp)
+{
+ struct mm_struct *mm;
- ktime_get_real_ts(&ts);
- meta->ts_realtime_ns = timespec_to_ns(&ts);
+ mm = get_task_mm(current);
+ if (!mm)
+ return;
- meta->seq = seq;
+ get_fs_root(current->fs, &mp->root_path);
- meta->collected |= KDBUS_ATTACH_TIMESTAMP;
+ down_read(&mm->mmap_sem);
+ mp->exe_path = mm->exe_file->f_path;
+ path_get(&mp->exe_path);
+ up_read(&mm->mmap_sem);
+
+ mmput(mm);
+ mp->valid |= KDBUS_ATTACH_EXE;
}
-/**
- * kdbus_meta_add_current() - collect metadata from current process
- * @meta: Metadata object
- * @which: KDBUS_ATTACH_* mask
- *
- * Collect the data specified in @which from the 'current', and store the
- * kernel-view of resources in @meta. Information that has already been
- * collected will not be gathered again.
- *
- * Return: 0 on success, negative errno on failure.
- */
-int kdbus_meta_add_current(struct kdbus_meta *meta, u64 which)
+static int kdbus_meta_proc_collect_cmdline(struct kdbus_meta_proc *mp)
{
- u64 mask;
- int i;
+ struct mm_struct *mm;
+ char *cmdline;
- /* which metadata is wanted but not yet collected? */
- mask = which & ~meta->collected;
- if (mask == 0)
+ mm = get_task_mm(current);
+ if (!mm)
return 0;
- if (mask & KDBUS_ATTACH_CREDS) {
- meta->uid = current_uid();
- meta->euid = current_euid();
- meta->suid = current_suid();
- meta->fsuid = current_fsuid();
+ if (!mm->arg_end) {
+ mmput(mm);
+ return 0;
+ }
+
+ cmdline = strndup_user((const char __user *)mm->arg_start,
+ mm->arg_end - mm->arg_start);
+ mmput(mm);
+
+ if (IS_ERR(cmdline))
+ return PTR_ERR(cmdline);
+
+ mp->cmdline = cmdline;
+ mp->valid |= KDBUS_ATTACH_CMDLINE;
- meta->gid = current_gid();
- meta->egid = current_egid();
- meta->sgid = current_sgid();
- meta->fsgid = current_fsgid();
+ return 0;
+}
- meta->collected |= KDBUS_ATTACH_CREDS;
+static int kdbus_meta_proc_collect_cgroup(struct kdbus_meta_proc *mp)
+{
+#ifdef CONFIG_CGROUPS
+ void *page;
+ char *s;
+
+ page = (void*)__get_free_page(GFP_TEMPORARY);
+ if (!page)
+ return -ENOMEM;
+
+ s = task_cgroup_path(current, page, PAGE_SIZE);
+ if (s) {
+ mp->cgroup = kstrdup(s, GFP_KERNEL);
+ if (!mp->cgroup) {
+ free_page((unsigned long)page);
+ return -ENOMEM;
+ }
}
- if (mask & KDBUS_ATTACH_PIDS) {
- struct task_struct *parent;
+ free_page((unsigned long)page);
+ mp->valid |= KDBUS_ATTACH_CGROUP;
+#endif
+
+ return 0;
+}
- meta->pid = get_pid(task_pid(current));
- meta->tgid = get_pid(task_tgid(current));
+static void kdbus_meta_proc_collect_caps(struct kdbus_meta_proc *mp)
+{
+ const struct cred *c = current_cred();
+ int i;
- rcu_read_lock();
- parent = rcu_dereference(current->real_parent);
- meta->ppid = get_pid(task_tgid(parent));
- rcu_read_unlock();
+ /* ABI: "last_cap" equals /proc/sys/kernel/cap_last_cap */
+ mp->caps.last_cap = CAP_LAST_CAP;
+ mp->caps_namespace = get_user_ns(current_user_ns());
- meta->collected |= KDBUS_ATTACH_PIDS;
+ CAP_FOR_EACH_U32(i) {
+ mp->caps.set[0].caps[i] = c->cap_inheritable.cap[i];
+ mp->caps.set[1].caps[i] = c->cap_permitted.cap[i];
+ mp->caps.set[2].caps[i] = c->cap_effective.cap[i];
+ mp->caps.set[3].caps[i] = c->cap_bset.cap[i];
}
- if (mask & KDBUS_ATTACH_AUXGROUPS) {
- struct group_info *info;
+ /* clear unused bits */
+ for (i = 0; i < 4; i++)
+ mp->caps.set[i].caps[CAP_TO_INDEX(CAP_LAST_CAP)] &=
+ CAP_LAST_U32_VALID_MASK;
+
+ mp->valid |= KDBUS_ATTACH_CAPS;
+}
- info = get_current_groups();
+static int kdbus_meta_proc_collect_seclabel(struct kdbus_meta_proc *mp)
+{
+#ifdef CONFIG_SECURITY
+ char *ctx = NULL;
+ u32 sid, len;
+ int ret;
- if (info->ngroups > 0) {
- meta->auxgrps = kmalloc_array(info->ngroups,
- sizeof(kgid_t),
- GFP_KERNEL);
- if (!meta->auxgrps)
- return -ENOMEM;
+ security_task_getsecid(current, &sid);
+ ret = security_secid_to_secctx(sid, &ctx, &len);
+ if (ret < 0) {
+ /*
+ * EOPNOTSUPP means no security module is active,
+ * lets skip adding the seclabel then. This effectively
+ * drops the SECLABEL item.
+ */
+ return (ret == -EOPNOTSUPP) ? 0 : ret;
+ }
- for (i = 0; i < info->ngroups; i++)
- meta->auxgrps[i] = GROUP_AT(info, i);
- }
+ mp->seclabel = kstrdup(ctx, GFP_KERNEL);
+ security_release_secctx(ctx, len);
+ if (!mp->seclabel)
+ return -ENOMEM;
- meta->n_auxgrps = info->ngroups;
- put_group_info(info);
+ mp->valid |= KDBUS_ATTACH_SECLABEL;
+#endif
- meta->collected |= KDBUS_ATTACH_AUXGROUPS;
- }
+ return 0;
+}
- if (mask & KDBUS_ATTACH_PID_COMM) {
- get_task_comm(meta->pid_comm, current->group_leader);
- meta->collected |= KDBUS_ATTACH_PID_COMM;
+static void kdbus_meta_proc_collect_audit(struct kdbus_meta_proc *mp)
+{
+#ifdef CONFIG_AUDITSYSCALL
+ mp->audit_loginuid = audit_get_loginuid(current);
+ mp->audit_sessionid = audit_get_sessionid(current);
+ mp->valid |= KDBUS_ATTACH_AUDIT;
+#endif
+}
+
+/**
+ * kdbus_meta_proc_collect() - Collect process metadata
+ * @mp: Process metadata object
+ * @what: Attach flags to collect
+ *
+ * This collects process metadata from current and saves it in @mp.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what)
+{
+ int ret;
+
+ if (!mp)
+ return 0;
+
+ mutex_lock(&mp->lock);
+
+ if ((what & KDBUS_ATTACH_CREDS) &&
+ !(mp->collected & KDBUS_ATTACH_CREDS)) {
+ kdbus_meta_proc_collect_creds(mp);
+ mp->collected |= KDBUS_ATTACH_CREDS;
}
- if (mask & KDBUS_ATTACH_TID_COMM) {
- get_task_comm(meta->tid_comm, current);
- meta->collected |= KDBUS_ATTACH_TID_COMM;
+ if ((what & KDBUS_ATTACH_PIDS) &&
+ !(mp->collected & KDBUS_ATTACH_PIDS)) {
+ kdbus_meta_proc_collect_pids(mp);
+ mp->collected |= KDBUS_ATTACH_PIDS;
}
- if (mask & KDBUS_ATTACH_EXE) {
- struct mm_struct *mm = get_task_mm(current);
+ if ((what & KDBUS_ATTACH_AUXGROUPS) &&
+ !(mp->collected & KDBUS_ATTACH_AUXGROUPS)) {
+ ret = kdbus_meta_proc_collect_auxgroups(mp);
+ if (ret < 0)
+ goto exit_unlock;
+ mp->collected |= KDBUS_ATTACH_AUXGROUPS;
+ }
- get_fs_root(current->fs, &meta->root_path);
+ if ((what & KDBUS_ATTACH_TID_COMM) &&
+ !(mp->collected & KDBUS_ATTACH_TID_COMM)) {
+ kdbus_meta_proc_collect_tid_comm(mp);
+ mp->collected |= KDBUS_ATTACH_TID_COMM;
+ }
- if (mm) {
- down_read(&mm->mmap_sem);
- meta->exe = get_file(mm->exe_file);
- up_read(&mm->mmap_sem);
- mmput(mm);
- }
+ if ((what & KDBUS_ATTACH_PID_COMM) &&
+ !(mp->collected & KDBUS_ATTACH_PID_COMM)) {
+ kdbus_meta_proc_collect_pid_comm(mp);
+ mp->collected |= KDBUS_ATTACH_PID_COMM;
+ }
- meta->collected |= KDBUS_ATTACH_EXE;
+ if ((what & KDBUS_ATTACH_EXE) &&
+ !(mp->collected & KDBUS_ATTACH_EXE)) {
+ kdbus_meta_proc_collect_exe(mp);
+ mp->collected |= KDBUS_ATTACH_EXE;
}
- if (mask & KDBUS_ATTACH_CMDLINE) {
- struct mm_struct *mm = get_task_mm(current);
+ if ((what & KDBUS_ATTACH_CMDLINE) &&
+ !(mp->collected & KDBUS_ATTACH_CMDLINE)) {
+ ret = kdbus_meta_proc_collect_cmdline(mp);
+ if (ret < 0)
+ goto exit_unlock;
+ mp->collected |= KDBUS_ATTACH_CMDLINE;
+ }
- if (mm && mm->arg_end) {
- size_t len = mm->arg_end - mm->arg_start;
- const char __user *s;
+ if ((what & KDBUS_ATTACH_CGROUP) &&
+ !(mp->collected & KDBUS_ATTACH_CGROUP)) {
+ ret = kdbus_meta_proc_collect_cgroup(mp);
+ if (ret < 0)
+ goto exit_unlock;
+ mp->collected |= KDBUS_ATTACH_CGROUP;
+ }
- s = (const char __user *)mm->arg_start;
- meta->cmdline = strndup_user(s, len);
- mmput(mm);
+ if ((what & KDBUS_ATTACH_CAPS) &&
+ !(mp->collected & KDBUS_ATTACH_CAPS)) {
+ kdbus_meta_proc_collect_caps(mp);
+ mp->collected |= KDBUS_ATTACH_CAPS;
+ }
- if (!meta->cmdline)
- return -ENOMEM;
- }
+ if ((what & KDBUS_ATTACH_SECLABEL) &&
+ !(mp->collected & KDBUS_ATTACH_SECLABEL)) {
+ ret = kdbus_meta_proc_collect_seclabel(mp);
+ if (ret < 0)
+ goto exit_unlock;
+ mp->collected |= KDBUS_ATTACH_SECLABEL;
+ }
- meta->collected |= KDBUS_ATTACH_CMDLINE;
+ if ((what & KDBUS_ATTACH_AUDIT) &&
+ !(mp->collected & KDBUS_ATTACH_AUDIT)) {
+ kdbus_meta_proc_collect_audit(mp);
+ mp->collected |= KDBUS_ATTACH_AUDIT;
}
-#ifdef CONFIG_CGROUPS
- /* attach the path of the one group hierarchy specified for the bus */
- if (mask & KDBUS_ATTACH_CGROUP) {
- char *s;
-
- s = task_cgroup_path(current, meta->tmp, sizeof(meta->tmp));
- if (s) {
- meta->cgroup = kstrdup(s, GFP_KERNEL);
- if (!meta->cgroup)
- return -ENOMEM;
- }
+ ret = 0;
- meta->collected |= KDBUS_ATTACH_CGROUP;
- }
-#endif
+exit_unlock:
+ mutex_unlock(&mp->lock);
+ return ret;
+}
+
+/**
+ * kdbus_meta_proc_fake() - Fill process metadata from faked credentials
+ * @meta: Metadata
+ * @creds: Creds to set, may be %NULL
+ * @pids: PIDs to set, may be %NULL
+ * @seclabel: Seclabel to set, may be %NULL
+ *
+ * This function takes information stored in @creds, @pids and @seclabel and
+ * resolves them to kernel-representations, if possible. A call to this function
+ * is considered an alternative to calling kdbus_meta_add_current(), which
+ * derives the same information from the 'current' task.
+ *
+ * This call uses the current task's namespaces to resolve the given
+ * information.
+ *
+ * Return: 0 on success, negative error number otherwise.
+ */
+int kdbus_meta_proc_fake(struct kdbus_meta_proc *mp,
+ const struct kdbus_creds *creds,
+ const struct kdbus_pids *pids,
+ const char *seclabel)
+{
+ int ret;
- if (mask & KDBUS_ATTACH_CAPS) {
- const struct cred *c = current_cred();
+ if (!mp)
+ return 0;
- /* ABI: "last_cap" equals /proc/sys/kernel/cap_last_cap */
- meta->caps.last_cap = CAP_LAST_CAP;
- meta->caps_namespace = get_user_ns(current_user_ns());
+ mutex_lock(&mp->lock);
- CAP_FOR_EACH_U32(i) {
- meta->caps.set[0].caps[i] = c->cap_inheritable.cap[i];
- meta->caps.set[1].caps[i] = c->cap_permitted.cap[i];
- meta->caps.set[2].caps[i] = c->cap_effective.cap[i];
- meta->caps.set[3].caps[i] = c->cap_bset.cap[i];
- }
+ if (creds && !(mp->collected & KDBUS_ATTACH_CREDS)) {
+ struct user_namespace *ns = current_user_ns();
- /* clear unused bits */
- for (i = 0; i < 4; i++)
- meta->caps.set[i].caps[CAP_TO_INDEX(CAP_LAST_CAP)] &=
- CAP_LAST_U32_VALID_MASK;
+ mp->uid = make_kuid(ns, creds->uid);
+ mp->euid = make_kuid(ns, creds->euid);
+ mp->suid = make_kuid(ns, creds->suid);
+ mp->fsuid = make_kuid(ns, creds->fsuid);
+
+ mp->gid = make_kgid(ns, creds->gid);
+ mp->egid = make_kgid(ns, creds->egid);
+ mp->sgid = make_kgid(ns, creds->sgid);
+ mp->fsgid = make_kgid(ns, creds->fsgid);
+
+ if ((creds->uid != (uid_t)-1 && !uid_valid(mp->uid)) ||
+ (creds->euid != (uid_t)-1 && !uid_valid(mp->euid)) ||
+ (creds->suid != (uid_t)-1 && !uid_valid(mp->suid)) ||
+ (creds->fsuid != (uid_t)-1 && !uid_valid(mp->fsuid)) ||
+ (creds->gid != (gid_t)-1 && !gid_valid(mp->gid)) ||
+ (creds->egid != (gid_t)-1 && !gid_valid(mp->egid)) ||
+ (creds->sgid != (gid_t)-1 && !gid_valid(mp->sgid)) ||
+ (creds->fsgid != (gid_t)-1 && !gid_valid(mp->fsgid))) {
+ ret = -EINVAL;
+ goto exit_unlock;
+ }
- meta->collected |= KDBUS_ATTACH_CAPS;
+ mp->valid |= KDBUS_ATTACH_CREDS;
+ mp->collected |= KDBUS_ATTACH_CREDS;
}
-#ifdef CONFIG_SECURITY
- if (mask & KDBUS_ATTACH_SECLABEL) {
- u32 sid;
- char *ctx = NULL;
- u32 len;
- int ret;
-
- security_task_getsecid(current, &sid);
- ret = security_secid_to_secctx(sid, &ctx, &len);
- if (ret == -EOPNOTSUPP) {
- /*
- * EOPNOTSUPP means no security module is active,
- * lets skip adding the seclabel then. This effectively
- * drops the SECLABEL item.
- */
- } else if (ret < 0) {
- return ret;
- } else {
- meta->seclabel = kstrdup(ctx, GFP_KERNEL);
- security_release_secctx(ctx, len);
- if (!meta->seclabel)
- return -ENOMEM;
-
- meta->collected |= KDBUS_ATTACH_SECLABEL;
+ if (pids && !(mp->collected & KDBUS_ATTACH_PIDS)) {
+ mp->pid = get_pid(find_vpid(pids->tid));
+ mp->tgid = get_pid(find_vpid(pids->pid));
+ mp->ppid = get_pid(find_vpid(pids->ppid));
+
+ if ((pids->tid != 0 && !mp->pid) ||
+ (pids->pid != 0 && !mp->tgid) ||
+ (pids->ppid != 0 && !mp->ppid)) {
+ put_pid(mp->pid);
+ put_pid(mp->tgid);
+ put_pid(mp->ppid);
+ mp->pid = NULL;
+ mp->tgid = NULL;
+ mp->ppid = NULL;
+ ret = -EINVAL;
+ goto exit_unlock;
}
+
+ mp->valid |= KDBUS_ATTACH_PIDS;
+ mp->collected |= KDBUS_ATTACH_PIDS;
}
-#endif
-#ifdef CONFIG_AUDITSYSCALL
- if (mask & KDBUS_ATTACH_AUDIT) {
- meta->audit_loginuid = audit_get_loginuid(current);
- meta->audit_sessionid = audit_get_sessionid(current);
- meta->collected |= KDBUS_ATTACH_AUDIT;
+ if (seclabel && !(mp->collected & KDBUS_ATTACH_SECLABEL)) {
+ mp->seclabel = kstrdup(seclabel, GFP_KERNEL);
+ if (!mp->seclabel) {
+ ret = -ENOMEM;
+ goto exit_unlock;
+ }
+
+ mp->valid |= KDBUS_ATTACH_SECLABEL;
+ mp->collected |= KDBUS_ATTACH_SECLABEL;
}
-#endif
- return 0;
+ ret = 0;
+
+exit_unlock:
+ mutex_unlock(&mp->lock);
+ return ret;
}
/**
- * kdbus_meta_calc_attach_flags() - calculate attach flags for a sender
- * and a receiver
- * @sender: Sending connection
- * @receiver: Receiving connection
+ * kdbus_meta_conn_new() - Create connection metadata object
*
- * Return: the attach flags both the sender and the receiver have opted-in
- * for.
+ * Return: Pointer to new object on success, ERR_PTR on failure.
*/
-u64 kdbus_meta_calc_attach_flags(const struct kdbus_conn *sender,
- const struct kdbus_conn *receiver)
+struct kdbus_meta_conn *kdbus_meta_conn_new(void)
{
- return atomic64_read(&sender->attach_flags_send) &
- atomic64_read(&receiver->attach_flags_recv);
+ struct kdbus_meta_conn *mc;
+
+ mc = kzalloc(sizeof(*mc), GFP_KERNEL);
+ if (!mc)
+ return ERR_PTR(-ENOMEM);
+
+ kref_init(&mc->kref);
+ mutex_init(&mc->lock);
+
+ return mc;
}
-/*
- * kdbus_meta_add_conn_info() - collect connection description and
- * owned names from source connection
- * @meta: Metadata object where to store the collected info
- * @conn: Connection to get owned names and description from
- * @which: KDBUS_ATTACH_* mask
- *
- * This function collectes only KDBUS_ITEM_CONN_DESCRIPTION and
- * KDBUS_ITEM_OWNED_NAMES. If the items were already collected then they
- * are freed and added again. These items must always reflect the
- * current information.
- *
- * Return: 0 on success, negative errno on failure.
+static void kdbus_meta_conn_free(struct kref *kref)
+{
+ struct kdbus_meta_conn *mc = container_of(kref, struct kdbus_meta_conn,
+ kref);
+
+ kfree(mc->conn_description);
+ kfree(mc->owned_names_items);
+ kfree(mc);
+}
+
+/**
+ * kdbus_meta_conn_ref() - Gain reference
+ * @mc: Connection metadata object
+ */
+struct kdbus_meta_conn *kdbus_meta_conn_ref(struct kdbus_meta_conn *mc)
+{
+ if (mc)
+ kref_get(&mc->kref);
+ return mc;
+}
+
+/**
+ * kdbus_meta_conn_unref() - Drop reference
+ * @mc: Connection metadata object
*/
-int kdbus_meta_add_conn_info(struct kdbus_meta *meta,
- struct kdbus_conn *conn, u64 which)
+struct kdbus_meta_conn *kdbus_meta_conn_unref(struct kdbus_meta_conn *mc)
+{
+ if (mc)
+ kref_put(&mc->kref, kdbus_meta_conn_free);
+ return NULL;
+}
+
+static void kdbus_meta_conn_collect_timestamp(struct kdbus_meta_conn *mc,
+ struct kdbus_kmsg *kmsg)
+{
+ struct timespec ts;
+
+ ktime_get_ts(&ts);
+ mc->ts.monotonic_ns = timespec_to_ns(&ts);
+
+ ktime_get_real_ts(&ts);
+ mc->ts.realtime_ns = timespec_to_ns(&ts);
+
+ if (kmsg)
+ mc->ts.seqnum = kmsg->seq;
+
+ mc->valid |= KDBUS_ATTACH_TIMESTAMP;
+}
+
+static int kdbus_meta_conn_collect_names(struct kdbus_meta_conn *mc,
+ struct kdbus_conn *conn)
{
const struct kdbus_name_entry *e;
struct kdbus_item *item;
- bool meta_description;
- bool meta_names;
- int ret = 0;
+ size_t slen, size;
- if (!conn)
+ size = 0;
+ list_for_each_entry(e, &conn->names_list, conn_entry)
+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_name) +
+ strlen(e->name) + 1);
+
+ if (!size)
return 0;
- /*
- * Before taking any lock, first check if:
- * 1) we are interested in the info
- * 2) connection do own names
- * 3) connection has a conn description field, this field
- * is only writable when connections are created
- */
- meta_names = (which & KDBUS_ATTACH_NAMES &&
- atomic_read(&conn->name_count) > 0);
- meta_description = (which & KDBUS_ATTACH_CONN_DESCRIPTION &&
- conn->description);
+ item = kmalloc(size, GFP_KERNEL);
+ if (!item)
+ return -ENOMEM;
- if (!meta_names && !meta_description)
- return 0;
+ mc->owned_names_items = item;
+ mc->owned_names_size = size;
+
+ list_for_each_entry(e, &conn->names_list, conn_entry) {
+ slen = strlen(e->name) + 1;
+ kdbus_item_set(item, KDBUS_ITEM_OWNED_NAME, NULL,
+ sizeof(struct kdbus_name) + slen);
+ item->name.flags = e->flags;
+ memcpy(item->name.name, e->name, slen);
+ item = KDBUS_ITEM_NEXT(item);
+ }
- mutex_lock(&conn->lock);
+ /* sanity check: the buffer should be completely written now */
+ WARN_ON((u8 *)item != (u8 *)mc->owned_names_items + size);
- /* Add owned names */
- if (meta_names) {
- size_t size = 0;
+ mc->valid |= KDBUS_ATTACH_NAMES;
+ return 0;
+}
- list_for_each_entry(e, &conn->names_list, conn_entry)
- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_name) +
- strlen(e->name) + 1);
+static int kdbus_meta_conn_collect_description(struct kdbus_meta_conn *mc,
+ struct kdbus_conn *conn)
+{
+ if (!conn->description)
+ return 0;
- item = kzalloc(size, GFP_KERNEL);
- if (!item) {
- ret = -ENOMEM;
- goto exit_unlock;
- }
+ mc->conn_description = kstrdup(conn->description, GFP_KERNEL);
+ if (!mc->conn_description)
+ return -ENOMEM;
- /* Free previous added names */
- kfree(meta->owned_names_items);
- meta->owned_names_items = item;
- meta->owned_names_size = size;
+ mc->valid |= KDBUS_ATTACH_CONN_DESCRIPTION;
+ return 0;
+}
- list_for_each_entry(e, &conn->names_list, conn_entry) {
- size_t slen = strlen(e->name) + 1;
+/**
+ * kdbus_meta_conn_collect() - Collect connection metadata
+ * @mc: Message metadata object
+ * @kmsg: Kmsg to collect data from
+ * @conn: Connection to collect data from
+ * @what: Attach flags to collect
+ *
+ * This collects connection metadata from @kmsg and @conn and saves it in @mc.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc,
+ struct kdbus_kmsg *kmsg,
+ struct kdbus_conn *conn,
+ u64 what)
+{
+ int ret;
- kdbus_item_set(item, KDBUS_ITEM_OWNED_NAME, NULL,
- sizeof(struct kdbus_name) + slen);
- item->name.flags = e->flags;
- memcpy(item->name.name, e->name, slen);
- item = KDBUS_ITEM_NEXT(item);
- }
+ if (!mc)
+ return 0;
- /* sanity check: the buffer should be completely written now */
- WARN_ON((u8 *)item != (u8 *)meta->owned_names_items + size);
+ if (conn)
+ mutex_lock(&conn->lock);
+ mutex_lock(&mc->lock);
- meta->collected |= KDBUS_ATTACH_NAMES;
+ if (kmsg && (what & KDBUS_ATTACH_TIMESTAMP) &&
+ !(mc->collected & KDBUS_ATTACH_TIMESTAMP)) {
+ kdbus_meta_conn_collect_timestamp(mc, kmsg);
+ mc->collected |= KDBUS_ATTACH_TIMESTAMP;
}
- if (meta_description) {
- /* free previous add connection description */
- kfree(meta->conn_description);
- meta->conn_description = kstrdup(conn->description,
- GFP_KERNEL);
- if (!meta->conn_description) {
- ret = -ENOMEM;
+
+ if (conn && (what & KDBUS_ATTACH_NAMES) &&
+ !(mc->collected & KDBUS_ATTACH_NAMES)) {
+ ret = kdbus_meta_conn_collect_names(mc, conn);
+ if (ret < 0)
goto exit_unlock;
- }
+ mc->collected |= KDBUS_ATTACH_NAMES;
+ }
- meta->collected |= KDBUS_ATTACH_CONN_DESCRIPTION;
+ if (conn && (what & KDBUS_ATTACH_CONN_DESCRIPTION) &&
+ !(mc->collected & KDBUS_ATTACH_CONN_DESCRIPTION)) {
+ ret = kdbus_meta_conn_collect_description(mc, conn);
+ if (ret < 0)
+ goto exit_unlock;
+ mc->collected |= KDBUS_ATTACH_CONN_DESCRIPTION;
}
+ ret = 0;
+
exit_unlock:
- mutex_unlock(&conn->lock);
+ mutex_unlock(&mc->lock);
+ if (conn)
+ mutex_unlock(&conn->lock);
return ret;
}
/**
* kdbus_meta_export() - export information from metadata into buffer
- * @meta: The metadata object
+ * @mp: Process metadata, or NULL
+ * @mc: Connection metadata, or NULL
* @mask: Mask of KDBUS_ATTACH_* flags to export
* @sz: Pointer to return the buffer size
*
@@ -612,59 +797,78 @@ exit_unlock:
* Only information that is requested in @mask and that has been collected
* before is exported.
*
- * All information will be translated using the namespaces pinned by @conn_dst.
- *
- * Upon success, @buf will point to the newly allocated buffer, and @sz will
- * report the length of that buffer. The caller is obliged to free @buf when no
- * longer needed.
+ * All information will be translated using the current namespaces.
*
* Return: An array of items on success, ERR_PTR value on errors. On success,
- * @sz is also set to the number of bytes returned in the items array.
+ * @sz is also set to the number of bytes returned in the items array. The
+ * caller must release the buffer via kfree().
*/
-struct kdbus_item *kdbus_meta_export(struct kdbus_meta *meta,
- u64 mask, size_t *sz)
+struct kdbus_item *kdbus_meta_export(struct kdbus_meta_proc *mp,
+ struct kdbus_meta_conn *mc,
+ u64 mask,
+ size_t *sz)
{
struct user_namespace *user_ns = current_user_ns();
struct kdbus_item *item, *items = NULL;
char *exe_pathname = NULL;
+ void *exe_page = NULL;
size_t size = 0;
- int ret = 0;
+ u64 valid = 0;
+ int ret;
+
+ if (WARN_ON(!sz))
+ return ERR_PTR(-EINVAL);
- mask &= meta->collected & kdbus_meta_attach_mask;
+ if (mp) {
+ mutex_lock(&mp->lock);
+ valid |= mp ? mp->valid : 0;
+ mutex_unlock(&mp->lock);
+ }
+
+ if (mc) {
+ mutex_lock(&mc->lock);
+ valid |= mc ? mc->valid : 0;
+ mutex_unlock(&mc->lock);
+ }
+
+ mask &= valid;
+ mask &= kdbus_meta_attach_mask;
/*
- * We currently have no sane way of translating a set of caps
+ * TODO: We currently have no sane way of translating a set of caps
* between different user namespaces. Until that changes, we have
* to drop such items.
*/
- if (meta->caps_namespace != user_ns)
+ if (mp && mp->caps_namespace != user_ns)
mask &= ~KDBUS_ATTACH_CAPS;
- /* First, determine the overall size of all items */
+ if (!mask) {
+ *sz = 0;
+ return NULL;
+ }
- if (mask & KDBUS_ATTACH_TIMESTAMP)
- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_timestamp));
+ /* process metadata */
- if (mask & KDBUS_ATTACH_CREDS)
+ if (mp && (mask & KDBUS_ATTACH_CREDS))
size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds));
- if (mask & KDBUS_ATTACH_PIDS)
+ if (mp && (mask & KDBUS_ATTACH_PIDS))
size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids));
- if (mask & KDBUS_ATTACH_AUXGROUPS)
- size += KDBUS_ITEM_SIZE(meta->n_auxgrps * sizeof(u32));
+ if (mp && (mask & KDBUS_ATTACH_AUXGROUPS))
+ size += KDBUS_ITEM_SIZE(mp->n_auxgrps * sizeof(u32));
- if (mask & KDBUS_ATTACH_PID_COMM)
- size += KDBUS_ITEM_SIZE(strlen(meta->pid_comm) + 1);
+ if (mp && (mask & KDBUS_ATTACH_TID_COMM))
+ size += KDBUS_ITEM_SIZE(strlen(mp->tid_comm) + 1);
- if (mask & KDBUS_ATTACH_TID_COMM)
- size += KDBUS_ITEM_SIZE(strlen(meta->tid_comm) + 1);
+ if (mp && (mask & KDBUS_ATTACH_PID_COMM))
+ size += KDBUS_ITEM_SIZE(strlen(mp->pid_comm) + 1);
- if (mask & KDBUS_ATTACH_EXE) {
+ if (mp && (mask & KDBUS_ATTACH_EXE)) {
struct path p;
/*
- * FIXME: We need access to __d_path() so we can write the path
+ * TODO: We need access to __d_path() so we can write the path
* relative to conn->root_path. Once upstream, we need
* EXPORT_SYMBOL(__d_path) or an equivalent of d_path() that
* takes the root path directly. Until then, we drop this item
@@ -672,177 +876,189 @@ struct kdbus_item *kdbus_meta_export(struct kdbus_meta *meta,
*/
get_fs_root(current->fs, &p);
- if (path_equal(&p, &meta->root_path)) {
- exe_pathname = d_path(&meta->exe->f_path,
- meta->tmp, sizeof(meta->tmp));
+ if (path_equal(&p, &mp->root_path)) {
+ exe_page = (void*)__get_free_page(GFP_TEMPORARY);
+ if (!exe_page) {
+ path_put(&p);
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ exe_pathname = d_path(&mp->exe_path, exe_page,
+ PAGE_SIZE);
if (IS_ERR(exe_pathname)) {
+ path_put(&p);
ret = PTR_ERR(exe_pathname);
- goto exit_free;
+ goto exit;
}
size += KDBUS_ITEM_SIZE(strlen(exe_pathname) + 1);
+ } else {
+ mask &= ~KDBUS_ATTACH_EXE;
}
path_put(&p);
}
- if (mask & KDBUS_ATTACH_CMDLINE)
- size += KDBUS_ITEM_SIZE(strlen(meta->cmdline) + 1);
+ if (mp && (mask & KDBUS_ATTACH_CMDLINE))
+ size += KDBUS_ITEM_SIZE(strlen(mp->cmdline) + 1);
- if (mask & KDBUS_ATTACH_CGROUP)
- size += KDBUS_ITEM_SIZE(strlen(meta->cgroup) + 1);
+ if (mp && (mask & KDBUS_ATTACH_CGROUP))
+ size += KDBUS_ITEM_SIZE(strlen(mp->cgroup) + 1);
- if (mask & KDBUS_ATTACH_CAPS)
- size += KDBUS_ITEM_SIZE(sizeof(meta->caps));
+ if (mp && (mask & KDBUS_ATTACH_CAPS))
+ size += KDBUS_ITEM_SIZE(sizeof(mp->caps));
- if (mask & KDBUS_ATTACH_SECLABEL)
- size += KDBUS_ITEM_SIZE(strlen(meta->seclabel) + 1);
+ if (mp && (mask & KDBUS_ATTACH_SECLABEL))
+ size += KDBUS_ITEM_SIZE(strlen(mp->seclabel) + 1);
- if (mask & KDBUS_ATTACH_AUDIT)
+ if (mp && (mask & KDBUS_ATTACH_AUDIT))
size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_audit));
- if (mask & KDBUS_ATTACH_CONN_DESCRIPTION)
- size += KDBUS_ITEM_SIZE(strlen(meta->conn_description) + 1);
+ /* connection metadata */
- if (mask & KDBUS_ATTACH_NAMES)
- size += meta->owned_names_size;
+ if (mc && (mask & KDBUS_ATTACH_NAMES))
+ size += mc->owned_names_size;
- /*
- * Now we know how big our final blog of metadata will be.
- * Allocate memory and fill in the items.
- */
+ if (mc && (mask & KDBUS_ATTACH_CONN_DESCRIPTION))
+ size += KDBUS_ITEM_SIZE(strlen(mc->conn_description) + 1);
+
+ if (mc && (mask & KDBUS_ATTACH_TIMESTAMP))
+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_timestamp));
+
+ if (!size) {
+ *sz = 0;
+ ret = 0;
+ goto exit;
+ }
items = kzalloc(size, GFP_KERNEL);
if (!items) {
ret = -ENOMEM;
- goto exit_free;
+ goto exit;
}
item = items;
- if (mask & KDBUS_ATTACH_TIMESTAMP) {
- struct kdbus_timestamp ts = {
- .seqnum = meta->seq,
- .monotonic_ns = meta->ts_monotonic_ns,
- .realtime_ns = meta->ts_realtime_ns,
- };
+ /* process metadata */
- kdbus_item_set(item, KDBUS_ITEM_TIMESTAMP, &ts, sizeof(ts));
- item = KDBUS_ITEM_NEXT(item);
- }
-
- if (mask & KDBUS_ATTACH_CREDS) {
+ if (mp && (mask & KDBUS_ATTACH_CREDS)) {
struct kdbus_creds creds = {
- .uid = kdbus_from_kuid_keep(meta->uid),
- .euid = kdbus_from_kuid_keep(meta->euid),
- .suid = kdbus_from_kuid_keep(meta->suid),
- .fsuid = kdbus_from_kuid_keep(meta->fsuid),
- .gid = kdbus_from_kgid_keep(meta->gid),
- .egid = kdbus_from_kgid_keep(meta->egid),
- .sgid = kdbus_from_kgid_keep(meta->sgid),
- .fsgid = kdbus_from_kgid_keep(meta->fsgid),
+ .uid = kdbus_from_kuid_keep(mp->uid),
+ .euid = kdbus_from_kuid_keep(mp->euid),
+ .suid = kdbus_from_kuid_keep(mp->suid),
+ .fsuid = kdbus_from_kuid_keep(mp->fsuid),
+ .gid = kdbus_from_kgid_keep(mp->gid),
+ .egid = kdbus_from_kgid_keep(mp->egid),
+ .sgid = kdbus_from_kgid_keep(mp->sgid),
+ .fsgid = kdbus_from_kgid_keep(mp->fsgid),
};
- kdbus_item_set(item, KDBUS_ITEM_CREDS, &creds, sizeof(creds));
- item = KDBUS_ITEM_NEXT(item);
+ item = kdbus_item_set(item, KDBUS_ITEM_CREDS, &creds,
+ sizeof(creds));
}
- if (mask & KDBUS_ATTACH_PIDS) {
+ if (mp && (mask & KDBUS_ATTACH_PIDS)) {
struct kdbus_pids pids = {
- .pid = pid_vnr(meta->tgid),
- .tid = pid_vnr(meta->pid),
- .ppid = pid_vnr(meta->ppid),
+ .pid = pid_vnr(mp->tgid),
+ .tid = pid_vnr(mp->pid),
+ .ppid = pid_vnr(mp->ppid),
};
- kdbus_item_set(item, KDBUS_ITEM_PIDS, &pids, sizeof(pids));
- item = KDBUS_ITEM_NEXT(item);
+ item = kdbus_item_set(item, KDBUS_ITEM_PIDS, &pids,
+ sizeof(pids));
}
- if (mask & KDBUS_ATTACH_AUXGROUPS) {
+ if (mp && (mask & KDBUS_ATTACH_AUXGROUPS)) {
int i;
- kdbus_item_set(item, KDBUS_ITEM_AUXGROUPS,
- NULL, meta->n_auxgrps * sizeof(u32));
+ kdbus_item_set(item, KDBUS_ITEM_AUXGROUPS, NULL,
+ mp->n_auxgrps * sizeof(u32));
- for (i = 0; i < meta->n_auxgrps; i++)
- item->data32[i] =
- from_kgid_munged(user_ns, meta->auxgrps[i]);
+ for (i = 0; i < mp->n_auxgrps; i++)
+ item->data32[i] = from_kgid_munged(user_ns,
+ mp->auxgrps[i]);
item = KDBUS_ITEM_NEXT(item);
}
- if (mask & KDBUS_ATTACH_PID_COMM) {
- kdbus_item_set(item, KDBUS_ITEM_PID_COMM,
- meta->pid_comm, strlen(meta->pid_comm) + 1);
- item = KDBUS_ITEM_NEXT(item);
- }
+ if (mp && (mask & KDBUS_ATTACH_TID_COMM))
+ item = kdbus_item_set(item, KDBUS_ITEM_TID_COMM, mp->tid_comm,
+ strlen(mp->tid_comm) + 1);
- if (mask & KDBUS_ATTACH_TID_COMM) {
- kdbus_item_set(item, KDBUS_ITEM_TID_COMM,
- meta->tid_comm, strlen(meta->tid_comm) + 1);
- item = KDBUS_ITEM_NEXT(item);
- }
+ if (mp && (mask & KDBUS_ATTACH_PID_COMM))
+ item = kdbus_item_set(item, KDBUS_ITEM_PID_COMM, mp->pid_comm,
+ strlen(mp->pid_comm) + 1);
- if ((mask & KDBUS_ATTACH_EXE) && exe_pathname) {
- kdbus_item_set(item, KDBUS_ITEM_EXE,
- exe_pathname, strlen(exe_pathname) + 1);
- item = KDBUS_ITEM_NEXT(item);
- }
+ if (mp && (mask & KDBUS_ATTACH_EXE))
+ item = kdbus_item_set(item, KDBUS_ITEM_EXE, exe_pathname,
+ strlen(exe_pathname) + 1);
- if (mask & KDBUS_ATTACH_CMDLINE) {
- kdbus_item_set(item, KDBUS_ITEM_CMDLINE,
- meta->cmdline, strlen(meta->cmdline) + 1);
- item = KDBUS_ITEM_NEXT(item);
- }
+ if (mp && (mask & KDBUS_ATTACH_CMDLINE))
+ item = kdbus_item_set(item, KDBUS_ITEM_CMDLINE, mp->cmdline,
+ strlen(mp->cmdline) + 1);
- if (mask & KDBUS_ATTACH_CGROUP) {
- kdbus_item_set(item, KDBUS_ITEM_CGROUP,
- meta->cgroup, strlen(meta->cgroup) + 1);
- item = KDBUS_ITEM_NEXT(item);
- }
+ if (mp && (mask & KDBUS_ATTACH_CGROUP))
+ item = kdbus_item_set(item, KDBUS_ITEM_CGROUP, mp->cgroup,
+ strlen(mp->cgroup) + 1);
- if (mask & KDBUS_ATTACH_CAPS) {
- kdbus_item_set(item, KDBUS_ITEM_CAPS,
- &meta->caps, sizeof(meta->caps));
- item = KDBUS_ITEM_NEXT(item);
- }
+ if (mp && (mask & KDBUS_ATTACH_CAPS))
+ item = kdbus_item_set(item, KDBUS_ITEM_CAPS, &mp->caps,
+ sizeof(mp->caps));
- if (mask & KDBUS_ATTACH_SECLABEL) {
- kdbus_item_set(item, KDBUS_ITEM_SECLABEL,
- meta->seclabel, strlen(meta->seclabel) + 1);
- item = KDBUS_ITEM_NEXT(item);
- }
+ if (mp && (mask & KDBUS_ATTACH_SECLABEL))
+ item = kdbus_item_set(item, KDBUS_ITEM_SECLABEL, mp->seclabel,
+ strlen(mp->seclabel) + 1);
- if (mask & KDBUS_ATTACH_AUDIT) {
+ if (mp && (mask & KDBUS_ATTACH_AUDIT)) {
struct kdbus_audit a = {
- .loginuid = from_kuid(user_ns, meta->audit_loginuid),
- .sessionid = meta->audit_sessionid,
+ .loginuid = from_kuid(user_ns, mp->audit_loginuid),
+ .sessionid = mp->audit_sessionid,
};
- kdbus_item_set(item, KDBUS_ITEM_AUDIT, &a, sizeof(a));
- item = KDBUS_ITEM_NEXT(item);
+ item = kdbus_item_set(item, KDBUS_ITEM_AUDIT, &a, sizeof(a));
}
- if (mask & KDBUS_ATTACH_CONN_DESCRIPTION) {
- kdbus_item_set(item, KDBUS_ITEM_CONN_DESCRIPTION,
- meta->conn_description,
- strlen(meta->conn_description) + 1);
- item = KDBUS_ITEM_NEXT(item);
- }
+ /* connection metadata */
- if (mask & KDBUS_ATTACH_NAMES) {
- memcpy(item, meta->owned_names_items, meta->owned_names_size);
+ if (mc && (mask & KDBUS_ATTACH_NAMES)) {
+ memcpy(item, mc->owned_names_items, mc->owned_names_size);
item = (struct kdbus_item *)
- ((u8 *)item + meta->owned_names_size);
+ ((u8 *)item + mc->owned_names_size);
}
+ if (mc && (mask & KDBUS_ATTACH_CONN_DESCRIPTION))
+ item = kdbus_item_set(item, KDBUS_ITEM_CONN_DESCRIPTION,
+ mc->conn_description,
+ strlen(mc->conn_description) + 1);
+
+ if (mc && (mask & KDBUS_ATTACH_TIMESTAMP))
+ item = kdbus_item_set(item, KDBUS_ITEM_TIMESTAMP, &mc->ts,
+ sizeof(mc->ts));
+
/* sanity check: the buffer should be completely written now */
WARN_ON((u8 *)item != (u8 *)items + size);
*sz = size;
+ ret = 0;
-exit_free:
- if (ret < 0)
- return ERR_PTR(ret);
+exit:
+ if (exe_page)
+ free_page((unsigned long)exe_page);
+ return ret < 0 ? ERR_PTR(ret) : items;
+}
- return items;
+/**
+ * kdbus_meta_calc_attach_flags() - calculate attach flags for a sender
+ * and a receiver
+ * @sender: Sending connection
+ * @receiver: Receiving connection
+ *
+ * Return: the attach flags both the sender and the receiver have opted-in
+ * for.
+ */
+u64 kdbus_meta_calc_attach_flags(const struct kdbus_conn *sender,
+ const struct kdbus_conn *receiver)
+{
+ return atomic64_read(&sender->attach_flags_send) &
+ atomic64_read(&receiver->attach_flags_recv);
}
diff --git a/metadata.h b/metadata.h
index dac5ccb5953..4ddac7bf630 100644
--- a/metadata.h
+++ b/metadata.h
@@ -15,27 +15,37 @@
#ifndef __KDBUS_METADATA_H
#define __KDBUS_METADATA_H
-struct kdbus_meta;
struct kdbus_conn;
struct kdbus_domain;
+struct kdbus_kmsg;
struct kdbus_pool_slice;
+struct kdbus_meta_proc;
+struct kdbus_meta_conn;
+
extern unsigned long long kdbus_meta_attach_mask;
-struct kdbus_meta *kdbus_meta_new(void);
-struct kdbus_meta *kdbus_meta_ref(struct kdbus_meta *meta);
-struct kdbus_meta *kdbus_meta_unref(struct kdbus_meta *meta);
-
-void kdbus_meta_add_timestamp(struct kdbus_meta *meta, u64 seq);
-int kdbus_meta_add_current(struct kdbus_meta *meta, u64 which);
-int kdbus_meta_add_conn_info(struct kdbus_meta *meta,
- struct kdbus_conn *conn_src, u64 which);
-int kdbus_meta_add_fake(struct kdbus_meta *meta,
- const struct kdbus_creds *creds,
- const struct kdbus_pids *pids,
- const char *seclabel);
-struct kdbus_item *kdbus_meta_export(struct kdbus_meta *meta,
- u64 mask, size_t *sz);
+struct kdbus_meta_proc *kdbus_meta_proc_new(void);
+struct kdbus_meta_proc *kdbus_meta_proc_ref(struct kdbus_meta_proc *mp);
+struct kdbus_meta_proc *kdbus_meta_proc_unref(struct kdbus_meta_proc *mp);
+int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what);
+int kdbus_meta_proc_fake(struct kdbus_meta_proc *mp,
+ const struct kdbus_creds *creds,
+ const struct kdbus_pids *pids,
+ const char *seclabel);
+
+struct kdbus_meta_conn *kdbus_meta_conn_new(void);
+struct kdbus_meta_conn *kdbus_meta_conn_ref(struct kdbus_meta_conn *mc);
+struct kdbus_meta_conn *kdbus_meta_conn_unref(struct kdbus_meta_conn *mc);
+int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc,
+ struct kdbus_kmsg *kmsg,
+ struct kdbus_conn *conn,
+ u64 what);
+
+struct kdbus_item *kdbus_meta_export(struct kdbus_meta_proc *mp,
+ struct kdbus_meta_conn *mc,
+ u64 mask,
+ size_t *sz);
u64 kdbus_meta_calc_attach_flags(const struct kdbus_conn *sender,
const struct kdbus_conn *receiver);
diff --git a/notify.c b/notify.c
index 335679cc9b8..44bab30299d 100644
--- a/notify.c
+++ b/notify.c
@@ -205,7 +205,8 @@ void kdbus_notify_flush(struct kdbus_bus *bus)
list_for_each_entry_safe(kmsg, tmp, &notify_list, notify_entry) {
kmsg->seq = atomic64_inc_return(&bus->domain->msg_seq_last);
- kdbus_meta_add_timestamp(kmsg->meta, kmsg->seq);
+ kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, NULL,
+ KDBUS_ATTACH_TIMESTAMP);
if (kmsg->msg.dst_id != KDBUS_DST_ID_BROADCAST) {
struct kdbus_conn *conn;
diff --git a/queue.c b/queue.c
index 8f36dddde67..59ad0e246f4 100644
--- a/queue.c
+++ b/queue.c
@@ -212,7 +212,8 @@ struct kdbus_queue_entry *kdbus_queue_entry_alloc(struct kdbus_pool *pool,
INIT_LIST_HEAD(&entry->entry);
entry->msg_res = kdbus_msg_resources_ref(res);
- entry->meta = kdbus_meta_ref(kmsg->meta);
+ entry->proc_meta = kdbus_meta_proc_ref(kmsg->proc_meta);
+ entry->conn_meta = kdbus_meta_conn_ref(kmsg->conn_meta);
memcpy(&entry->msg, msg, sizeof(*msg));
if (kmsg->iov_count) {
@@ -384,10 +385,12 @@ int kdbus_queue_entry_install(struct kdbus_queue_entry *entry,
size_t kvec_count = 0;
int ret = 0;
- if (entry->meta) {
+ if (entry->proc_meta || entry->conn_meta) {
u64 attach_flags = atomic64_read(&conn_dst->attach_flags_recv);
- meta_items = kdbus_meta_export(entry->meta, attach_flags,
+ meta_items = kdbus_meta_export(entry->proc_meta,
+ entry->conn_meta,
+ attach_flags,
&meta_size);
if (IS_ERR(meta_items)) {
ret = PTR_ERR(meta_items);
@@ -483,7 +486,8 @@ int kdbus_queue_entry_move(struct kdbus_conn *conn_dst,
void kdbus_queue_entry_free(struct kdbus_queue_entry *entry)
{
kdbus_msg_resources_unref(entry->msg_res);
- kdbus_meta_unref(entry->meta);
+ kdbus_meta_conn_unref(entry->conn_meta);
+ kdbus_meta_proc_unref(entry->proc_meta);
kdbus_reply_unref(entry->reply);
kfree(entry->msg_extra);
kfree(entry);
diff --git a/queue.h b/queue.h
index d9d35ab92c2..e853c5c3a18 100644
--- a/queue.h
+++ b/queue.h
@@ -55,7 +55,8 @@ struct kdbus_queue {
* @fds_count: Number of elements in @fds_fp
* @dst_name_id: The sequence number of the name this message is
* addressed to, 0 for messages sent to an ID
- * @meta: Metadata, captured at message arrival
+ * @proc_meta: Process metadata, captured at message arrival
+ * @conn_meta: Connection metadata, captured at message arrival
* @reply: The reply block if a reply to this message is expected.
* @user: Index in per-user message counter, -1 for unused
*/
@@ -75,7 +76,8 @@ struct kdbus_queue_entry {
u64 dst_name_id;
struct kdbus_msg_resources *msg_res;
- struct kdbus_meta *meta;
+ struct kdbus_meta_proc *proc_meta;
+ struct kdbus_meta_conn *conn_meta;
struct kdbus_reply *reply;
struct kdbus_domain_user *user;
};