[PATCH] jiffies_64 cleanup
[linux-2.6.git] / security / keys / keyring.c
index 90a551e..e1cc4dd 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/security.h>
 #include <linux/seq_file.h>
 #include <linux/err.h>
 #include <asm/uaccess.h>
@@ -129,7 +130,7 @@ static int keyring_duplicate(struct key *keyring, const struct key *source)
        int loop, ret;
 
        const unsigned limit =
-               (PAGE_SIZE - sizeof(*klist)) / sizeof(struct key);
+               (PAGE_SIZE - sizeof(*klist)) / sizeof(struct key *);
 
        ret = 0;
 
@@ -150,7 +151,7 @@ static int keyring_duplicate(struct key *keyring, const struct key *source)
                        max = limit;
 
                ret = -ENOMEM;
-               size = sizeof(*klist) + sizeof(struct key) * max;
+               size = sizeof(*klist) + sizeof(struct key *) * max;
                klist = kmalloc(size, GFP_KERNEL);
                if (!klist)
                        goto error;
@@ -163,7 +164,7 @@ static int keyring_duplicate(struct key *keyring, const struct key *source)
                klist->nkeys = sklist->nkeys;
                memcpy(klist->keys,
                       sklist->keys,
-                      sklist->nkeys * sizeof(struct key));
+                      sklist->nkeys * sizeof(struct key *));
 
                for (loop = klist->nkeys - 1; loop >= 0; loop--)
                        atomic_inc(&klist->keys[loop]->usage);
@@ -201,7 +202,11 @@ static void keyring_destroy(struct key *keyring)
 
        if (keyring->description) {
                write_lock(&keyring_name_lock);
-               list_del(&keyring->type_data.link);
+
+               if (keyring->type_data.link.next != NULL &&
+                   !list_empty(&keyring->type_data.link))
+                       list_del(&keyring->type_data.link);
+
                write_unlock(&keyring_name_lock);
        }
 
@@ -305,7 +310,9 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
        int ret;
 
        keyring = key_alloc(&key_type_keyring, description,
-                           uid, gid, KEY_USR_ALL, not_in_quota);
+                           uid, gid,
+                           (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
+                           not_in_quota);
 
        if (!IS_ERR(keyring)) {
                ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
@@ -329,12 +336,13 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
  * - we rely on RCU to prevent the keyring lists from disappearing on us
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we only found negative matching keys
+ * - we propagate the possession attribute from the keyring ref to the key ref
  */
-struct key *keyring_search_aux(struct key *keyring,
-                              struct task_struct *context,
-                              struct key_type *type,
-                              const void *description,
-                              key_match_func_t match)
+key_ref_t keyring_search_aux(key_ref_t keyring_ref,
+                            struct task_struct *context,
+                            struct key_type *type,
+                            const void *description,
+                            key_match_func_t match)
 {
        struct {
                struct keyring_list *keylist;
@@ -343,29 +351,35 @@ struct key *keyring_search_aux(struct key *keyring,
 
        struct keyring_list *keylist;
        struct timespec now;
-       struct key *key;
+       unsigned long possessed;
+       struct key *keyring, *key;
+       key_ref_t key_ref;
        long err;
        int sp, kix;
 
+       keyring = key_ref_to_ptr(keyring_ref);
+       possessed = is_key_possessed(keyring_ref);
        key_check(keyring);
 
-       rcu_read_lock();
-
        /* top keyring must have search permission to begin the search */
-       key = ERR_PTR(-EACCES);
-       if (!key_task_permission(keyring, context, KEY_SEARCH))
+        err = key_task_permission(keyring_ref, context, KEY_SEARCH);
+       if (err < 0) {
+               key_ref = ERR_PTR(err);
                goto error;
+       }
 
-       key = ERR_PTR(-ENOTDIR);
+       key_ref = ERR_PTR(-ENOTDIR);
        if (keyring->type != &key_type_keyring)
                goto error;
 
+       rcu_read_lock();
+
        now = current_kernel_time();
        err = -EAGAIN;
        sp = 0;
 
        /* start processing a new keyring */
- descend:
+descend:
        if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
                goto not_this_keyring;
 
@@ -393,7 +407,8 @@ struct key *keyring_search_aux(struct key *keyring,
                        continue;
 
                /* key must have search permissions */
-               if (!key_task_permission(key, context, KEY_SEARCH))
+               if (key_task_permission(make_key_ref(key, possessed),
+                                       context, KEY_SEARCH) < 0)
                        continue;
 
                /* we set a different error code if we find a negative key */
@@ -407,7 +422,7 @@ struct key *keyring_search_aux(struct key *keyring,
 
        /* search through the keyrings nested in this one */
        kix = 0;
- ascend:
+ascend:
        for (; kix < keylist->nkeys; kix++) {
                key = keylist->keys[kix];
                if (key->type != &key_type_keyring)
@@ -419,7 +434,8 @@ struct key *keyring_search_aux(struct key *keyring,
                if (sp >= KEYRING_SEARCH_MAX_DEPTH)
                        continue;
 
-               if (!key_task_permission(key, context, KEY_SEARCH))
+               if (!key_task_permission(make_key_ref(key, possessed),
+                                        context, KEY_SEARCH) < 0)
                        continue;
 
                /* stack the current position */
@@ -434,7 +450,7 @@ struct key *keyring_search_aux(struct key *keyring,
 
        /* the keyring we're looking at was disqualified or didn't contain a
         * matching key */
- not_this_keyring:
+not_this_keyring:
        if (sp > 0) {
                /* resume the processing of a keyring higher up in the tree */
                sp--;
@@ -443,16 +459,18 @@ struct key *keyring_search_aux(struct key *keyring,
                goto ascend;
        }
 
-       key = ERR_PTR(err);
-       goto error;
+       key_ref = ERR_PTR(err);
+       goto error_2;
 
        /* we found a viable match */
- found:
+found:
        atomic_inc(&key->usage);
        key_check(key);
- error:
+       key_ref = make_key_ref(key, possessed);
+error_2:
        rcu_read_unlock();
-       return key;
+error:
+       return key_ref;
 
 } /* end keyring_search_aux() */
 
@@ -465,9 +483,9 @@ struct key *keyring_search_aux(struct key *keyring,
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we only found negative matching keys
  */
-struct key *keyring_search(struct key *keyring,
-                          struct key_type *type,
-                          const char *description)
+key_ref_t keyring_search(key_ref_t keyring,
+                        struct key_type *type,
+                        const char *description)
 {
        if (!type->match)
                return ERR_PTR(-ENOKEY);
@@ -484,15 +502,19 @@ EXPORT_SYMBOL(keyring_search);
  * search the given keyring only (no recursion)
  * - keyring must be locked by caller
  */
-struct key *__keyring_search_one(struct key *keyring,
-                                const struct key_type *ktype,
-                                const char *description,
-                                key_perm_t perm)
+key_ref_t __keyring_search_one(key_ref_t keyring_ref,
+                              const struct key_type *ktype,
+                              const char *description,
+                              key_perm_t perm)
 {
        struct keyring_list *klist;
-       struct key *key;
+       unsigned long possessed;
+       struct key *keyring, *key;
        int loop;
 
+       keyring = key_ref_to_ptr(keyring_ref);
+       possessed = is_key_possessed(keyring_ref);
+
        rcu_read_lock();
 
        klist = rcu_dereference(keyring->payload.subscriptions);
@@ -503,21 +525,21 @@ struct key *__keyring_search_one(struct key *keyring,
                        if (key->type == ktype &&
                            (!key->type->match ||
                             key->type->match(key, description)) &&
-                           key_permission(key, perm) &&
+                           key_permission(make_key_ref(key, possessed),
+                                          perm) < 0 &&
                            !test_bit(KEY_FLAG_REVOKED, &key->flags)
                            )
                                goto found;
                }
        }
 
-       key = ERR_PTR(-ENOKEY);
-       goto error;
+       rcu_read_unlock();
+       return ERR_PTR(-ENOKEY);
 
  found:
        atomic_inc(&key->usage);
- error:
        rcu_read_unlock();
-       return key;
+       return make_key_ref(key, possessed);
 
 } /* end __keyring_search_one() */
 
@@ -599,7 +621,8 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound)
                        if (strcmp(keyring->description, name) != 0)
                                continue;
 
-                       if (!key_permission(keyring, KEY_SEARCH))
+                       if (!key_permission(make_key_ref(keyring, 0),
+                                           KEY_SEARCH) < 0)
                                continue;
 
                        /* found a potential candidate, but we still need to
@@ -783,7 +806,7 @@ int __key_link(struct key *keyring, struct key *key)
                ret = -ENFILE;
                if (max > 65535)
                        goto error3;
-               size = sizeof(*klist) + sizeof(*key) * max;
+               size = sizeof(*klist) + sizeof(struct key *) * max;
                if (size > PAGE_SIZE)
                        goto error3;
 
@@ -895,7 +918,8 @@ int key_unlink(struct key *keyring, struct key *key)
 
 key_is_present:
        /* we need to copy the key list for RCU purposes */
-       nklist = kmalloc(sizeof(*klist) + sizeof(*key) * klist->maxkeys,
+       nklist = kmalloc(sizeof(*klist) +
+                        sizeof(struct key *) * klist->maxkeys,
                         GFP_KERNEL);
        if (!nklist)
                goto nomem;
@@ -905,12 +929,12 @@ key_is_present:
        if (loop > 0)
                memcpy(&nklist->keys[0],
                       &klist->keys[0],
-                      loop * sizeof(klist->keys[0]));
+                      loop * sizeof(struct key *));
 
        if (loop < nklist->nkeys)
                memcpy(&nklist->keys[loop],
                       &klist->keys[loop + 1],
-                      (nklist->nkeys - loop) * sizeof(klist->keys[0]));
+                      (nklist->nkeys - loop) * sizeof(struct key *));
 
        /* adjust the user's quota */
        key_payload_reserve(keyring,