KEYS/DNS: Fix ____call_usermodehelper() to not lose the session keyring
[linux-3.10.git] / security / keys / permission.c
index baf3d5f..c35b522 100644 (file)
@@ -1,4 +1,4 @@
-/* permission.c: key permission determination
+/* Key permission checking
  *
  * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
 #include <linux/security.h>
 #include "internal.h"
 
-/*****************************************************************************/
-/*
- * check to see whether permission is granted to use a key in the desired way,
- * but permit the security modules to override
+/**
+ * key_task_permission - Check a key can be used
+ * @key_ref: The key to check.
+ * @cred: The credentials to use.
+ * @perm: The permissions to check for.
+ *
+ * Check to see whether permission is granted to use a key in the desired way,
+ * but permit the security modules to override.
+ *
+ * The caller must hold either a ref on cred or must hold the RCU readlock.
+ *
+ * Returns 0 if successful, -EACCES if access is denied based on the
+ * permissions bits or the LSM check.
  */
-int key_task_permission(const key_ref_t key_ref,
-                       struct task_struct *context,
+int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
                        key_perm_t perm)
 {
-       struct cred *cred = context->cred;
        struct key *key;
        key_perm_t kperm;
        int ret;
 
        key = key_ref_to_ptr(key_ref);
 
+       if (key->user->user_ns != cred->user->user_ns)
+               goto use_other_perms;
+
        /* use the second 8-bits of permissions for keys the caller owns */
        if (key->uid == cred->fsuid) {
                kperm = key->perm >> 16;
@@ -43,20 +53,20 @@ int key_task_permission(const key_ref_t key_ref,
                        goto use_these_perms;
                }
 
-               spin_lock(&cred->lock);
                ret = groups_search(cred->group_info, key->gid);
-               spin_unlock(&cred->lock);
-
                if (ret) {
                        kperm = key->perm >> 8;
                        goto use_these_perms;
                }
        }
 
+use_other_perms:
+
        /* otherwise use the least-significant 8-bits */
        kperm = key->perm;
 
 use_these_perms:
+
        /* use the top 8-bits of permissions for keys the caller possesses
         * - possessor permissions are additive with other permissions
         */
@@ -69,15 +79,17 @@ use_these_perms:
                return -EACCES;
 
        /* let LSM be the final arbiter */
-       return security_key_permission(key_ref, context, perm);
-
-} /* end key_task_permission() */
-
+       return security_key_permission(key_ref, cred, perm);
+}
 EXPORT_SYMBOL(key_task_permission);
 
-/*****************************************************************************/
-/*
- * validate a key
+/**
+ * key_validate - Validate a key.
+ * @key: The key to be validated.
+ *
+ * Check that a key is valid, returning 0 if the key is okay, -EKEYREVOKED if
+ * the key's type has been removed or if the key has been revoked or
+ * -EKEYEXPIRED if the key has expired.
  */
 int key_validate(struct key *key)
 {
@@ -100,9 +112,7 @@ int key_validate(struct key *key)
                }
        }
 
- error:
+error:
        return ret;
-
-} /* end key_validate() */
-
+}
 EXPORT_SYMBOL(key_validate);