summaryrefslogtreecommitdiff
path: root/ipc/kdbus
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/kdbus')
-rw-r--r--ipc/kdbus/bus.h2
-rw-r--r--ipc/kdbus/connection.c39
-rw-r--r--ipc/kdbus/connection.h6
-rw-r--r--ipc/kdbus/endpoint.c28
-rw-r--r--ipc/kdbus/endpoint.h3
-rw-r--r--ipc/kdbus/handle.c30
-rw-r--r--ipc/kdbus/handle.h6
-rw-r--r--ipc/kdbus/message.c2
8 files changed, 75 insertions, 41 deletions
diff --git a/ipc/kdbus/bus.h b/ipc/kdbus/bus.h
index 238986eff..8c2acaed6 100644
--- a/ipc/kdbus/bus.h
+++ b/ipc/kdbus/bus.h
@@ -44,6 +44,7 @@ struct kdbus_user;
* @domain: Domain of this bus
* @creator: Creator of the bus
* @creator_meta: Meta information about the bus creator
+ * @last_message_id: Last used message id
* @policy_db: Policy database for this bus
* @name_registry: Name registry of this bus
* @conn_rwlock: Read/Write lock for all lists of child connections
@@ -67,6 +68,7 @@ struct kdbus_bus {
struct kdbus_meta_proc *creator_meta;
/* protected by own locks */
+ atomic64_t last_message_id;
struct kdbus_policy_db policy_db;
struct kdbus_name_registry *name_registry;
diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
index d94b417e0..aa3296ea4 100644
--- a/ipc/kdbus/connection.c
+++ b/ipc/kdbus/connection.c
@@ -52,7 +52,8 @@
#define KDBUS_CONN_ACTIVE_BIAS (INT_MIN + 2)
#define KDBUS_CONN_ACTIVE_NEW (INT_MIN + 1)
-static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged,
+static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep,
+ struct file *file,
struct kdbus_cmd_hello *hello,
const char *name,
const struct kdbus_creds *creds,
@@ -72,6 +73,8 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged,
bool is_policy_holder;
bool is_activator;
bool is_monitor;
+ bool privileged;
+ bool owner;
struct kvec kvec;
int ret;
@@ -81,6 +84,9 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged,
struct kdbus_bloom_parameter bloom;
} bloom_item;
+ privileged = kdbus_ep_is_privileged(ep, file);
+ owner = kdbus_ep_is_owner(ep, file);
+
is_monitor = hello->flags & KDBUS_HELLO_MONITOR;
is_activator = hello->flags & KDBUS_HELLO_ACTIVATOR;
is_policy_holder = hello->flags & KDBUS_HELLO_POLICY_HOLDER;
@@ -97,9 +103,9 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged,
return ERR_PTR(-EINVAL);
if (is_monitor && ep->user)
return ERR_PTR(-EOPNOTSUPP);
- if (!privileged && (is_activator || is_policy_holder || is_monitor))
+ if (!owner && (is_activator || is_policy_holder || is_monitor))
return ERR_PTR(-EPERM);
- if ((creds || pids || seclabel) && !privileged)
+ if (!owner && (creds || pids || seclabel))
return ERR_PTR(-EPERM);
ret = kdbus_sanitize_attach_flags(hello->attach_flags_send,
@@ -129,12 +135,13 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged,
atomic_set(&conn->request_count, 0);
atomic_set(&conn->lost_count, 0);
INIT_DELAYED_WORK(&conn->work, kdbus_reply_list_scan_work);
- conn->cred = get_current_cred();
+ conn->cred = get_cred(file->f_cred);
conn->pid = get_pid(task_pid(current));
get_fs_root(current->fs, &conn->root_path);
init_waitqueue_head(&conn->wait);
kdbus_queue_init(&conn->queue);
conn->privileged = privileged;
+ conn->owner = owner;
conn->ep = kdbus_ep_ref(ep);
conn->id = atomic64_inc_return(&bus->domain->last_id);
conn->flags = hello->flags;
@@ -214,11 +221,21 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged,
* Note that limits are always accounted against the real UID, not
* the effective UID (cred->user always points to the accounting of
* cred->uid, not cred->euid).
+ * In case the caller is privileged, we allow changing the accounting
+ * to the faked user.
*/
if (ep->user) {
conn->user = kdbus_user_ref(ep->user);
} else {
- conn->user = kdbus_user_lookup(ep->bus->domain, current_uid());
+ kuid_t uid;
+
+ if (conn->meta_fake && uid_valid(conn->meta_fake->uid) &&
+ conn->privileged)
+ uid = conn->meta_fake->uid;
+ else
+ uid = conn->cred->uid;
+
+ conn->user = kdbus_user_lookup(ep->bus->domain, uid);
if (IS_ERR(conn->user)) {
ret = PTR_ERR(conn->user);
conn->user = NULL;
@@ -1123,7 +1140,7 @@ static int kdbus_conn_reply(struct kdbus_conn *src,
mutex_unlock(&dst->lock);
if (!reply) {
- ret = -EPERM;
+ ret = -EBADSLT;
goto exit;
}
@@ -1418,7 +1435,7 @@ bool kdbus_conn_policy_own_name(struct kdbus_conn *conn,
return false;
}
- if (conn->privileged)
+ if (conn->owner)
return true;
res = kdbus_policy_query(&conn->ep->bus->policy_db, conn_creds,
@@ -1448,7 +1465,7 @@ bool kdbus_conn_policy_talk(struct kdbus_conn *conn,
to, KDBUS_POLICY_TALK))
return false;
- if (conn->privileged)
+ if (conn->owner)
return true;
if (uid_eq(conn_creds->euid, to->cred->uid))
return true;
@@ -1567,12 +1584,12 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn,
/**
* kdbus_cmd_hello() - handle KDBUS_CMD_HELLO
* @ep: Endpoint to operate on
- * @privileged: Whether the caller is privileged
+ * @file: File this connection is opened on
* @argp: Command payload
*
* Return: NULL or newly created connection on success, ERR_PTR on failure.
*/
-struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, bool privileged,
+struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, struct file *file,
void __user *argp)
{
struct kdbus_cmd_hello *cmd;
@@ -1607,7 +1624,7 @@ struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, bool privileged,
item_name = argv[1].item ? argv[1].item->str : NULL;
- c = kdbus_conn_new(ep, privileged, cmd, item_name,
+ c = kdbus_conn_new(ep, file, cmd, item_name,
argv[2].item ? &argv[2].item->creds : NULL,
argv[3].item ? &argv[3].item->pids : NULL,
argv[4].item ? argv[4].item->str : NULL,
diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h
index 5ee864eb0..8e0180ace 100644
--- a/ipc/kdbus/connection.h
+++ b/ipc/kdbus/connection.h
@@ -73,7 +73,8 @@ struct kdbus_staging;
* @activator_of: Well-known name entry this connection acts as an
* @names_list: List of well-known names
* @names_queue_list: Well-known names this connection waits for
- * @privileged: Whether this connection is privileged on the bus
+ * @privileged: Whether this connection is privileged on the domain
+ * @owner: Owned by the same user as the bus owner
*/
struct kdbus_conn {
struct kref kref;
@@ -116,6 +117,7 @@ struct kdbus_conn {
struct list_head names_queue_list;
bool privileged:1;
+ bool owner:1;
};
struct kdbus_conn *kdbus_conn_ref(struct kdbus_conn *conn);
@@ -154,7 +156,7 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn,
const struct kdbus_msg *msg);
/* command dispatcher */
-struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, bool privileged,
+struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, struct file *file,
void __user *argp);
int kdbus_cmd_byebye_unlocked(struct kdbus_conn *conn, void __user *argp);
int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp);
diff --git a/ipc/kdbus/endpoint.c b/ipc/kdbus/endpoint.c
index 977964dbb..44e7a20de 100644
--- a/ipc/kdbus/endpoint.c
+++ b/ipc/kdbus/endpoint.c
@@ -184,6 +184,34 @@ struct kdbus_ep *kdbus_ep_unref(struct kdbus_ep *ep)
}
/**
+ * kdbus_ep_is_privileged() - check whether a file is privileged
+ * @ep: endpoint to operate on
+ * @file: file to test
+ *
+ * Return: True if @file is privileged in the domain of @ep.
+ */
+bool kdbus_ep_is_privileged(struct kdbus_ep *ep, struct file *file)
+{
+ return !ep->user &&
+ file_ns_capable(file, ep->bus->domain->user_namespace,
+ CAP_IPC_OWNER);
+}
+
+/**
+ * kdbus_ep_is_owner() - check whether a file should be treated as bus owner
+ * @ep: endpoint to operate on
+ * @file: file to test
+ *
+ * Return: True if @file should be treated as bus owner on @ep
+ */
+bool kdbus_ep_is_owner(struct kdbus_ep *ep, struct file *file)
+{
+ return !ep->user &&
+ (uid_eq(file->f_cred->euid, ep->bus->node.uid) ||
+ kdbus_ep_is_privileged(ep, file));
+}
+
+/**
* kdbus_cmd_ep_make() - handle KDBUS_CMD_ENDPOINT_MAKE
* @bus: bus to operate on
* @argp: command payload
diff --git a/ipc/kdbus/endpoint.h b/ipc/kdbus/endpoint.h
index bc1b94a70..e0da59f01 100644
--- a/ipc/kdbus/endpoint.h
+++ b/ipc/kdbus/endpoint.h
@@ -61,6 +61,9 @@ struct kdbus_ep *kdbus_ep_new(struct kdbus_bus *bus, const char *name,
struct kdbus_ep *kdbus_ep_ref(struct kdbus_ep *ep);
struct kdbus_ep *kdbus_ep_unref(struct kdbus_ep *ep);
+bool kdbus_ep_is_privileged(struct kdbus_ep *ep, struct file *file);
+bool kdbus_ep_is_owner(struct kdbus_ep *ep, struct file *file);
+
struct kdbus_ep *kdbus_cmd_ep_make(struct kdbus_bus *bus, void __user *argp);
int kdbus_cmd_ep_update(struct kdbus_ep *ep, void __user *argp);
diff --git a/ipc/kdbus/handle.c b/ipc/kdbus/handle.c
index e0e06b0e1..fc60932d6 100644
--- a/ipc/kdbus/handle.c
+++ b/ipc/kdbus/handle.c
@@ -264,7 +264,6 @@ enum kdbus_handle_type {
* @bus_owner: bus this handle owns
* @ep_owner: endpoint this handle owns
* @conn: connection this handle owns
- * @privileged: Flag to mark a handle as privileged
*/
struct kdbus_handle {
struct mutex lock;
@@ -275,8 +274,6 @@ struct kdbus_handle {
struct kdbus_ep *ep_owner;
struct kdbus_conn *conn;
};
-
- bool privileged:1;
};
static int kdbus_handle_open(struct inode *inode, struct file *file)
@@ -298,23 +295,6 @@ static int kdbus_handle_open(struct inode *inode, struct file *file)
mutex_init(&handle->lock);
handle->type = KDBUS_HANDLE_NONE;
- if (node->type == KDBUS_NODE_ENDPOINT) {
- struct kdbus_ep *ep = kdbus_ep_from_node(node);
- struct kdbus_bus *bus = ep->bus;
-
- /*
- * A connection is privileged if it is opened on an endpoint
- * without custom policy and either:
- * * the user has CAP_IPC_OWNER in the domain user namespace
- * or
- * * the callers euid matches the uid of the bus creator
- */
- if (!ep->user &&
- (ns_capable(bus->domain->user_namespace, CAP_IPC_OWNER) ||
- uid_eq(file->f_cred->euid, bus->node.uid)))
- handle->privileged = true;
- }
-
file->private_data = handle;
ret = 0;
@@ -406,6 +386,7 @@ static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd,
struct kdbus_handle *handle = file->private_data;
struct kdbus_node *node = file_inode(file)->i_private;
struct kdbus_ep *ep, *file_ep = kdbus_ep_from_node(node);
+ struct kdbus_bus *bus = file_ep->bus;
struct kdbus_conn *conn;
int ret = 0;
@@ -413,14 +394,14 @@ static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd,
return -ESHUTDOWN;
switch (cmd) {
- case KDBUS_CMD_ENDPOINT_MAKE:
+ case KDBUS_CMD_ENDPOINT_MAKE: {
/* creating custom endpoints is a privileged operation */
- if (!handle->privileged) {
+ if (!kdbus_ep_is_owner(file_ep, file)) {
ret = -EPERM;
break;
}
- ep = kdbus_cmd_ep_make(file_ep->bus, buf);
+ ep = kdbus_cmd_ep_make(bus, buf);
if (IS_ERR_OR_NULL(ep)) {
ret = PTR_ERR_OR_ZERO(ep);
break;
@@ -429,9 +410,10 @@ static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd,
handle->ep_owner = ep;
ret = KDBUS_HANDLE_EP_OWNER;
break;
+ }
case KDBUS_CMD_HELLO:
- conn = kdbus_cmd_hello(file_ep, handle->privileged, buf);
+ conn = kdbus_cmd_hello(file_ep, file, buf);
if (IS_ERR_OR_NULL(conn)) {
ret = PTR_ERR_OR_ZERO(conn);
break;
diff --git a/ipc/kdbus/handle.h b/ipc/kdbus/handle.h
index 8a36c0595..5dde2c10b 100644
--- a/ipc/kdbus/handle.h
+++ b/ipc/kdbus/handle.h
@@ -45,7 +45,7 @@ struct kdbus_arg {
* @argv: array of items this command supports
* @user: set by parser to user-space location of current command
* @cmd: set by parser to kernel copy of command payload
- * @cmd_buf: 512 bytes inline buf to avoid kmalloc() on small cmds
+ * @cmd_buf: inline buf to avoid kmalloc() on small cmds
* @items: points to item array in @cmd
* @items_size: size of @items in bytes
* @is_cmd: whether this is a command-payload or msg-payload
@@ -55,7 +55,7 @@ struct kdbus_arg {
* the object to kdbus_args_parse(). The parser will copy the command payload
* into kernel-space and verify the correctness of the data.
*
- * We use a 512 bytes buffer for small command payloads, to be allocated on
+ * We use a 256 bytes buffer for small command payloads, to be allocated on
* stack on syscall entrance.
*/
struct kdbus_args {
@@ -65,7 +65,7 @@ struct kdbus_args {
struct kdbus_cmd __user *user;
struct kdbus_cmd *cmd;
- u8 cmd_buf[512];
+ u8 cmd_buf[256];
struct kdbus_item *items;
size_t items_size;
diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c
index 432dba4dc..ae565cd34 100644
--- a/ipc/kdbus/message.c
+++ b/ipc/kdbus/message.c
@@ -671,7 +671,7 @@ static struct kdbus_staging *kdbus_staging_new(struct kdbus_bus *bus,
if (!staging)
return ERR_PTR(-ENOMEM);
- staging->msg_seqnum = atomic64_inc_return(&bus->domain->last_id);
+ staging->msg_seqnum = atomic64_inc_return(&bus->last_message_id);
staging->n_parts = 0; /* we reserve n_parts, but don't enforce them */
staging->parts = (void *)(staging + 1);