]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - security/keys/key.c
Fix nfsd truncation of readdir results
[linux-2.6-omap-h63xx.git] / security / keys / key.c
index 01bbc6d9d19b0997a8d984cdd2373d9adc96090b..14948cf83ef6acc6ea19811465201ff5ae8660f0 100644 (file)
@@ -1,6 +1,6 @@
-/* key.c: basic authentication token and access key management
+/* Basic authentication token and access key management
  *
- * Copyright (C) 2004-6 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-2008 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -27,6 +27,11 @@ DEFINE_SPINLOCK(key_serial_lock);
 struct rb_root key_user_tree; /* tree of quota records indexed by UID */
 DEFINE_SPINLOCK(key_user_lock);
 
+unsigned int key_quota_root_maxkeys = 200;     /* root's key count quota */
+unsigned int key_quota_root_maxbytes = 20000;  /* root's key space quota */
+unsigned int key_quota_maxkeys = 200;          /* general key count quota */
+unsigned int key_quota_maxbytes = 20000;       /* general key space quota */
+
 static LIST_HEAD(key_types_list);
 static DECLARE_RWSEM(key_types_sem);
 
@@ -34,7 +39,7 @@ static void key_cleanup(struct work_struct *work);
 static DECLARE_WORK(key_cleanup_task, key_cleanup);
 
 /* we serialise key instantiation and link */
-DECLARE_RWSEM(key_construction_sem);
+DEFINE_MUTEX(key_construction_mutex);
 
 /* any key who's type gets unegistered will be re-typed to this */
 static struct key_type key_type_dead = {
@@ -104,7 +109,7 @@ struct key_user *key_user_lookup(uid_t uid)
        candidate->qnkeys = 0;
        candidate->qnbytes = 0;
        spin_lock_init(&candidate->lock);
-       INIT_LIST_HEAD(&candidate->consq);
+       mutex_init(&candidate->cons_lock);
 
        rb_link_node(&candidate->node, parent, p);
        rb_insert_color(&candidate->node, &key_user_tree);
@@ -137,36 +142,6 @@ void key_user_put(struct key_user *user)
 
 } /* end key_user_put() */
 
-/*****************************************************************************/
-/*
- * insert a key with a fixed serial number
- */
-static void __init __key_insert_serial(struct key *key)
-{
-       struct rb_node *parent, **p;
-       struct key *xkey;
-
-       parent = NULL;
-       p = &key_serial_tree.rb_node;
-
-       while (*p) {
-               parent = *p;
-               xkey = rb_entry(parent, struct key, serial_node);
-
-               if (key->serial < xkey->serial)
-                       p = &(*p)->rb_left;
-               else if (key->serial > xkey->serial)
-                       p = &(*p)->rb_right;
-               else
-                       BUG();
-       }
-
-       /* we've found a suitable hole - arrange for this key to occupy it */
-       rb_link_node(&key->serial_node, parent, p);
-       rb_insert_color(&key->serial_node, &key_serial_tree);
-
-} /* end __key_insert_serial() */
-
 /*****************************************************************************/
 /*
  * assign a key the next unique serial number
@@ -266,11 +241,16 @@ struct key *key_alloc(struct key_type *type, const char *desc,
        /* check that the user's quota permits allocation of another key and
         * its description */
        if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
+               unsigned maxkeys = (uid == 0) ?
+                       key_quota_root_maxkeys : key_quota_maxkeys;
+               unsigned maxbytes = (uid == 0) ?
+                       key_quota_root_maxbytes : key_quota_maxbytes;
+
                spin_lock(&user->lock);
                if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) {
-                       if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
-                           user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES
-                           )
+                       if (user->qnkeys + 1 >= maxkeys ||
+                           user->qnbytes + quotalen >= maxbytes ||
+                           user->qnbytes + quotalen < user->qnbytes)
                                goto no_quota;
                }
 
@@ -375,11 +355,14 @@ int key_payload_reserve(struct key *key, size_t datalen)
 
        /* contemplate the quota adjustment */
        if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
+               unsigned maxbytes = (key->user->uid == 0) ?
+                       key_quota_root_maxbytes : key_quota_maxbytes;
+
                spin_lock(&key->user->lock);
 
                if (delta > 0 &&
-                   key->user->qnbytes + delta > KEYQUOTA_MAX_BYTES
-                   ) {
+                   (key->user->qnbytes + delta >= maxbytes ||
+                    key->user->qnbytes + delta < key->user->qnbytes)) {
                        ret = -EDQUOT;
                }
                else {
@@ -418,7 +401,7 @@ static int __key_instantiate_and_link(struct key *key,
        awaken = 0;
        ret = -EBUSY;
 
-       down_write(&key_construction_sem);
+       mutex_lock(&key_construction_mutex);
 
        /* can't instantiate twice */
        if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
@@ -443,11 +426,11 @@ static int __key_instantiate_and_link(struct key *key,
                }
        }
 
-       up_write(&key_construction_sem);
+       mutex_unlock(&key_construction_mutex);
 
        /* wake up anyone waiting for a key to be constructed */
        if (awaken)
-               wake_up_all(&request_key_conswq);
+               wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
 
        return ret;
 
@@ -500,7 +483,7 @@ int key_negate_and_link(struct key *key,
        if (keyring)
                down_write(&keyring->sem);
 
-       down_write(&key_construction_sem);
+       mutex_lock(&key_construction_mutex);
 
        /* can't instantiate twice */
        if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
@@ -525,14 +508,14 @@ int key_negate_and_link(struct key *key,
                        key_revoke(instkey);
        }
 
-       up_write(&key_construction_sem);
+       mutex_unlock(&key_construction_mutex);
 
        if (keyring)
                up_write(&keyring->sem);
 
        /* wake up anyone waiting for a key to be constructed */
        if (awaken)
-               wake_up_all(&request_key_conswq);
+               wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
 
        return ret;
 
@@ -757,11 +740,11 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
                               const char *description,
                               const void *payload,
                               size_t plen,
+                              key_perm_t perm,
                               unsigned long flags)
 {
        struct key_type *ktype;
        struct key *keyring, *key = NULL;
-       key_perm_t perm;
        key_ref_t key_ref;
        int ret;
 
@@ -806,21 +789,23 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
                        goto found_matching_key;
        }
 
-       /* decide on the permissions we want */
-       perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR;
-       perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK | KEY_USR_SETATTR;
+       /* if the client doesn't provide, decide on the permissions we want */
+       if (perm == KEY_PERM_UNDEF) {
+               perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR;
+               perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK | KEY_USR_SETATTR;
 
-       if (ktype->read)
-               perm |= KEY_POS_READ | KEY_USR_READ;
+               if (ktype->read)
+                       perm |= KEY_POS_READ | KEY_USR_READ;
 
-       if (ktype == &key_type_keyring || ktype->update)
-               perm |= KEY_USR_WRITE;
+               if (ktype == &key_type_keyring || ktype->update)
+                       perm |= KEY_USR_WRITE;
+       }
 
        /* allocate a new key */
        key = key_alloc(ktype, description, current->fsuid, current->fsgid,
                        current, perm, flags);
        if (IS_ERR(key)) {
-               key_ref = ERR_PTR(PTR_ERR(key));
+               key_ref = ERR_CAST(key);
                goto error_3;
        }
 
@@ -899,12 +884,14 @@ void key_revoke(struct key *key)
 {
        key_check(key);
 
-       /* make sure no one's trying to change or use the key when we mark
-        * it */
-       down_write(&key->sem);
-       set_bit(KEY_FLAG_REVOKED, &key->flags);
-
-       if (key->type->revoke)
+       /* make sure no one's trying to change or use the key when we mark it
+        * - we tell lockdep that we might nest because we might be revoking an
+        *   authorisation key whilst holding the sem on a key we've just
+        *   instantiated
+        */
+       down_write_nested(&key->sem, 1);
+       if (!test_and_set_bit(KEY_FLAG_REVOKED, &key->flags) &&
+           key->type->revoke)
                key->type->revoke(key);
 
        up_write(&key->sem);
@@ -1016,17 +1003,4 @@ void __init key_init(void)
        rb_insert_color(&root_key_user.node,
                        &key_user_tree);
 
-       /* record root's user standard keyrings */
-       key_check(&root_user_keyring);
-       key_check(&root_session_keyring);
-
-       __key_insert_serial(&root_user_keyring);
-       __key_insert_serial(&root_session_keyring);
-
-       keyring_publish_name(&root_user_keyring);
-       keyring_publish_name(&root_session_keyring);
-
-       /* link the two root keyrings together */
-       key_link(&root_session_keyring, &root_user_keyring);
-
 } /* end key_init() */