summaryrefslogtreecommitdiff
path: root/security/keys
diff options
context:
space:
mode:
Diffstat (limited to 'security/keys')
-rw-r--r--security/keys/Makefile1
-rw-r--r--security/keys/internal.h26
-rw-r--r--security/keys/key.c81
-rw-r--r--security/keys/keyctl.c301
-rw-r--r--security/keys/keyring.c86
-rw-r--r--security/keys/permission.c70
-rw-r--r--security/keys/proc.c2
-rw-r--r--security/keys/process_keys.c164
-rw-r--r--security/keys/request_key.c38
-rw-r--r--security/keys/request_key_auth.c5
10 files changed, 467 insertions, 307 deletions
diff --git a/security/keys/Makefile b/security/keys/Makefile
index c392d750b208..5145adfb6a05 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -6,6 +6,7 @@ obj-y := \
key.o \
keyring.o \
keyctl.o \
+ permission.o \
process_keys.o \
request_key.o \
request_key_auth.o \
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 46c8602661c9..db99ed434f3a 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -71,26 +71,26 @@ extern void keyring_publish_name(struct key *keyring);
extern int __key_link(struct key *keyring, struct key *key);
-extern struct key *__keyring_search_one(struct key *keyring,
- const struct key_type *type,
- const char *description,
- key_perm_t perm);
+extern key_ref_t __keyring_search_one(key_ref_t keyring_ref,
+ const struct key_type *type,
+ const char *description,
+ key_perm_t perm);
extern struct key *keyring_search_instkey(struct key *keyring,
key_serial_t target_id);
typedef int (*key_match_func_t)(const struct key *, const void *);
-extern struct key *keyring_search_aux(struct key *keyring,
- struct task_struct *tsk,
- struct key_type *type,
- const void *description,
- key_match_func_t match);
+extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
+ struct task_struct *tsk,
+ struct key_type *type,
+ const void *description,
+ key_match_func_t match);
-extern struct key *search_process_keyrings(struct key_type *type,
- const void *description,
- key_match_func_t match,
- struct task_struct *tsk);
+extern key_ref_t search_process_keyrings(struct key_type *type,
+ const void *description,
+ key_match_func_t match,
+ struct task_struct *tsk);
extern struct key *find_keyring_by_name(const char *name, key_serial_t bound);
diff --git a/security/keys/key.c b/security/keys/key.c
index fb89f9844465..2182be9e9309 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -693,14 +693,15 @@ void key_type_put(struct key_type *ktype)
* - the key has an incremented refcount
* - we need to put the key if we get an error
*/
-static inline struct key *__key_update(struct key *key, const void *payload,
- size_t plen)
+static inline key_ref_t __key_update(key_ref_t key_ref,
+ const void *payload, size_t plen)
{
+ struct key *key = key_ref_to_ptr(key_ref);
int ret;
/* need write permission on the key to update it */
ret = -EACCES;
- if (!key_permission(key, KEY_WRITE))
+ if (!key_permission(key_ref, KEY_WRITE))
goto error;
ret = -EEXIST;
@@ -719,12 +720,12 @@ static inline struct key *__key_update(struct key *key, const void *payload,
if (ret < 0)
goto error;
- out:
- return key;
+out:
+ return key_ref;
- error:
+error:
key_put(key);
- key = ERR_PTR(ret);
+ key_ref = ERR_PTR(ret);
goto out;
} /* end __key_update() */
@@ -734,52 +735,56 @@ static inline struct key *__key_update(struct key *key, const void *payload,
* search the specified keyring for a key of the same description; if one is
* found, update it, otherwise add a new one
*/
-struct key *key_create_or_update(struct key *keyring,
- const char *type,
- const char *description,
- const void *payload,
- size_t plen,
- int not_in_quota)
+key_ref_t key_create_or_update(key_ref_t keyring_ref,
+ const char *type,
+ const char *description,
+ const void *payload,
+ size_t plen,
+ int not_in_quota)
{
struct key_type *ktype;
- struct key *key = NULL;
+ struct key *keyring, *key = NULL;
key_perm_t perm;
+ key_ref_t key_ref;
int ret;
- key_check(keyring);
-
/* look up the key type to see if it's one of the registered kernel
* types */
ktype = key_type_lookup(type);
if (IS_ERR(ktype)) {
- key = ERR_PTR(-ENODEV);
+ key_ref = ERR_PTR(-ENODEV);
goto error;
}
- ret = -EINVAL;
+ key_ref = ERR_PTR(-EINVAL);
if (!ktype->match || !ktype->instantiate)
goto error_2;
+ keyring = key_ref_to_ptr(keyring_ref);
+
+ key_check(keyring);
+
+ down_write(&keyring->sem);
+
+ /* if we're going to allocate a new key, we're going to have
+ * to modify the keyring */
+ key_ref = ERR_PTR(-EACCES);
+ if (!key_permission(keyring_ref, KEY_WRITE))
+ goto error_3;
+
/* search for an existing key of the same type and description in the
* destination keyring
*/
- down_write(&keyring->sem);
-
- key = __keyring_search_one(keyring, ktype, description, 0);
- if (!IS_ERR(key))
+ key_ref = __keyring_search_one(keyring_ref, ktype, description, 0);
+ if (!IS_ERR(key_ref))
goto found_matching_key;
- /* if we're going to allocate a new key, we're going to have to modify
- * the keyring */
- ret = -EACCES;
- if (!key_permission(keyring, KEY_WRITE))
- goto error_3;
-
/* decide on the permissions we want */
- perm = KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK;
+ perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK;
+ perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK;
if (ktype->read)
- perm |= KEY_USR_READ;
+ perm |= KEY_POS_READ | KEY_USR_READ;
if (ktype == &key_type_keyring || ktype->update)
perm |= KEY_USR_WRITE;
@@ -788,7 +793,7 @@ struct key *key_create_or_update(struct key *keyring,
key = key_alloc(ktype, description, current->fsuid, current->fsgid,
perm, not_in_quota);
if (IS_ERR(key)) {
- ret = PTR_ERR(key);
+ key_ref = ERR_PTR(PTR_ERR(key));
goto error_3;
}
@@ -796,15 +801,18 @@ struct key *key_create_or_update(struct key *keyring,
ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL);
if (ret < 0) {
key_put(key);
- key = ERR_PTR(ret);
+ key_ref = ERR_PTR(ret);
+ goto error_3;
}
+ key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
+
error_3:
up_write(&keyring->sem);
error_2:
key_type_put(ktype);
error:
- return key;
+ return key_ref;
found_matching_key:
/* we found a matching key, so we're going to try to update it
@@ -813,7 +821,7 @@ struct key *key_create_or_update(struct key *keyring,
up_write(&keyring->sem);
key_type_put(ktype);
- key = __key_update(key, payload, plen);
+ key_ref = __key_update(key_ref, payload, plen);
goto error;
} /* end key_create_or_update() */
@@ -824,15 +832,16 @@ EXPORT_SYMBOL(key_create_or_update);
/*
* update a key
*/
-int key_update(struct key *key, const void *payload, size_t plen)
+int key_update(key_ref_t key_ref, const void *payload, size_t plen)
{
+ struct key *key = key_ref_to_ptr(key_ref);
int ret;
key_check(key);
/* the key must be writable */
ret = -EACCES;
- if (!key_permission(key, KEY_WRITE))
+ if (!key_permission(key_ref, KEY_WRITE))
goto error;
/* attempt to update it if supported */
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index a6516a64b297..4c670ee6acf9 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -34,7 +34,7 @@ asmlinkage long sys_add_key(const char __user *_type,
size_t plen,
key_serial_t ringid)
{
- struct key *keyring, *key;
+ key_ref_t keyring_ref, key_ref;
char type[32], *description;
void *payload;
long dlen, ret;
@@ -86,25 +86,25 @@ asmlinkage long sys_add_key(const char __user *_type,
}
/* find the target keyring (which must be writable) */
- keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
- if (IS_ERR(keyring)) {
- ret = PTR_ERR(keyring);
+ keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+ if (IS_ERR(keyring_ref)) {
+ ret = PTR_ERR(keyring_ref);
goto error3;
}
/* create or update the requested key and add it to the target
* keyring */
- key = key_create_or_update(keyring, type, description,
- payload, plen, 0);
- if (!IS_ERR(key)) {
- ret = key->serial;
- key_put(key);
+ key_ref = key_create_or_update(keyring_ref, type, description,
+ payload, plen, 0);
+ if (!IS_ERR(key_ref)) {
+ ret = key_ref_to_ptr(key_ref)->serial;
+ key_ref_put(key_ref);
}
else {
- ret = PTR_ERR(key);
+ ret = PTR_ERR(key_ref);
}
- key_put(keyring);
+ key_ref_put(keyring_ref);
error3:
kfree(payload);
error2:
@@ -131,7 +131,8 @@ asmlinkage long sys_request_key(const char __user *_type,
key_serial_t destringid)
{
struct key_type *ktype;
- struct key *key, *dest;
+ struct key *key;
+ key_ref_t dest_ref;
char type[32], *description, *callout_info;
long dlen, ret;
@@ -187,11 +188,11 @@ asmlinkage long sys_request_key(const char __user *_type,
}
/* get the destination keyring if specified */
- dest = NULL;
+ dest_ref = NULL;
if (destringid) {
- dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
- if (IS_ERR(dest)) {
- ret = PTR_ERR(dest);
+ dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
+ if (IS_ERR(dest_ref)) {
+ ret = PTR_ERR(dest_ref);
goto error3;
}
}
@@ -204,7 +205,8 @@ asmlinkage long sys_request_key(const char __user *_type,
}
/* do the search */
- key = request_key_and_link(ktype, description, callout_info, dest);
+ key = request_key_and_link(ktype, description, callout_info,
+ key_ref_to_ptr(dest_ref));
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error5;
@@ -216,7 +218,7 @@ asmlinkage long sys_request_key(const char __user *_type,
error5:
key_type_put(ktype);
error4:
- key_put(dest);
+ key_ref_put(dest_ref);
error3:
kfree(callout_info);
error2:
@@ -234,17 +236,17 @@ asmlinkage long sys_request_key(const char __user *_type,
*/
long keyctl_get_keyring_ID(key_serial_t id, int create)
{
- struct key *key;
+ key_ref_t key_ref;
long ret;
- key = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
- if (IS_ERR(key)) {
- ret = PTR_ERR(key);
+ key_ref = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
+ if (IS_ERR(key_ref)) {
+ ret = PTR_ERR(key_ref);
goto error;
}
- ret = key->serial;
- key_put(key);
+ ret = key_ref_to_ptr(key_ref)->serial;
+ key_ref_put(key_ref);
error:
return ret;
@@ -302,7 +304,7 @@ long keyctl_update_key(key_serial_t id,
const void __user *_payload,
size_t plen)
{
- struct key *key;
+ key_ref_t key_ref;
void *payload;
long ret;
@@ -324,16 +326,16 @@ long keyctl_update_key(key_serial_t id,
}
/* find the target key (which must be writable) */
- key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
- if (IS_ERR(key)) {
- ret = PTR_ERR(key);
+ key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
+ if (IS_ERR(key_ref)) {
+ ret = PTR_ERR(key_ref);
goto error2;
}
/* update the key */
- ret = key_update(key, payload, plen);
+ ret = key_update(key_ref, payload, plen);
- key_put(key);
+ key_ref_put(key_ref);
error2:
kfree(payload);
error:
@@ -349,19 +351,19 @@ long keyctl_update_key(key_serial_t id,
*/
long keyctl_revoke_key(key_serial_t id)
{
- struct key *key;
+ key_ref_t key_ref;
long ret;
- key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
- if (IS_ERR(key)) {
- ret = PTR_ERR(key);
+ key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
+ if (IS_ERR(key_ref)) {
+ ret = PTR_ERR(key_ref);
goto error;
}
- key_revoke(key);
+ key_revoke(key_ref_to_ptr(key_ref));
ret = 0;
- key_put(key);
+ key_ref_put(key_ref);
error:
return ret;
@@ -375,18 +377,18 @@ long keyctl_revoke_key(key_serial_t id)
*/
long keyctl_keyring_clear(key_serial_t ringid)
{
- struct key *keyring;
+ key_ref_t keyring_ref;
long ret;
- keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
- if (IS_ERR(keyring)) {
- ret = PTR_ERR(keyring);
+ keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+ if (IS_ERR(keyring_ref)) {
+ ret = PTR_ERR(keyring_ref);
goto error;
}
- ret = keyring_clear(keyring);
+ ret = keyring_clear(key_ref_to_ptr(keyring_ref));
- key_put(keyring);
+ key_ref_put(keyring_ref);
error:
return ret;
@@ -401,26 +403,26 @@ long keyctl_keyring_clear(key_serial_t ringid)
*/
long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
{
- struct key *keyring, *key;
+ key_ref_t keyring_ref, key_ref;
long ret;
- keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
- if (IS_ERR(keyring)) {
- ret = PTR_ERR(keyring);
+ keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+ if (IS_ERR(keyring_ref)) {
+ ret = PTR_ERR(keyring_ref);
goto error;
}
- key = lookup_user_key(NULL, id, 1, 0, KEY_LINK);
- if (IS_ERR(key)) {
- ret = PTR_ERR(key);
+ key_ref = lookup_user_key(NULL, id, 1, 0, KEY_LINK);
+ if (IS_ERR(key_ref)) {
+ ret = PTR_ERR(key_ref);
goto error2;
}
- ret = key_link(keyring, key);
+ ret = key_link(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));
- key_put(key);
+ key_ref_put(key_ref);
error2:
- key_put(keyring);
+ key_ref_put(keyring_ref);
error:
return ret;
@@ -435,26 +437,26 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
*/
long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
{
- struct key *keyring, *key;
+ key_ref_t keyring_ref, key_ref;
long ret;
- keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
- if (IS_ERR(keyring)) {
- ret = PTR_ERR(keyring);
+ keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
+ if (IS_ERR(keyring_ref)) {
+ ret = PTR_ERR(keyring_ref);
goto error;
}
- key = lookup_user_key(NULL, id, 0, 0, 0);
- if (IS_ERR(key)) {
- ret = PTR_ERR(key);
+ key_ref = lookup_user_key(NULL, id, 0, 0, 0);
+ if (IS_ERR(key_ref)) {
+ ret = PTR_ERR(key_ref);
goto error2;
}
- ret = key_unlink(keyring, key);
+ ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));
- key_put(key);
+ key_ref_put(key_ref);
error2:
- key_put(keyring);
+ key_ref_put(keyring_ref);
error:
return ret;
@@ -476,24 +478,26 @@ long keyctl_describe_key(key_serial_t keyid,
size_t buflen)
{
struct key *key, *instkey;
+ key_ref_t key_ref;
char *tmpbuf;
long ret;
- key = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
- if (IS_ERR(key)) {
+ key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
+ if (IS_ERR(key_ref)) {
/* viewing a key under construction is permitted if we have the
* authorisation token handy */
- if (PTR_ERR(key) == -EACCES) {
+ if (PTR_ERR(key_ref) == -EACCES) {
instkey = key_get_instantiation_authkey(keyid);
if (!IS_ERR(instkey)) {
key_put(instkey);
- key = lookup_user_key(NULL, keyid, 0, 1, 0);
- if (!IS_ERR(key))
+ key_ref = lookup_user_key(NULL, keyid,
+ 0, 1, 0);
+ if (!IS_ERR(key_ref))
goto okay;
}
}
- ret = PTR_ERR(key);
+ ret = PTR_ERR(key_ref);
goto error;
}
@@ -504,13 +508,16 @@ okay:
if (!tmpbuf)
goto error2;
+ key = key_ref_to_ptr(key_ref);
+
ret = snprintf(tmpbuf, PAGE_SIZE - 1,
- "%s;%d;%d;%06x;%s",
- key->type->name,
- key->uid,
- key->gid,
- key->perm,
- key->description ? key->description :""
+ "%s;%d;%d;%08x;%s",
+ key_ref_to_ptr(key_ref)->type->name,
+ key_ref_to_ptr(key_ref)->uid,
+ key_ref_to_ptr(key_ref)->gid,
+ key_ref_to_ptr(key_ref)->perm,
+ key_ref_to_ptr(key_ref)->description ?
+ key_ref_to_ptr(key_ref)->description : ""
);
/* include a NUL char at the end of the data */
@@ -530,7 +537,7 @@ okay:
kfree(tmpbuf);
error2:
- key_put(key);
+ key_ref_put(key_ref);
error:
return ret;
@@ -552,7 +559,7 @@ long keyctl_keyring_search(key_serial_t ringid,
key_serial_t destringid)
{
struct key_type *ktype;
- struct key *keyring, *key, *dest;
+ key_ref_t keyring_ref, key_ref, dest_ref;
char type[32], *description;
long dlen, ret;
@@ -581,18 +588,18 @@ long keyctl_keyring_search(key_serial_t ringid,
goto error2;
/* get the keyring at which to begin the search */
- keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
- if (IS_ERR(keyring)) {
- ret = PTR_ERR(keyring);
+ keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
+ if (IS_ERR(keyring_ref)) {
+ ret = PTR_ERR(keyring_ref);
goto error2;
}
/* get the destination keyring if specified */
- dest = NULL;
+ dest_ref = NULL;
if (destringid) {
- dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
- if (IS_ERR(dest)) {
- ret = PTR_ERR(dest);
+ dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
+ if (IS_ERR(dest_ref)) {
+ ret = PTR_ERR(dest_ref);
goto error3;
}
}
@@ -605,9 +612,9 @@ long keyctl_keyring_search(key_serial_t ringid,
}
/* do the search */
- key = keyring_search(keyring, ktype, description);
- if (IS_ERR(key)) {
- ret = PTR_ERR(key);
+ key_ref = keyring_search(keyring_ref, ktype, description);
+ if (IS_ERR(key_ref)) {
+ ret = PTR_ERR(key_ref);
/* treat lack or presence of a negative key the same */
if (ret == -EAGAIN)
@@ -616,26 +623,26 @@ long keyctl_keyring_search(key_serial_t ringid,
}
/* link the resulting key to the destination keyring if we can */
- if (dest) {
+ if (dest_ref) {
ret = -EACCES;
- if (!key_permission(key, KEY_LINK))
+ if (!key_permission(key_ref, KEY_LINK))
goto error6;
- ret = key_link(dest, key);
+ ret = key_link(key_ref_to_ptr(dest_ref), key_ref_to_ptr(key_ref));
if (ret < 0)
goto error6;
}
- ret = key->serial;
+ ret = key_ref_to_ptr(key_ref)->serial;
error6:
- key_put(key);
+ key_ref_put(key_ref);
error5:
key_type_put(ktype);
error4:
- key_put(dest);
+ key_ref_put(dest_ref);
error3:
- key_put(keyring);
+ key_ref_put(keyring_ref);
error2:
kfree(description);
error:
@@ -645,16 +652,6 @@ long keyctl_keyring_search(key_serial_t ringid,
/*****************************************************************************/
/*
- * see if the key we're looking at is the target key
- */
-static int keyctl_read_key_same(const struct key *key, const void *target)
-{
- return key == target;
-
-} /* end keyctl_read_key_same() */
-
-/*****************************************************************************/
-/*
* read a user key's payload
* - the keyring must be readable or the key must be searchable from the
* process's keyrings
@@ -665,38 +662,33 @@ static int keyctl_read_key_same(const struct key *key, const void *target)
*/
long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
{
- struct key *key, *skey;
+ struct key *key;
+ key_ref_t key_ref;
long ret;
/* find the key first */
- key = lookup_user_key(NULL, keyid, 0, 0, 0);
- if (!IS_ERR(key)) {
- /* see if we can read it directly */
- if (key_permission(key, KEY_READ))
- goto can_read_key;
-
- /* we can't; see if it's searchable from this process's
- * keyrings
- * - we automatically take account of the fact that it may be
- * dangling off an instantiation key
- */
- skey = search_process_keyrings(key->type, key,
- keyctl_read_key_same, current);
- if (!IS_ERR(skey))
- goto can_read_key2;
-
- ret = PTR_ERR(skey);
- if (ret == -EAGAIN)
- ret = -EACCES;
- goto error2;
+ key_ref = lookup_user_key(NULL, keyid, 0, 0, 0);
+ if (IS_ERR(key_ref)) {
+ ret = -ENOKEY;
+ goto error;
}
- ret = -ENOKEY;
- goto error;
+ key = key_ref_to_ptr(key_ref);
+
+ /* see if we can read it directly */
+ if (key_permission(key_ref, KEY_READ))
+ goto can_read_key;
+
+ /* we can't; see if it's searchable from this process's keyrings
+ * - we automatically take account of the fact that it may be
+ * dangling off an instantiation key
+ */
+ if (!is_key_possessed(key_ref)) {
+ ret = -EACCES;
+ goto error2;
+ }
/* the key is probably readable - now try to read it */
- can_read_key2:
- key_put(skey);
can_read_key:
ret = key_validate(key);
if (ret == 0) {
@@ -727,18 +719,21 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
{
struct key *key;
+ key_ref_t key_ref;
long ret;
ret = 0;
if (uid == (uid_t) -1 && gid == (gid_t) -1)
goto error;
- key = lookup_user_key(NULL, id, 1, 1, 0);
- if (IS_ERR(key)) {
- ret = PTR_ERR(key);
+ key_ref = lookup_user_key(NULL, id, 1, 1, 0);
+ if (IS_ERR(key_ref)) {
+ ret = PTR_ERR(key_ref);
goto error;
}
+ key = key_ref_to_ptr(key_ref);
+
/* make the changes with the locks held to prevent chown/chown races */
ret = -EACCES;
down_write(&key->sem);
@@ -784,18 +779,21 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
{
struct key *key;
+ key_ref_t key_ref;
long ret;
ret = -EINVAL;
- if (perm & ~(KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
+ if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
goto error;
- key = lookup_user_key(NULL, id, 1, 1, 0);
- if (IS_ERR(key)) {
- ret = PTR_ERR(key);
+ key_ref = lookup_user_key(NULL, id, 1, 1, 0);
+ if (IS_ERR(key_ref)) {
+ ret = PTR_ERR(key_ref);
goto error;
}
+ key = key_ref_to_ptr(key_ref);
+
/* make the changes with the locks held to prevent chown/chmod races */
ret = -EACCES;
down_write(&key->sem);
@@ -824,7 +822,8 @@ long keyctl_instantiate_key(key_serial_t id,
key_serial_t ringid)
{
struct request_key_auth *rka;
- struct key *instkey, *keyring;
+ struct key *instkey;
+ key_ref_t keyring_ref;
void *payload;
long ret;
@@ -857,21 +856,21 @@ long keyctl_instantiate_key(key_serial_t id,
/* find the destination keyring amongst those belonging to the
* requesting task */
- keyring = NULL;
+ keyring_ref = NULL;
if (ringid) {
- keyring = lookup_user_key(rka->context, ringid, 1, 0,
- KEY_WRITE);
- if (IS_ERR(keyring)) {
- ret = PTR_ERR(keyring);
+ keyring_ref = lookup_user_key(rka->context, ringid, 1, 0,
+ KEY_WRITE);
+ if (IS_ERR(keyring_ref)) {
+ ret = PTR_ERR(keyring_ref);
goto error3;
}
}
/* instantiate the key and link it into a keyring */
ret = key_instantiate_and_link(rka->target_key, payload, plen,
- keyring, instkey);
+ key_ref_to_ptr(keyring_ref), instkey);
- key_put(keyring);
+ key_ref_put(keyring_ref);
error3:
key_put(instkey);
error2:
@@ -889,7 +888,8 @@ long keyctl_instantiate_key(key_serial_t id,
long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
{
struct request_key_auth *rka;
- struct key *instkey, *keyring;
+ struct key *instkey;
+ key_ref_t keyring_ref;
long ret;
/* find the instantiation authorisation key */
@@ -903,19 +903,20 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
/* find the destination keyring if present (which must also be
* writable) */
- keyring = NULL;
+ keyring_ref = NULL;
if (ringid) {
- keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
- if (IS_ERR(keyring)) {
- ret = PTR_ERR(keyring);
+ keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+ if (IS_ERR(keyring_ref)) {
+ ret = PTR_ERR(keyring_ref);
goto error2;
}
}
/* instantiate the key and link it into a keyring */
- ret = key_negate_and_link(rka->target_key, timeout, keyring, instkey);
+ ret = key_negate_and_link(rka->target_key, timeout,
+ key_ref_to_ptr(keyring_ref), instkey);
- key_put(keyring);
+ key_ref_put(keyring_ref);
error2:
key_put(instkey);
error:
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 9c208c756df8..0639396dd441 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -309,7 +309,7 @@ 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_USR_ALL, not_in_quota);
if (!IS_ERR(keyring)) {
ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
@@ -333,12 +333,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;
@@ -347,29 +348,33 @@ 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))
+ key_ref = ERR_PTR(-EACCES);
+ if (!key_task_permission(keyring_ref, context, KEY_SEARCH))
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;
@@ -397,7 +402,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))
continue;
/* we set a different error code if we find a negative key */
@@ -411,7 +417,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)
@@ -423,7 +429,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))
continue;
/* stack the current position */
@@ -438,7 +445,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--;
@@ -447,16 +454,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() */
@@ -469,9 +478,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);
@@ -488,15 +497,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);
@@ -507,21 +520,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) &&
!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() */
@@ -603,7 +616,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))
continue;
/* found a potential candidate, but we still need to
diff --git a/security/keys/permission.c b/security/keys/permission.c
new file mode 100644
index 000000000000..03db073ba45c
--- /dev/null
+++ b/security/keys/permission.c
@@ -0,0 +1,70 @@
+/* permission.c: key permission determination
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.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
+ */
+int key_task_permission(const key_ref_t key_ref,
+ struct task_struct *context,
+ key_perm_t perm)
+{
+ struct key *key;
+ key_perm_t kperm;
+ int ret;
+
+ key = key_ref_to_ptr(key_ref);
+
+ /* use the second 8-bits of permissions for keys the caller owns */
+ if (key->uid == context->fsuid) {
+ kperm = key->perm >> 16;
+ goto use_these_perms;
+ }
+
+ /* use the third 8-bits of permissions for keys the caller has a group
+ * membership in common with */
+ if (key->gid != -1 && key->perm & KEY_GRP_ALL) {
+ if (key->gid == context->fsgid) {
+ kperm = key->perm >> 8;
+ goto use_these_perms;
+ }
+
+ task_lock(context);
+ ret = groups_search(context->group_info, key->gid);
+ task_unlock(context);
+
+ if (ret) {
+ kperm = key->perm >> 8;
+ goto use_these_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
+ */
+ if (is_key_possessed(key_ref))
+ kperm |= key->perm >> 24;
+
+ kperm = kperm & perm & KEY_ALL;
+
+ return kperm == perm;
+
+} /* end key_task_permission() */
+
+EXPORT_SYMBOL(key_task_permission);
diff --git a/security/keys/proc.c b/security/keys/proc.c
index c55cf1fd0826..12b750e51fbf 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -167,7 +167,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
#define showflag(KEY, LETTER, FLAG) \
(test_bit(FLAG, &(KEY)->flags) ? LETTER : '-')
- seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %06x %5d %5d %-9.9s ",
+ seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ",
key->serial,
showflag(key, 'I', KEY_FLAG_INSTANTIATED),
showflag(key, 'R', KEY_FLAG_REVOKED),
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index c089f78fb94e..d42d2158ce13 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -39,7 +39,7 @@ struct key root_user_keyring = {
.type = &key_type_keyring,
.user = &root_key_user,
.sem = __RWSEM_INITIALIZER(root_user_keyring.sem),
- .perm = KEY_USR_ALL,
+ .perm = KEY_POS_ALL | KEY_USR_ALL,
.flags = 1 << KEY_FLAG_INSTANTIATED,
.description = "_uid.0",
#ifdef KEY_DEBUGGING
@@ -54,7 +54,7 @@ struct key root_session_keyring = {
.type = &key_type_keyring,
.user = &root_key_user,
.sem = __RWSEM_INITIALIZER(root_session_keyring.sem),
- .perm = KEY_USR_ALL,
+ .perm = KEY_POS_ALL | KEY_USR_ALL,
.flags = 1 << KEY_FLAG_INSTANTIATED,
.description = "_uid_ses.0",
#ifdef KEY_DEBUGGING
@@ -98,7 +98,7 @@ int alloc_uid_keyring(struct user_struct *user)
user->session_keyring = session_keyring;
ret = 0;
- error:
+error:
return ret;
} /* end alloc_uid_keyring() */
@@ -156,7 +156,7 @@ int install_thread_keyring(struct task_struct *tsk)
ret = 0;
key_put(old);
- error:
+error:
return ret;
} /* end install_thread_keyring() */
@@ -193,7 +193,7 @@ int install_process_keyring(struct task_struct *tsk)
}
ret = 0;
- error:
+error:
return ret;
} /* end install_process_keyring() */
@@ -236,7 +236,7 @@ static int install_session_keyring(struct task_struct *tsk,
/* we're using RCU on the pointer */
synchronize_rcu();
key_put(old);
- error:
+error:
return ret;
} /* end install_session_keyring() */
@@ -376,13 +376,13 @@ void key_fsgid_changed(struct task_struct *tsk)
* - we return -EAGAIN if we didn't find any matching key
* - we return -ENOKEY if we found only negative matching keys
*/
-struct key *search_process_keyrings(struct key_type *type,
- const void *description,
- key_match_func_t match,
- struct task_struct *context)
+key_ref_t search_process_keyrings(struct key_type *type,
+ const void *description,
+ key_match_func_t match,
+ struct task_struct *context)
{
struct request_key_auth *rka;
- struct key *key, *ret, *err, *instkey;
+ key_ref_t key_ref, ret, err, instkey_ref;
/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
* searchable, but we failed to find a key or we found a negative key;
@@ -391,46 +391,48 @@ struct key *search_process_keyrings(struct key_type *type,
*
* in terms of priority: success > -ENOKEY > -EAGAIN > other error
*/
- key = NULL;
+ key_ref = NULL;
ret = NULL;
err = ERR_PTR(-EAGAIN);
/* search the thread keyring first */
if (context->thread_keyring) {
- key = keyring_search_aux(context->thread_keyring,
- context, type, description, match);
- if (!IS_ERR(key))
+ key_ref = keyring_search_aux(
+ make_key_ref(context->thread_keyring, 1),
+ context, type, description, match);
+ if (!IS_ERR(key_ref))
goto found;
- switch (PTR_ERR(key)) {
+ switch (PTR_ERR(key_ref)) {
case -EAGAIN: /* no key */
if (ret)
break;
case -ENOKEY: /* negative key */
- ret = key;
+ ret = key_ref;
break;
default:
- err = key;
+ err = key_ref;
break;
}
}
/* search the process keyring second */
if (context->signal->process_keyring) {
- key = keyring_search_aux(context->signal->process_keyring,
- context, type, description, match);
- if (!IS_ERR(key))
+ key_ref = keyring_search_aux(
+ make_key_ref(context->signal->process_keyring, 1),
+ context, type, description, match);
+ if (!IS_ERR(key_ref))
goto found;
- switch (PTR_ERR(key)) {
+ switch (PTR_ERR(key_ref)) {
case -EAGAIN: /* no key */
if (ret)
break;
case -ENOKEY: /* negative key */
- ret = key;
+ ret = key_ref;
break;
default:
- err = key;
+ err = key_ref;
break;
}
}
@@ -438,23 +440,25 @@ struct key *search_process_keyrings(struct key_type *type,
/* search the session keyring */
if (context->signal->session_keyring) {
rcu_read_lock();
- key = keyring_search_aux(
- rcu_dereference(context->signal->session_keyring),
+ key_ref = keyring_search_aux(
+ make_key_ref(rcu_dereference(
+ context->signal->session_keyring),
+ 1),
context, type, description, match);
rcu_read_unlock();
- if (!IS_ERR(key))
+ if (!IS_ERR(key_ref))
goto found;
- switch (PTR_ERR(key)) {
+ switch (PTR_ERR(key_ref)) {
case -EAGAIN: /* no key */
if (ret)
break;
case -ENOKEY: /* negative key */
- ret = key;
+ ret = key_ref;
break;
default:
- err = key;
+ err = key_ref;
break;
}
@@ -465,51 +469,54 @@ struct key *search_process_keyrings(struct key_type *type,
goto no_key;
rcu_read_lock();
- instkey = __keyring_search_one(
- rcu_dereference(context->signal->session_keyring),
+ instkey_ref = __keyring_search_one(
+ make_key_ref(rcu_dereference(
+ context->signal->session_keyring),
+ 1),
&key_type_request_key_auth, NULL, 0);
rcu_read_unlock();
- if (IS_ERR(instkey))
+ if (IS_ERR(instkey_ref))
goto no_key;
- rka = instkey->payload.data;
+ rka = key_ref_to_ptr(instkey_ref)->payload.data;
- key = search_process_keyrings(type, description, match,
- rka->context);
- key_put(instkey);
+ key_ref = search_process_keyrings(type, description, match,
+ rka->context);
+ key_ref_put(instkey_ref);
- if (!IS_ERR(key))
+ if (!IS_ERR(key_ref))
goto found;
- switch (PTR_ERR(key)) {
+ switch (PTR_ERR(key_ref)) {
case -EAGAIN: /* no key */
if (ret)
break;
case -ENOKEY: /* negative key */
- ret = key;
+ ret = key_ref;
break;
default:
- err = key;
+ err = key_ref;
break;
}
}
/* or search the user-session keyring */
else {
- key = keyring_search_aux(context->user->session_keyring,
- context, type, description, match);
- if (!IS_ERR(key))
+ key_ref = keyring_search_aux(
+ make_key_ref(context->user->session_keyring, 1),
+ context, type, description, match);
+ if (!IS_ERR(key_ref))
goto found;
- switch (PTR_ERR(key)) {
+ switch (PTR_ERR(key_ref)) {
case -EAGAIN: /* no key */
if (ret)
break;
case -ENOKEY: /* negative key */
- ret = key;
+ ret = key_ref;
break;
default:
- err = key;
+ err = key_ref;
break;
}
}
@@ -517,29 +524,40 @@ struct key *search_process_keyrings(struct key_type *type,
no_key:
/* no key - decide on the error we're going to go for */
- key = ret ? ret : err;
+ key_ref = ret ? ret : err;
found:
- return key;
+ return key_ref;
} /* end search_process_keyrings() */
/*****************************************************************************/
/*
+ * see if the key we're looking at is the target key
+ */
+static int lookup_user_key_possessed(const struct key *key, const void *target)
+{
+ return key == target;
+
+} /* end lookup_user_key_possessed() */
+
+/*****************************************************************************/
+/*
* lookup a key given a key ID from userspace with a given permissions mask
* - don't create special keyrings unless so requested
* - partially constructed keys aren't found unless requested
*/
-struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
- int create, int partial, key_perm_t perm)
+key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
+ int create, int partial, key_perm_t perm)
{
+ key_ref_t key_ref, skey_ref;
struct key *key;
int ret;
if (!context)
context = current;
- key = ERR_PTR(-ENOKEY);
+ key_ref = ERR_PTR(-ENOKEY);
switch (id) {
case KEY_SPEC_THREAD_KEYRING:
@@ -556,6 +574,7 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
key = context->thread_keyring;
atomic_inc(&key->usage);
+ key_ref = make_key_ref(key, 1);
break;
case KEY_SPEC_PROCESS_KEYRING:
@@ -572,6 +591,7 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
key = context->signal->process_keyring;
atomic_inc(&key->usage);
+ key_ref = make_key_ref(key, 1);
break;
case KEY_SPEC_SESSION_KEYRING:
@@ -579,7 +599,7 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
/* always install a session keyring upon access if one
* doesn't exist yet */
ret = install_session_keyring(
- context, context->user->session_keyring);
+ context, context->user->session_keyring);
if (ret < 0)
goto error;
}
@@ -588,16 +608,19 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
key = rcu_dereference(context->signal->session_keyring);
atomic_inc(&key->usage);
rcu_read_unlock();
+ key_ref = make_key_ref(key, 1);
break;
case KEY_SPEC_USER_KEYRING:
key = context->user->uid_keyring;
atomic_inc(&key->usage);
+ key_ref = make_key_ref(key, 1);
break;
case KEY_SPEC_USER_SESSION_KEYRING:
key = context->user->session_keyring;
atomic_inc(&key->usage);
+ key_ref = make_key_ref(key, 1);
break;
case KEY_SPEC_GROUP_KEYRING:
@@ -606,13 +629,28 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
goto error;
default:
- key = ERR_PTR(-EINVAL);
+ key_ref = ERR_PTR(-EINVAL);
if (id < 1)
goto error;
key = key_lookup(id);
- if (IS_ERR(key))
+ if (IS_ERR(key)) {
+ key_ref = ERR_PTR(PTR_ERR(key));
goto error;
+ }
+
+ key_ref = make_key_ref(key, 0);
+
+ /* check to see if we possess the key */
+ skey_ref = search_process_keyrings(key->type, key,
+ lookup_user_key_possessed,
+ current);
+
+ if (!IS_ERR(skey_ref)) {
+ key_put(key);
+ key_ref = skey_ref;
+ }
+
break;
}
@@ -630,15 +668,15 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
/* check the permissions */
ret = -EACCES;
- if (!key_task_permission(key, context, perm))
+ if (!key_task_permission(key_ref, context, perm))
goto invalid_key;
- error:
- return key;
+error:
+ return key_ref;
- invalid_key:
- key_put(key);
- key = ERR_PTR(ret);
+invalid_key:
+ key_ref_put(key_ref);
+ key_ref = ERR_PTR(ret);
goto error;
} /* end lookup_user_key() */
@@ -694,9 +732,9 @@ long join_session_keyring(const char *name)
ret = keyring->serial;
key_put(keyring);
- error2:
+error2:
up(&key_session_sem);
- error:
+error:
return ret;
} /* end join_session_keyring() */
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 90c1506d007c..5cc4bba70db6 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -7,6 +7,8 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
+ *
+ * See Documentation/keys-request-key.txt
*/
#include <linux/module.h>
@@ -129,7 +131,7 @@ static struct key *__request_key_construction(struct key_type *type,
/* create a key and add it to the queue */
key = key_alloc(type, description,
- current->fsuid, current->fsgid, KEY_USR_ALL, 0);
+ current->fsuid, current->fsgid, KEY_POS_ALL, 0);
if (IS_ERR(key))
goto alloc_failed;
@@ -365,14 +367,24 @@ struct key *request_key_and_link(struct key_type *type,
{
struct key_user *user;
struct key *key;
+ key_ref_t key_ref;
kenter("%s,%s,%s,%p",
type->name, description, callout_info, dest_keyring);
/* search all the process keyrings for a key */
- key = search_process_keyrings(type, description, type->match, current);
+ key_ref = search_process_keyrings(type, description, type->match,
+ current);
+
+ kdebug("search 1: %p", key_ref);
- if (PTR_ERR(key) == -EAGAIN) {
+ if (!IS_ERR(key_ref)) {
+ key = key_ref_to_ptr(key_ref);
+ }
+ else if (PTR_ERR(key_ref) != -EAGAIN) {
+ key = ERR_PTR(PTR_ERR(key_ref));
+ }
+ else {
/* the search failed, but the keyrings were searchable, so we
* should consult userspace if we can */
key = ERR_PTR(-ENOKEY);
@@ -384,7 +396,7 @@ struct key *request_key_and_link(struct key_type *type,
if (!user)
goto nomem;
- do {
+ for (;;) {
if (signal_pending(current))
goto interrupted;
@@ -397,10 +409,22 @@ struct key *request_key_and_link(struct key_type *type,
/* someone else made the key we want, so we need to
* search again as it might now be available to us */
- key = search_process_keyrings(type, description,
- type->match, current);
+ key_ref = search_process_keyrings(type, description,
+ type->match,
+ current);
+
+ kdebug("search 2: %p", key_ref);
- } while (PTR_ERR(key) == -EAGAIN);
+ if (!IS_ERR(key_ref)) {
+ key = key_ref_to_ptr(key_ref);
+ break;
+ }
+
+ if (PTR_ERR(key_ref) != -EAGAIN) {
+ key = ERR_PTR(PTR_ERR(key_ref));
+ break;
+ }
+ }
key_user_put(user);
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index f22264632229..a8e4069d48cb 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -7,6 +7,8 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
+ *
+ * See Documentation/keys-request-key.txt
*/
#include <linux/module.h>
@@ -96,6 +98,7 @@ static void request_key_auth_destroy(struct key *key)
kenter("{%d}", key->serial);
key_put(rka->target_key);
+ kfree(rka);
} /* end request_key_auth_destroy() */
@@ -126,7 +129,7 @@ struct key *request_key_auth_new(struct key *target, struct key **_rkakey)
rkakey = key_alloc(&key_type_request_key_auth, desc,
current->fsuid, current->fsgid,
- KEY_USR_VIEW, 1);
+ KEY_POS_VIEW | KEY_USR_VIEW, 1);
if (IS_ERR(rkakey)) {
key_put(keyring);
kleave("= %ld", PTR_ERR(rkakey));