Update to latest upstream kdbus

Commit 917ee9c62522
This commit is contained in:
Josh Boyer 2015-08-06 14:39:08 -04:00
parent c3a77ea556
commit 2d19b299b6
1 changed files with 766 additions and 0 deletions

View File

@ -49186,3 +49186,769 @@ index 27a5021fe70f..432dba4dcfdc 100644
--
2.4.3
From 12000cd279ab5502006441c406ceba5bde44be71 Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
Date: Thu, 6 Aug 2015 10:21:20 +0200
Subject: [PATCH 1/9] kdbus: return EBADSLT on replies without slot
If you send a reply without an active reply slot, we used to return EPERM.
However, this makes it impossible to distinguish this case from a real
permission-denied error (eg., LSM). Hence, make sure we return a unique
error-code if the reply-slot is missing.
With this patch, you get EBADSLT ("Invalid slot") if you call
KDBUS_CMD_SEND with a reply-cookie that has no valid slot.
Reviewed-by: Daniel Mack <daniel@zonque.org>
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
ipc/kdbus/connection.c | 2 +-
tools/testing/selftests/kdbus/test-message.c | 2 +-
tools/testing/selftests/kdbus/test-sync.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
index d94b417e0f32..2787bd7d00c1 100644
--- a/ipc/kdbus/connection.c
+++ b/ipc/kdbus/connection.c
@@ -1123,7 +1123,7 @@ static int kdbus_conn_reply(struct kdbus_conn *src,
mutex_unlock(&dst->lock);
if (!reply) {
- ret = -EPERM;
+ ret = -EBADSLT;
goto exit;
}
diff --git a/tools/testing/selftests/kdbus/test-message.c b/tools/testing/selftests/kdbus/test-message.c
index ddc1e0af877b..563dc859077a 100644
--- a/tools/testing/selftests/kdbus/test-message.c
+++ b/tools/testing/selftests/kdbus/test-message.c
@@ -75,7 +75,7 @@ int kdbus_test_message_basic(struct kdbus_test_env *env)
/* Faked replies with a valid reply cookie are rejected */
ret = kdbus_msg_send_reply(conn, time(NULL) ^ cookie, sender->id);
- ASSERT_RETURN(ret == -EPERM);
+ ASSERT_RETURN(ret == -EBADSLT);
ret = kdbus_free(conn, offset);
ASSERT_RETURN(ret == 0);
diff --git a/tools/testing/selftests/kdbus/test-sync.c b/tools/testing/selftests/kdbus/test-sync.c
index e2be910d2ece..0655a545fbf1 100644
--- a/tools/testing/selftests/kdbus/test-sync.c
+++ b/tools/testing/selftests/kdbus/test-sync.c
@@ -235,7 +235,7 @@ static void *run_thread_reply(void *data)
/* using an unknown cookie must fail */
ret = kdbus_msg_send_reply(conn_a, ~cookie, conn_b->id);
- if (ret != -EPERM) {
+ if (ret != -EBADSLT) {
status = TEST_ERR;
goto exit_thread;
}
--
2.4.3
From 2fee35fd480b2387e1f148fdc2125cc93708501b Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
Date: Thu, 6 Aug 2015 10:21:21 +0200
Subject: [PATCH 2/9] kdbus: reduce stack buffer to 256 bytes
This reduces the stack-buffer for small ioctl payloads to 256 bytes. As
seen during real workloads, this is more than enough. And we really
should reduce stack pressure. Hence, lets limit the stack buffers to 256
bytes.
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Reviewed-by: Daniel Mack <daniel@zonque.org>
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
ipc/kdbus/handle.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/ipc/kdbus/handle.h b/ipc/kdbus/handle.h
index 8a36c0595091..5dde2c10bed4 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;
--
2.4.3
From cff26ca42ae55286f5b8366302812d16bbc4a90a Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
Date: Thu, 6 Aug 2015 10:21:22 +0200
Subject: [PATCH 3/9] kdbus: use separate counter for message IDs
For each kdbus domain, we maintain an ID-counter to guarantee unique IDs
across all objects. We also used to use it for message IDs. However, this
requires touching a shared cacheline on each message transaction, even
though we never guaranteed global ordering across buses, anyway.
Introduce a separate counter which is used solely for message IDs.
Semantics stay the same, but it no longer relates to IDs across buses.
Reviewed-by: Daniel Mack <daniel@zonque.org>
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
ipc/kdbus/bus.h | 2 ++
ipc/kdbus/message.c | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/ipc/kdbus/bus.h b/ipc/kdbus/bus.h
index 238986eff92f..8c2acaed6258 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/message.c b/ipc/kdbus/message.c
index 432dba4dcfdc..ae565cd343f8 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);
--
2.4.3
From 41c64712fef883818dadd5796f7522f675931d16 Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
Date: Thu, 6 Aug 2015 10:21:23 +0200
Subject: [PATCH 4/9] kdbus: move privilege checking in kdbus_conn_new()
Instead of relying on handle.c to perform privilege evaluation and
passing information along, move this into kdbus_conn_new(). This has the
benefit that we can now split 'owner' level and 'privileged' levels
apart. This will be required for following extensions that need to
distinguish both cases.
Also, pass on 'struct file*' from handle into kdbus_conn_new(). Most
kernel helpers cannot accept 'struct cred*' but instead only operate on
files (and access file->f_cred then).
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
ipc/kdbus/connection.c | 41 ++++++++++++++++++++++++++++++++---------
ipc/kdbus/connection.h | 6 ++++--
ipc/kdbus/handle.c | 2 +-
3 files changed, 37 insertions(+), 12 deletions(-)
diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
index 2787bd7d00c1..243cbc77624e 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,25 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged,
struct kdbus_bloom_parameter bloom;
} bloom_item;
+ /*
+ * A connection is considered privileged, if, and only if, it didn't
+ * connect through a custom endpoint *and* it has CAP_IPC_OWNER on the
+ * namespace of the current domain.
+ * Additionally, a connection is considered equivalent to the bus owner
+ * if it didn't connect through a custom endpoint *and* it either is
+ * privileged or the same user as the bus owner.
+ *
+ * Bus owners and alike can bypass bus policies. Privileged connections
+ * can additionally change accounting, modify kernel resources and
+ * perform restricted operations, as long as they're privileged on the
+ * same level as the resources they touch.
+ */
+ privileged = !ep->user &&
+ file_ns_capable(file, ep->bus->domain->user_namespace,
+ CAP_IPC_OWNER);
+ owner = !ep->user &&
+ (privileged || uid_eq(file->f_cred->euid, ep->bus->node.uid));
+
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 +119,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 +151,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;
@@ -1418,7 +1441,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 +1471,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 +1590,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 +1630,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 5ee864eb0e41..8e0180ace3f6 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/handle.c b/ipc/kdbus/handle.c
index e0e06b0e1114..a93c385c6280 100644
--- a/ipc/kdbus/handle.c
+++ b/ipc/kdbus/handle.c
@@ -431,7 +431,7 @@ static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd,
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;
--
2.4.3
From 1cd893dae99f8169c0f0620f343e3ee2379d0d28 Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
Date: Thu, 6 Aug 2015 10:21:24 +0200
Subject: [PATCH 5/9] kdbus: perform accounting on proxied uids
If a connection proxies a uid, we should make sure to perform accounting
on that passed uid. Otherwise, limits will be shared across all proxied
users (or we'd require the proxy to run setuid() and thus require
CAP_SETUID).
However, this is only allowed if the proxy is privileged on the bus. That
is, it must have CAP_IPC_ADMIN on the domain and the passed uid must be
mapped in that domain.
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
ipc/kdbus/connection.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
index 243cbc77624e..c81888ed1138 100644
--- a/ipc/kdbus/connection.c
+++ b/ipc/kdbus/connection.c
@@ -237,11 +237,21 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep,
* 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;
--
2.4.3
From 9dad3c87e273ac8e895ec86252bd79792d49da77 Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
Date: Thu, 6 Aug 2015 10:21:25 +0200
Subject: [PATCH 6/9] kdbus: inline privilege checks
Instead of caching privilege information in 'kdbus_handle' (and thus
increasing the size of each handle by 8 byte), perform privilege checks
on the cached creds in file->f_cred inline. None of the functions that
need those checks is a fast path (in fact, it's just EP_MAKE that needs
it right now), so there's no need to cache the data.
If more functions need this check later on, we should turn it into a
small static helper.
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
ipc/kdbus/handle.c | 34 +++++++++++-----------------------
1 file changed, 11 insertions(+), 23 deletions(-)
diff --git a/ipc/kdbus/handle.c b/ipc/kdbus/handle.c
index a93c385c6280..4d41ecf9cc7d 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,20 @@ 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: {
+ bool priv;
+
+ priv = uid_eq(file->f_cred->euid, bus->node.uid) ||
+ file_ns_capable(file, bus->domain->user_namespace,
+ CAP_IPC_OWNER);
+
/* creating custom endpoints is a privileged operation */
- if (!handle->privileged) {
+ if (file_ep->user || !priv) {
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,6 +416,7 @@ 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, file, buf);
--
2.4.3
From c4bf3679fb862abfc7064c975a5782cdb2a01c9e Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
Date: Thu, 6 Aug 2015 10:21:26 +0200
Subject: [PATCH 7/9] kdbus: consolidate common code
Move the file-credential checkers into kdbus_ep_*() helper functions to
avoid hard-coding the same behavior in multiple places.
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
ipc/kdbus/connection.c | 20 ++------------------
ipc/kdbus/endpoint.c | 28 ++++++++++++++++++++++++++++
ipc/kdbus/endpoint.h | 3 +++
ipc/kdbus/handle.c | 8 +-------
4 files changed, 34 insertions(+), 25 deletions(-)
diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
index c81888ed1138..aa3296ea4f93 100644
--- a/ipc/kdbus/connection.c
+++ b/ipc/kdbus/connection.c
@@ -84,24 +84,8 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep,
struct kdbus_bloom_parameter bloom;
} bloom_item;
- /*
- * A connection is considered privileged, if, and only if, it didn't
- * connect through a custom endpoint *and* it has CAP_IPC_OWNER on the
- * namespace of the current domain.
- * Additionally, a connection is considered equivalent to the bus owner
- * if it didn't connect through a custom endpoint *and* it either is
- * privileged or the same user as the bus owner.
- *
- * Bus owners and alike can bypass bus policies. Privileged connections
- * can additionally change accounting, modify kernel resources and
- * perform restricted operations, as long as they're privileged on the
- * same level as the resources they touch.
- */
- privileged = !ep->user &&
- file_ns_capable(file, ep->bus->domain->user_namespace,
- CAP_IPC_OWNER);
- owner = !ep->user &&
- (privileged || uid_eq(file->f_cred->euid, ep->bus->node.uid));
+ 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;
diff --git a/ipc/kdbus/endpoint.c b/ipc/kdbus/endpoint.c
index 977964dbb44a..44e7a20de9c2 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 bc1b94a70f93..e0da59f01a7a 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 4d41ecf9cc7d..fc60932d69c7 100644
--- a/ipc/kdbus/handle.c
+++ b/ipc/kdbus/handle.c
@@ -395,14 +395,8 @@ static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd,
switch (cmd) {
case KDBUS_CMD_ENDPOINT_MAKE: {
- bool priv;
-
- priv = uid_eq(file->f_cred->euid, bus->node.uid) ||
- file_ns_capable(file, bus->domain->user_namespace,
- CAP_IPC_OWNER);
-
/* creating custom endpoints is a privileged operation */
- if (file_ep->user || !priv) {
+ if (!kdbus_ep_is_owner(file_ep, file)) {
ret = -EPERM;
break;
}
--
2.4.3
From 146f50d92e16b684da73ecbb290d980babe98366 Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
Date: Thu, 6 Aug 2015 10:21:27 +0200
Subject: [PATCH 8/9] kdbus/samples: skip if __NR_memfd_create is not defined
We require __NR_memfd_create for the kdbus samples. Make sure we skip
compilation if the target architecture and kernel do not support memfds.
Reported-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Reviewed-by: Daniel Mack <daniel@zonque.org>
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
samples/kdbus/kdbus-workers.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/samples/kdbus/kdbus-workers.c b/samples/kdbus/kdbus-workers.c
index c3ba958639f3..5a6dfdce3bfd 100644
--- a/samples/kdbus/kdbus-workers.c
+++ b/samples/kdbus/kdbus-workers.c
@@ -59,9 +59,11 @@
#include <stdio.h>
#include <stdlib.h>
+#include <sys/syscall.h>
/* glibc < 2.7 does not ship sys/signalfd.h */
-#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 7
+/* we require kernels with __NR_memfd_create */
+#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 7 && defined(__NR_memfd_create)
#include <ctype.h>
#include <errno.h>
@@ -75,7 +77,6 @@
#include <sys/mman.h>
#include <sys/poll.h>
#include <sys/signalfd.h>
-#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <time.h>
--
2.4.3
From 917ee9c6252234fdb8e08670d3c31b6cef18e902 Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
Date: Thu, 6 Aug 2015 10:21:28 +0200
Subject: [PATCH 9/9] kdbus/tests: properly parse KDBUS_CMD_LIST objects
There is no reason to assume the information returned by KDBUS_CMD_LIST
contains only a single KDBUS_ITEM_OWNED_NAME. Parse each of them properly
and don't bail out early.
Reviewed-by: Daniel Mack <daniel@zonque.org>
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
tools/testing/selftests/kdbus/kdbus-util.c | 9 +++++----
tools/testing/selftests/kdbus/test-names.c | 17 +++++++++++------
2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/tools/testing/selftests/kdbus/kdbus-util.c b/tools/testing/selftests/kdbus/kdbus-util.c
index a5e54ca3a492..82fa89b1a881 100644
--- a/tools/testing/selftests/kdbus/kdbus-util.c
+++ b/tools/testing/selftests/kdbus/kdbus-util.c
@@ -1155,11 +1155,12 @@ int kdbus_list(struct kdbus_conn *conn, uint64_t flags)
if (item->type == KDBUS_ITEM_OWNED_NAME) {
n = item->name.name;
flags = item->name.flags;
- }
- kdbus_printf("%8llu flags=0x%08llx conn=0x%08llx '%s'\n",
- name->id, (unsigned long long) flags,
- name->flags, n);
+ kdbus_printf("%8llu flags=0x%08llx conn=0x%08llx '%s'\n",
+ name->id,
+ (unsigned long long) flags,
+ name->flags, n);
+ }
}
kdbus_printf("\n");
diff --git a/tools/testing/selftests/kdbus/test-names.c b/tools/testing/selftests/kdbus/test-names.c
index 66ebb47370eb..fd4ac5adc6d2 100644
--- a/tools/testing/selftests/kdbus/test-names.c
+++ b/tools/testing/selftests/kdbus/test-names.c
@@ -35,15 +35,20 @@ static int conn_is_name_owner(const struct kdbus_conn *conn,
struct kdbus_item *item;
const char *n = NULL;
- KDBUS_ITEM_FOREACH(item, name, items)
- if (item->type == KDBUS_ITEM_OWNED_NAME)
+ KDBUS_ITEM_FOREACH(item, name, items) {
+ if (item->type == KDBUS_ITEM_OWNED_NAME) {
n = item->name.name;
- if (name->id == conn->id &&
- n && strcmp(needle, n) == 0) {
- found = true;
- break;
+ if (name->id == conn->id &&
+ n && strcmp(needle, n) == 0) {
+ found = true;
+ break;
+ }
+ }
}
+
+ if (found)
+ break;
}
ret = kdbus_free(conn, cmd_list.offset);
--
2.4.3