diff options
author | Kay Sievers <kay@vrfy.org> | 2014-01-18 17:31:41 +0100 |
---|---|---|
committer | Kay Sievers <kay@vrfy.org> | 2014-01-18 17:31:41 +0100 |
commit | 8e1dcbfc9654ada7a1deac571f0187fec8454571 (patch) | |
tree | 83c8e2206135e8f920ae313472158ef0c871e2d9 | |
parent | a4017447d1da830993fcb62b5ec45fd14b17c566 (diff) | |
download | kdbus-bus-8e1dcbfc9654ada7a1deac571f0187fec8454571.tar.gz kdbus-bus-8e1dcbfc9654ada7a1deac571f0187fec8454571.tar.bz2 kdbus-bus-8e1dcbfc9654ada7a1deac571f0187fec8454571.zip |
limit the number of buses and connections per user
-rw-r--r-- | TODO | 3 | ||||
-rw-r--r-- | bus.c | 19 | ||||
-rw-r--r-- | bus.h | 2 | ||||
-rw-r--r-- | connection.c | 22 | ||||
-rw-r--r-- | connection.h | 2 | ||||
-rw-r--r-- | defaults.h | 6 | ||||
-rw-r--r-- | handle.c | 6 | ||||
-rw-r--r-- | kdbus.h | 2 | ||||
-rw-r--r-- | namespace.c | 58 | ||||
-rw-r--r-- | namespace.h | 24 |
10 files changed, 140 insertions, 4 deletions
@@ -21,9 +21,6 @@ Features: for another connection, like a connection can have a maximum of 100 messages in-flight, but only 10 of them for the same connection - - limit the number of buses an ordinary user can create - - limit the number of connections per uid - - allow to update the metadata subscription bit mask - support the creation of anonymous buses @@ -57,6 +57,10 @@ static void __kdbus_bus_free(struct kref *kref) struct kdbus_bus *bus = container_of(kref, struct kdbus_bus, kref); kdbus_bus_disconnect(bus); + + atomic_dec(&bus->user->buses); + kdbus_ns_user_unref(bus->user); + if (bus->name_registry) kdbus_name_registry_free(bus->name_registry); kdbus_ns_unref(bus->ns); @@ -237,6 +241,21 @@ int kdbus_bus_new(struct kdbus_ns *ns, if (ret < 0) goto exit; + /* account the bus against the user */ + b->user = kdbus_ns_user_ref(ns, uid); + if (!b->user) { + ret = -ENOMEM; + goto exit; + } + + if (!capable(CAP_IPC_OWNER) && + atomic_inc_return(&b->user->buses) > KDBUS_USER_MAX_BUSES) { + atomic_dec(&b->user->buses); + b->user = kdbus_ns_user_unref(b->user); + ret = -EMFILE; + goto exit; + } + /* link into namespace */ mutex_lock(&ns->lock); b->id = ++ns->bus_seq_last; @@ -38,6 +38,7 @@ * @ns_entry: Namespace's list of buses * @monitors_list: Connections that monitor this bus * @id128: Unique random 128 bit ID of this bus + * @user: Owner of the connection; * * A bus provides a "bus" endpoint / device node. * @@ -64,6 +65,7 @@ struct kdbus_bus { struct list_head ns_entry; struct list_head monitors_list; u8 id128[16]; + struct kdbus_ns_user *user; }; int kdbus_bus_make_user(void __user *buf, struct kdbus_cmd_make **make, diff --git a/connection.c b/connection.c index b952b4e4854..0bbdb182d41 100644 --- a/connection.c +++ b/connection.c @@ -1359,6 +1359,10 @@ static void __kdbus_conn_free(struct kref *kref) struct kdbus_conn_reply_entry *reply, *reply_tmp; kdbus_conn_disconnect(conn, false); + + atomic_dec(&conn->user->connections); + kdbus_ns_user_unref(conn->user); + if (conn->ep->policy_db) kdbus_policy_db_remove_conn(conn->ep->policy_db, conn); @@ -1824,6 +1828,20 @@ int kdbus_conn_new(struct kdbus_ep *ep, conn->meta = meta; } + /* account the connection against the user */ + conn->user = kdbus_ns_user_ref(ep->bus->ns, ep->bus->uid_owner); + if (!conn->user) { + ret = -ENOMEM; + goto exit_free_meta; + } + + if (!capable(CAP_IPC_OWNER) && + atomic_inc_return(&conn->user->connections) > KDBUS_USER_MAX_CONN) { + atomic_dec(&conn->user->connections); + ret = -EMFILE; + goto exit_unref_user; + } + /* link into bus */ mutex_lock(&bus->lock); hash_add(bus->conn_hash, &conn->hentry, conn->id); @@ -1832,6 +1850,8 @@ int kdbus_conn_new(struct kdbus_ep *ep, *c = conn; return 0; +exit_unref_user: + kdbus_ns_user_unref(conn->user); exit_free_meta: kdbus_meta_free(conn->owner_meta); exit_release_names: @@ -1850,7 +1870,7 @@ exit_free_conn: } /** - * kdbus_conn_has_name() - check if a connection owns a name + * kdbus_conn_has_name() - check if a connection owns r name * @conn: Connection * @name: Well-know name to check for * diff --git a/connection.h b/connection.h index f55b3b57ba8..624cbd0de4e 100644 --- a/connection.h +++ b/connection.h @@ -49,6 +49,7 @@ * HELLO * @msg_count: Number of queued messages * @pool: The user's buffer to receive messages + * @user: Owner of the connection; */ struct kdbus_conn { struct kref kref; @@ -76,6 +77,7 @@ struct kdbus_conn { struct kdbus_meta *owner_meta; unsigned int msg_count; struct kdbus_pool *pool; + struct kdbus_ns_user *user; }; struct kdbus_kmsg; diff --git a/defaults.h b/defaults.h index da6b83c986e..683b4e2c56b 100644 --- a/defaults.h +++ b/defaults.h @@ -52,4 +52,10 @@ /* maximum number of queud requests waiting ot a reply */ #define KDBUS_CONN_MAX_REQUESTS_PENDING 64 +/* maximum number of connections per user in one namespace */ +#define KDBUS_USER_MAX_CONN 256 + +/* maximum number of buses per user in one namespace */ +#define KDBUS_USER_MAX_BUSES 16 + #endif @@ -401,6 +401,12 @@ static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd, kgid_t gid = KGIDT_INIT(0); char *name; + /* creating custom endpoints is a privileged operation */ + if (!kdbus_bus_uid_is_privileged(handle->ep->bus)) { + ret = -EFAULT; + break; + } + if (!KDBUS_IS_ALIGNED8((uintptr_t)buf)) { ret = -EFAULT; break; @@ -864,6 +864,8 @@ enum kdbus_ioctl_type { * refused to send as KDBUS_MSG_PAYLOAD_MEMFD. * @EMFILE: Too many file descriptors have been supplied with a * message. + * Too many connections or buses are created for a given + * user. * @EMLINK: Too many requests from this connection to other peers * are queued and waiting for a reply * @EMSGSIZE: The supplied data is larger than the allowed maximum diff --git a/namespace.c b/namespace.c index 56e32c734c2..66af3b6a875 100644 --- a/namespace.c +++ b/namespace.c @@ -392,3 +392,61 @@ exit: kfree(m); return ret; } + +struct kdbus_ns_user *kdbus_ns_user_ref(struct kdbus_ns *ns, kuid_t uid) +{ + struct kdbus_ns_user *u; + + /* find uid and reference it */ + mutex_lock(&ns->lock); + hash_for_each_possible(ns->user_hash, u, hentry, uid) { + if (u->uid != uid) + continue; + + kref_get(&u->kref); + mutex_unlock(&ns->lock); + return u; + } + mutex_unlock(&ns->lock); + + /* allocate a new user */ + u = kzalloc(GFP_KERNEL, sizeof(struct kdbus_ns_user)); + if (!u) + return NULL; + + kref_init(&u->kref); + u->ns = kdbus_ns_ref(ns); + u->uid = uid; + atomic_set(&u->buses, 0); + atomic_set(&u->connections, 0); + + /* link into namespace */ + mutex_lock(&ns->lock); + hash_add(ns->user_hash, &u->hentry, u->uid); + mutex_unlock(&ns->lock); + +printk("new user %u\n", u->uid); + return u; +} + +static void __kdbus_ns_user_free(struct kref *kref) +{ + struct kdbus_ns_user *user = container_of(kref, struct kdbus_ns_user, + kref); + + BUG_ON(atomic_read(&user->buses) > 0); + BUG_ON(atomic_read(&user->connections) > 0); + + mutex_lock(&user->ns->lock); + hash_del(&user->hentry); + mutex_unlock(&user->ns->lock); + kdbus_ns_unref(user->ns); +printk("user %u done\n", user->uid); + kfree(user); +} + +struct kdbus_ns_user *kdbus_ns_user_unref(struct kdbus_ns_user *user) +{ + kref_put(&user->kref, __kdbus_ns_user_free); + return NULL; +} diff --git a/namespace.h b/namespace.h index a5dbb9b8ba6..e36ce939d64 100644 --- a/namespace.h +++ b/namespace.h @@ -13,6 +13,7 @@ #ifndef __KDBUS_NS_H #define __KDBUS_NS_H +#include <linux/hashtable.h> #include <linux/idr.h> /** @@ -33,6 +34,7 @@ * @msg_seq_last: Last used message id sequence number * @ns_entry: Entry in parent namespace * @bus_list: Buses in this namespace + * @user_hash: Accounting of user resources * * A namespace provides a "control" device node. Every namespace has its * own major number for its endpoint device nodes. @@ -61,6 +63,25 @@ struct kdbus_ns { atomic64_t msg_seq_last; struct list_head ns_entry; struct list_head bus_list; + DECLARE_HASHTABLE(user_hash, 6); +}; + +/** + * struct kdbus_ns_user - resource accounting for users + * @kref: Reference counter + * @ns: Namespace of the user + * @hentry: Entry in namespace user map + * @uid: UID of the user + * @buses: Number of buses the user has created + * @connections: Number of connections the user has created + */ +struct kdbus_ns_user { + struct kref kref; + struct kdbus_ns *ns; + struct hlist_node hentry; + kuid_t uid; + atomic_t buses; + atomic_t connections; }; extern struct kdbus_ns *kdbus_ns_init; @@ -74,4 +95,7 @@ int kdbus_ns_new(struct kdbus_ns *parent, const char *name, int kdbus_ns_make_user(void __user *buf, struct kdbus_cmd_make **make, char **name); struct kdbus_ns *kdbus_ns_find_by_major(unsigned int major); + +struct kdbus_ns_user *kdbus_ns_user_ref(struct kdbus_ns *ns, kuid_t uid); +struct kdbus_ns_user *kdbus_ns_user_unref(struct kdbus_ns_user *user); #endif |