kdbus: improve user quota accounting by using kdbus_domain_user_account()
authorDjalal Harouni <tixxdz@opendz.org>
Wed, 30 Jul 2014 20:11:55 +0000 (21:11 +0100)
committerKay Sievers <kay@vrfy.org>
Thu, 31 Jul 2014 14:29:56 +0000 (16:29 +0200)
Currently kdbus_domain_user_find_or_new() is used to find a user
domain or create a new one and link it into the domain.

kdbus_domain_user_find_or_new() may fail due to memory allocation
errors or if the domain was shutdown, but since callers will
receive only a NULL pointer on failure, they assume -ENOMEM and
ignore -ESHUTDOWN. Fix this in kdbus_domain_user_account() by returning
the appropriate error code.

There are also some races with kdbus_domain_user_find_or_new(), if it is
called with the same parameters and if we do not find a previously
linked domain user, then both threads will race to assign a different ID
for the same uid, thus, invalidating the users array. We fix this in the
new kdbus_domain_user_account() and __kdbus_domain_user_account() by
taking the domain lock only one time.

Replace some kdbus_domain_user_find_or_new() calls with
kdbus_domain_user_account(). The last one in bus.c is updated in the
next patch.

Signed-off-by: Djalal Harouni <tixxdz@opendz.org>
connection.c
handle.c

index 85ffa5acd1a4a490b63c59886a38a5e341721b62..e0bcee19ae6c6efdc4aa566f6809e2392ac982be 100644 (file)
@@ -2088,12 +2088,12 @@ int kdbus_conn_new(struct kdbus_ep *ep,
         */
        if (ep->user)
                conn->user = kdbus_domain_user_ref(ep->user);
-       else
-               conn->user = kdbus_domain_user_find_or_new(ep->bus->domain,
-                                                          current_fsuid());
-       if (!conn->user) {
-               ret = -ENOMEM;
-               goto exit_free_meta;
+       else {
+               ret = kdbus_domain_user_account(ep->bus->domain,
+                                               current_fsuid(),
+                                               &conn->user);
+               if (ret < 0)
+                       goto exit_free_meta;
        }
 
        /* lock order: domain -> bus -> ep -> names -> conn */
index bf32c6e6deaa805709222fe54af8e27388310722..d8e1dc62b8abeb9cc4bf8f9dbc934ad27607b5f5 100644 (file)
--- a/handle.c
+++ b/handle.c
@@ -464,11 +464,11 @@ static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd,
                 * endpoint users do not share the budget with the ordinary
                 * users created for a UID.
                 */
-               ep->user = kdbus_domain_user_find_or_new(
-                               handle->ep->bus->domain, INVALID_UID);
-               if (!ep->user) {
+               ret = kdbus_domain_user_account(
+                               handle->ep->bus->domain,
+                               INVALID_UID, &ep->user);
+               if (ret < 0) {
                        kdbus_ep_unref(ep);
-                       ret = -ENOMEM;
                        break;
                }