[PATCH 05/14] kdbus: add connection, queue handling and message validation code
From: Daniel Mack This patch adds code to create and destroy connections, to validate incoming messages and to maintain the queue of messages that are associated with a connection. Note that connection and queue have a 1:1 relation, the code is only split in two parts for cleaner separation and better readability. Signed-off-by: Daniel Mack Signed-off-by: David Herrmann Signed-off-by: Djalal Harouni Signed-off-by: Greg Kroah-Hartman --- ipc/kdbus/connection.c | 2215 ipc/kdbus/connection.h | 257 ++ ipc/kdbus/item.c | 339 ipc/kdbus/item.h | 64 ++ ipc/kdbus/message.c| 616 ++ ipc/kdbus/message.h| 133 +++ ipc/kdbus/queue.c | 678 +++ ipc/kdbus/queue.h | 92 ++ ipc/kdbus/reply.c | 259 ++ ipc/kdbus/reply.h | 68 ++ ipc/kdbus/util.h |2 +- 11 files changed, 4722 insertions(+), 1 deletion(-) create mode 100644 ipc/kdbus/connection.c create mode 100644 ipc/kdbus/connection.h create mode 100644 ipc/kdbus/item.c create mode 100644 ipc/kdbus/item.h create mode 100644 ipc/kdbus/message.c create mode 100644 ipc/kdbus/message.h create mode 100644 ipc/kdbus/queue.c create mode 100644 ipc/kdbus/queue.h create mode 100644 ipc/kdbus/reply.c create mode 100644 ipc/kdbus/reply.h diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c new file mode 100644 index ..e554f1a71aa1 --- /dev/null +++ b/ipc/kdbus/connection.c @@ -0,0 +1,2215 @@ +/* + * Copyright (C) 2013-2015 Kay Sievers + * Copyright (C) 2013-2015 Greg Kroah-Hartman + * Copyright (C) 2013-2015 Daniel Mack + * Copyright (C) 2013-2015 David Herrmann + * Copyright (C) 2013-2015 Linux Foundation + * Copyright (C) 2014-2015 Djalal Harouni + * + * kdbus is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bus.h" +#include "connection.h" +#include "endpoint.h" +#include "handle.h" +#include "match.h" +#include "message.h" +#include "metadata.h" +#include "names.h" +#include "domain.h" +#include "item.h" +#include "notify.h" +#include "policy.h" +#include "pool.h" +#include "reply.h" +#include "util.h" +#include "queue.h" + +#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, +struct kdbus_cmd_hello *hello, +const char *name, +const struct kdbus_creds *creds, +const struct kdbus_pids *pids, +const char *seclabel, +const char *conn_description) +{ +#ifdef CONFIG_DEBUG_LOCK_ALLOC + static struct lock_class_key __key; +#endif + struct kdbus_pool_slice *slice = NULL; + struct kdbus_bus *bus = ep->bus; + struct kdbus_conn *conn; + u64 attach_flags_send; + u64 attach_flags_recv; + u64 items_size = 0; + bool is_policy_holder; + bool is_activator; + bool is_monitor; + struct kvec kvec; + int ret; + + struct { + u64 size; + u64 type; + struct kdbus_bloom_parameter bloom; + } bloom_item; + + is_monitor = hello->flags & KDBUS_HELLO_MONITOR; + is_activator = hello->flags & KDBUS_HELLO_ACTIVATOR; + is_policy_holder = hello->flags & KDBUS_HELLO_POLICY_HOLDER; + + if (!hello->pool_size || !IS_ALIGNED(hello->pool_size, PAGE_SIZE)) + return ERR_PTR(-EINVAL); + if (is_monitor + is_activator + is_policy_holder > 1) + return ERR_PTR(-EINVAL); + if (name && !is_activator && !is_policy_holder) + return ERR_PTR(-EINVAL); + if (!name && (is_activator || is_policy_holder)) + return ERR_PTR(-EINVAL); + if (name && !kdbus_name_is_valid(name, true)) + return ERR_PTR(-EINVAL); + if (is_monitor && ep->user) + return ERR_PTR(-EOPNOTSUPP); + if (!privileged && (is_activator || is_policy_holder || is_monitor)) + return ERR_PTR(-EPERM); + if ((creds || pids || seclabel) && !privileged) + return ERR_PTR(-EPERM); + + ret = kdbus_sanitize_attach_flags(hello->attach_flags_send, + &attach_flags_send); + if (ret < 0) + return ERR_PTR(ret); + + ret = kdbus_sanitize_attach_flags(hell
[PATCH 05/13] kdbus: add connection, queue handling and message validation code
From: Daniel Mack This patch adds code to create and destroy connections, to validate incoming messages and to maintain the queue of messages that are associated with a connection. Note that connection and queue have a 1:1 relation, the code is only split in two parts for cleaner separation and better readability. Signed-off-by: Daniel Mack Signed-off-by: David Herrmann Signed-off-by: Djalal Harouni Signed-off-by: Greg Kroah-Hartman --- ipc/kdbus/connection.c | 2004 ipc/kdbus/connection.h | 262 +++ ipc/kdbus/item.c | 309 ipc/kdbus/item.h | 57 ++ ipc/kdbus/message.c| 598 +++ ipc/kdbus/message.h| 133 ipc/kdbus/queue.c | 505 ipc/kdbus/queue.h | 108 +++ ipc/kdbus/reply.c | 262 +++ ipc/kdbus/reply.h | 68 ++ ipc/kdbus/util.h |2 +- 11 files changed, 4307 insertions(+), 1 deletion(-) create mode 100644 ipc/kdbus/connection.c create mode 100644 ipc/kdbus/connection.h create mode 100644 ipc/kdbus/item.c create mode 100644 ipc/kdbus/item.h create mode 100644 ipc/kdbus/message.c create mode 100644 ipc/kdbus/message.h create mode 100644 ipc/kdbus/queue.c create mode 100644 ipc/kdbus/queue.h create mode 100644 ipc/kdbus/reply.c create mode 100644 ipc/kdbus/reply.h diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c new file mode 100644 index ..75e2ea161a0e --- /dev/null +++ b/ipc/kdbus/connection.c @@ -0,0 +1,2004 @@ +/* + * Copyright (C) 2013-2014 Kay Sievers + * Copyright (C) 2013-2014 Greg Kroah-Hartman + * Copyright (C) 2013-2014 Daniel Mack + * Copyright (C) 2013-2014 David Herrmann + * Copyright (C) 2013-2014 Linux Foundation + * Copyright (C) 2014 Djalal Harouni + * + * kdbus is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bus.h" +#include "connection.h" +#include "endpoint.h" +#include "match.h" +#include "message.h" +#include "metadata.h" +#include "names.h" +#include "domain.h" +#include "item.h" +#include "notify.h" +#include "policy.h" +#include "pool.h" +#include "reply.h" +#include "util.h" +#include "queue.h" + +#define KDBUS_CONN_ACTIVE_BIAS (INT_MIN + 2) +#define KDBUS_CONN_ACTIVE_NEW (INT_MIN + 1) + +/* + * Check for maximum number of messages per individual user. This + * should prevent a single user from being able to fill the receiver's + * queue. + */ +static int kdbus_conn_queue_user_quota(const struct kdbus_conn *conn_src, + struct kdbus_conn *conn_dst, + struct kdbus_queue_entry *entry) +{ + struct kdbus_domain_user *user; + + /* +* When the kernel is the sender we do not do per user +* accouting, instead we just count how many messages have +* been queued and we check the quota limit when inserting +* message into the receiver queue. +*/ + if (!conn_src) + return 0; + + /* +* Per-user accounting can be expensive if we have many different +* users on the bus. Allow one set of messages to pass through +* un-accounted. Only once we hit that limit, we start accounting. +*/ + if (conn_dst->queue.msg_count < KDBUS_CONN_MAX_MSGS_UNACCOUNTED) + return 0; + + user = conn_src->user; + + /* extend array to store the user message counters */ + if (user->idr >= conn_dst->msg_users_max) { + unsigned int *users; + unsigned int i; + + i = 8 + KDBUS_ALIGN8(user->idr); + users = krealloc(conn_dst->msg_users, i * sizeof(unsigned int), +GFP_KERNEL | __GFP_ZERO); + if (!users) + return -ENOMEM; + + conn_dst->msg_users = users; + conn_dst->msg_users_max = i; + } + + if (conn_dst->msg_users[user->idr] >= KDBUS_CONN_MAX_MSGS_PER_USER) + return -ENOBUFS; + + conn_dst->msg_users[user->idr]++; + entry->user = kdbus_domain_user_ref(user); + return 0; +} + +/** + * kdbus_cmd_msg_recv() - receive a message from the queue + * @conn: Connection to work on + * @recv: The command as passed in by the ioctl + * + * Return: 0 on success, negative errno on failure + */ +int kdbus_cmd_msg_recv(struct kdbus_conn *conn, + struct kdbus_cmd_recv *recv) +{ + bool install = !(recv->flags & KDBUS_RECV_PEEK); + struct kdbus_queue_entry *entry
kdbus: add connection, queue handling and message validation code
From: Daniel Mack This patch adds code to create and destroy connections, to validate incoming messages and to maintain the queue of messages that are associated with a connection. Note that connection and queue have a 1:1 relation, the code is only split in two parts for cleaner separation and better readability. Signed-off-by: Daniel Mack Signed-off-by: David Herrmann Signed-off-by: Djalal Harouni Signed-off-by: Greg Kroah-Hartman --- ipc/kdbus/connection.c | 1838 ipc/kdbus/connection.h | 188 + ipc/kdbus/item.c | 258 +++ ipc/kdbus/item.h | 41 ++ ipc/kdbus/message.c| 444 ipc/kdbus/message.h| 75 ++ ipc/kdbus/queue.c | 608 ipc/kdbus/queue.h | 93 +++ ipc/kdbus/util.h |2 +- 9 files changed, 3546 insertions(+), 1 deletion(-) create mode 100644 ipc/kdbus/connection.c create mode 100644 ipc/kdbus/connection.h create mode 100644 ipc/kdbus/item.c create mode 100644 ipc/kdbus/item.h create mode 100644 ipc/kdbus/message.c create mode 100644 ipc/kdbus/message.h create mode 100644 ipc/kdbus/queue.c create mode 100644 ipc/kdbus/queue.h diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c new file mode 100644 index ..73d149eecc25 --- /dev/null +++ b/ipc/kdbus/connection.c @@ -0,0 +1,1838 @@ +/* + * Copyright (C) 2013-2014 Kay Sievers + * Copyright (C) 2013-2014 Greg Kroah-Hartman + * Copyright (C) 2013-2014 Daniel Mack + * Copyright (C) 2013-2014 David Herrmann + * Copyright (C) 2013-2014 Linux Foundation + * Copyright (C) 2014 Djalal Harouni + * + * kdbus is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bus.h" +#include "connection.h" +#include "endpoint.h" +#include "match.h" +#include "message.h" +#include "metadata.h" +#include "names.h" +#include "domain.h" +#include "item.h" +#include "notify.h" +#include "policy.h" +#include "util.h" +#include "queue.h" + +#define KDBUS_CONN_ACTIVE_BIAS (INT_MIN + 1) + +/** + * struct kdbus_conn_reply - an entry of kdbus_conn's list of replies + * @kref: Ref-count of this object + * @entry: The entry of the connection's reply_list + * @reply_dst: The connection the reply will be sent to (method origin) + * @queue_entry: The queue enty item that is prepared by the replying + * connection + * @deadline_ns: The deadline of the reply, in nanoseconds + * @cookie:The cookie of the requesting message + * @name_id: ID of the well-known name the original msg was sent to + * @sync: The reply block is waiting for synchronous I/O + * @waiting: The condition to synchronously wait for + * @interrupted: The sync reply was left in an interrupted state + * @err: The error code for the synchronous reply + */ +struct kdbus_conn_reply { + struct kref kref; + struct list_head entry; + struct kdbus_conn *reply_dst; + struct kdbus_queue_entry *queue_entry; + u64 deadline_ns; + u64 cookie; + u64 name_id; + bool sync:1; + bool waiting:1; + bool interrupted:1; + int err; +}; + +static struct kdbus_conn_reply * +kdbus_conn_reply_new(struct kdbus_conn *reply_dst, +const struct kdbus_msg *msg, +struct kdbus_name_entry *name_entry) +{ + bool sync = msg->flags & KDBUS_MSG_FLAGS_SYNC_REPLY; + struct kdbus_conn_reply *r; + int ret = 0; + + if (atomic_inc_return(&reply_dst->reply_count) > + KDBUS_CONN_MAX_REQUESTS_PENDING) { + ret = -EMLINK; + goto exit_dec_reply_count; + } + + r = kzalloc(sizeof(*r), GFP_KERNEL); + if (!r) { + ret = -ENOMEM; + goto exit_dec_reply_count; + } + + kref_init(&r->kref); + r->reply_dst = kdbus_conn_ref(reply_dst); + r->cookie = msg->cookie; + r->name_id = name_entry ? name_entry->name_id : 0; + r->deadline_ns = msg->timeout_ns; + + if (sync) { + r->sync = true; + r->waiting = true; + } + +exit_dec_reply_count: + if (ret < 0) { + atomic_dec(&reply_dst->reply_count); + return ERR_PTR(ret); + } + + return r; +} + +static void __kdbus_conn_reply_free(struct kref *kref) +{ + struct kdbus_conn_reply *reply = + container_of(kref, struct kdbus_conn_reply, kref); + + atomic_dec(&reply->reply_dst->reply_count); + kdbus_conn_unref(reply
Re: kdbus: add connection, queue handling and message validation code
On Wed, Oct 29, 2014 at 08:55:58PM -0700, Andy Lutomirski wrote: > On Wed, Oct 29, 2014 at 8:47 PM, Eric W. Biederman > wrote: > > Greg Kroah-Hartman writes: > > > >> From: Daniel Mack > >> > >> This patch adds code to create and destroy connections, to validate > >> incoming messages and to maintain the queue of messages that are > >> associated with a connection. > >> > >> Note that connection and queue have a 1:1 relation, the code is only > >> split in two parts for cleaner separation and better readability. > > > > You are not performing capability checks at open time. > > > > As such this API is suceptible to a host of file descriptor passing attacks. > > To be fair, write(2) doesn't work on these fds, so the usual attacks > don't work. But who knows what absurd things kdbus clients will do > with fd passing? Yes, we use ioctl() so we are safe here! if there is a a suid process that does perform arbitrary ioctl() on intrusted passed fds, then we are already in truble given all the already available ioctl() (not only kdbus, all available ioctl()... we blame the client), so yes usual write()/read() do not work here. But we do perform the creds check against the cred of connection creation time, if you open the fd you do not have the connection, you still need a KDBUS_CMD_HELLO ioctl() on the fd, and during that time we store the creds, and we perform all the TALK, SEE and OWN against those creds (uid/gid). It is like a second connect() call, unless you perform the KDBUS_CMD_HELLO you are not connected, and after turning your fd to a connection, a service can restrict its access (TALK, OWN and SEE) policies, not all connected peers can TALK (send messages) to a service. -- Djalal Harouni http://opendz.org -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: kdbus: add connection, queue handling and message validation code
On Wed, Oct 29, 2014 at 8:47 PM, Eric W. Biederman wrote: > Greg Kroah-Hartman writes: > >> From: Daniel Mack >> >> This patch adds code to create and destroy connections, to validate >> incoming messages and to maintain the queue of messages that are >> associated with a connection. >> >> Note that connection and queue have a 1:1 relation, the code is only >> split in two parts for cleaner separation and better readability. > > You are not performing capability checks at open time. > > As such this API is suceptible to a host of file descriptor passing attacks. To be fair, write(2) doesn't work on these fds, so the usual attacks don't work. But who knows what absurd things kdbus clients will do with fd passing? --Andy > >> Signed-off-by: Daniel Mack >> Signed-off-by: Greg Kroah-Hartman >> --- > >> +/* >> + * Check for maximum number of messages per individual user. This >> + * should prevent a single user from being able to fill the receiver's >> + * queue. >> + */ >> +static int kdbus_conn_queue_user_quota(struct kdbus_conn *conn, >> +const struct kdbus_conn *conn_src, >> +struct kdbus_queue_entry *entry) >> +{ >> + unsigned int user; >> + >> + if (!conn_src) >> + return 0; >> + >> + if (ns_capable(&init_user_ns, CAP_IPC_OWNER)) >> + return 0; > > -- Andy Lutomirski AMA Capital Management, LLC -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
kdbus: add connection, queue handling and message validation code
From: Daniel Mack This patch adds code to create and destroy connections, to validate incoming messages and to maintain the queue of messages that are associated with a connection. Note that connection and queue have a 1:1 relation, the code is only split in two parts for cleaner separation and better readability. Signed-off-by: Daniel Mack Signed-off-by: Greg Kroah-Hartman --- drivers/misc/kdbus/connection.c | 1751 +++ drivers/misc/kdbus/connection.h | 177 drivers/misc/kdbus/item.c | 256 ++ drivers/misc/kdbus/item.h | 40 + drivers/misc/kdbus/message.c| 420 ++ drivers/misc/kdbus/message.h| 72 ++ drivers/misc/kdbus/queue.c | 602 ++ drivers/misc/kdbus/queue.h | 82 ++ drivers/misc/kdbus/util.h |2 +- 9 files changed, 3401 insertions(+), 1 deletion(-) create mode 100644 drivers/misc/kdbus/connection.c create mode 100644 drivers/misc/kdbus/connection.h create mode 100644 drivers/misc/kdbus/item.c create mode 100644 drivers/misc/kdbus/item.h create mode 100644 drivers/misc/kdbus/message.c create mode 100644 drivers/misc/kdbus/message.h create mode 100644 drivers/misc/kdbus/queue.c create mode 100644 drivers/misc/kdbus/queue.h diff --git a/drivers/misc/kdbus/connection.c b/drivers/misc/kdbus/connection.c new file mode 100644 index ..5b1f3ed51611 --- /dev/null +++ b/drivers/misc/kdbus/connection.c @@ -0,0 +1,1751 @@ +/* + * Copyright (C) 2013-2014 Kay Sievers + * Copyright (C) 2013-2014 Greg Kroah-Hartman + * Copyright (C) 2013-2014 Daniel Mack + * Copyright (C) 2013-2014 David Herrmann + * Copyright (C) 2013-2014 Linux Foundation + * Copyright (C) 2014 Djalal Harouni + * + * kdbus is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bus.h" +#include "connection.h" +#include "endpoint.h" +#include "match.h" +#include "message.h" +#include "metadata.h" +#include "names.h" +#include "domain.h" +#include "item.h" +#include "notify.h" +#include "policy.h" +#include "util.h" +#include "queue.h" + +struct kdbus_conn_reply; + +#define KDBUS_CONN_ACTIVE_BIAS (INT_MIN + 1) + +/** + * struct kdbus_conn_reply - an entry of kdbus_conn's list of replies + * @kref: Ref-count of this object + * @entry: The entry of the connection's reply_list + * @reply_dst: The connection the reply will be sent to (method origin) + * @queue_entry: The queue enty item that is prepared by the replying + * connection + * @deadline_ns: The deadline of the reply, in nanoseconds + * @cookie:The cookie of the requesting message + * @name_id: ID of the well-known name the original msg was sent to + * @sync: The reply block is waiting for synchronous I/O + * @waiting: The condition to synchronously wait for + * @interrupted: The sync reply was left in an interrupted state + * @err: The error code for the synchronous reply + */ +struct kdbus_conn_reply { + struct kref kref; + struct list_head entry; + struct kdbus_conn *reply_dst; + struct kdbus_queue_entry *queue_entry; + u64 deadline_ns; + u64 cookie; + u64 name_id; + bool sync:1; + bool waiting:1; + bool interrupted:1; + int err; +}; + +static int kdbus_conn_reply_new(struct kdbus_conn_reply **reply_wait, + struct kdbus_conn *reply_dst, + const struct kdbus_msg *msg, + struct kdbus_name_entry *name_entry) +{ + bool sync = msg->flags & KDBUS_MSG_FLAGS_SYNC_REPLY; + struct kdbus_conn_reply *r; + int ret = 0; + + if (atomic_inc_return(&reply_dst->reply_count) > + KDBUS_CONN_MAX_REQUESTS_PENDING) { + ret = -EMLINK; + goto exit_dec_reply_count; + } + + r = kzalloc(sizeof(*r), GFP_KERNEL); + if (!r) { + ret = -ENOMEM; + goto exit_dec_reply_count; + } + + kref_init(&r->kref); + r->reply_dst = kdbus_conn_ref(reply_dst); + r->cookie = msg->cookie; + r->name_id = name_entry ? name_entry->name_id : 0; + r->deadline_ns = msg->timeout_ns; + + if (sync) { + r->sync = true; + r->waiting = true; + } + + *reply_wait = r; + +exit_dec_reply_count: + if (ret < 0) + atomic_dec(&reply_dst->reply_count); + + return ret; +} + +static void __kdbus_conn_reply_free(struct kref *kref) +{ +