Commit 664cceb0 authored by David Howells's avatar David Howells Committed by Linus Torvalds

[PATCH] Keys: Add possessor permissions to keys [try #3]

The attached patch adds extra permission grants to keys for the possessor of a
key in addition to the owner, group and other permissions bits. This makes
SUID binaries easier to support without going as far as labelling keys and key
targets using the LSM facilities.

This patch adds a second "pointer type" to key structures (struct key_ref *)
that can have the bottom bit of the address set to indicate the possession of
a key. This is propagated through searches from the keyring to the discovered
key. It has been made a separate type so that the compiler can spot attempts
to dereference a potentially incorrect pointer.

The "possession" attribute can't be attached to a key structure directly as
it's not an intrinsic property of a key.

Pointers to keys have been replaced with struct key_ref *'s wherever
possession information needs to be passed through.

This does assume that the bottom bit of the pointer will always be zero on
return from kmem_cache_alloc().

The key reference type has been made into a typedef so that at least it can be
located in the sources, even though it's basically a pointer to an undefined
type. I've also renamed the accessor functions to be more useful, and all
reference variables should now end in "_ref".
Signed-Off-By: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 5134fc15
...@@ -195,8 +195,8 @@ KEY ACCESS PERMISSIONS ...@@ -195,8 +195,8 @@ KEY ACCESS PERMISSIONS
====================== ======================
Keys have an owner user ID, a group access ID, and a permissions mask. The mask Keys have an owner user ID, a group access ID, and a permissions mask. The mask
has up to eight bits each for user, group and other access. Only five of each has up to eight bits each for possessor, user, group and other access. Only
set of eight bits are defined. These permissions granted are: five of each set of eight bits are defined. These permissions granted are:
(*) View (*) View
...@@ -242,15 +242,15 @@ about the status of the key service: ...@@ -242,15 +242,15 @@ about the status of the key service:
this way: this way:
SERIAL FLAGS USAGE EXPY PERM UID GID TYPE DESCRIPTION: SUMMARY SERIAL FLAGS USAGE EXPY PERM UID GID TYPE DESCRIPTION: SUMMARY
00000001 I----- 39 perm 1f0000 0 0 keyring _uid_ses.0: 1/4 00000001 I----- 39 perm 1f1f0000 0 0 keyring _uid_ses.0: 1/4
00000002 I----- 2 perm 1f0000 0 0 keyring _uid.0: empty 00000002 I----- 2 perm 1f1f0000 0 0 keyring _uid.0: empty
00000007 I----- 1 perm 1f0000 0 0 keyring _pid.1: empty 00000007 I----- 1 perm 1f1f0000 0 0 keyring _pid.1: empty
0000018d I----- 1 perm 1f0000 0 0 keyring _pid.412: empty 0000018d I----- 1 perm 1f1f0000 0 0 keyring _pid.412: empty
000004d2 I--Q-- 1 perm 1f0000 32 -1 keyring _uid.32: 1/4 000004d2 I--Q-- 1 perm 1f1f0000 32 -1 keyring _uid.32: 1/4
000004d3 I--Q-- 3 perm 1f0000 32 -1 keyring _uid_ses.32: empty 000004d3 I--Q-- 3 perm 1f1f0000 32 -1 keyring _uid_ses.32: empty
00000892 I--QU- 1 perm 1f0000 0 0 user metal:copper: 0 00000892 I--QU- 1 perm 1f000000 0 0 user metal:copper: 0
00000893 I--Q-N 1 35s 1f0000 0 0 user metal:silver: 0 00000893 I--Q-N 1 35s 1f1f0000 0 0 user metal:silver: 0
00000894 I--Q-- 1 10h 1f0000 0 0 user metal:gold: 0 00000894 I--Q-- 1 10h 001f0000 0 0 user metal:gold: 0
The flags are: The flags are:
...@@ -637,6 +637,34 @@ call, and the key released upon close. How to deal with conflicting keys due to ...@@ -637,6 +637,34 @@ call, and the key released upon close. How to deal with conflicting keys due to
two different users opening the same file is left to the filesystem author to two different users opening the same file is left to the filesystem author to
solve. solve.
Note that there are two different types of pointers to keys that may be
encountered:
(*) struct key *
This simply points to the key structure itself. Key structures will be at
least four-byte aligned.
(*) key_ref_t
This is equivalent to a struct key *, but the least significant bit is set
if the caller "possesses" the key. By "possession" it is meant that the
calling processes has a searchable link to the key from one of its
keyrings. There are three functions for dealing with these:
key_ref_t make_key_ref(const struct key *key,
unsigned long possession);
struct key *key_ref_to_ptr(const key_ref_t key_ref);
unsigned long is_key_possessed(const key_ref_t key_ref);
The first function constructs a key reference from a key pointer and
possession information (which must be 0 or 1 and not any other value).
The second function retrieves the key pointer from a reference and the
third retrieves the possession flag.
When accessing a key's payload contents, certain precautions must be taken to When accessing a key's payload contents, certain precautions must be taken to
prevent access vs modification races. See the section "Notes on accessing prevent access vs modification races. See the section "Notes on accessing
payload contents" for more information. payload contents" for more information.
...@@ -665,7 +693,11 @@ payload contents" for more information. ...@@ -665,7 +693,11 @@ payload contents" for more information.
void key_put(struct key *key); void key_put(struct key *key);
This can be called from interrupt context. If CONFIG_KEYS is not set then Or:
void key_ref_put(key_ref_t key_ref);
These can be called from interrupt context. If CONFIG_KEYS is not set then
the argument will not be parsed. the argument will not be parsed.
...@@ -689,13 +721,17 @@ payload contents" for more information. ...@@ -689,13 +721,17 @@ payload contents" for more information.
(*) If a keyring was found in the search, this can be further searched by: (*) If a keyring was found in the search, this can be further searched by:
struct key *keyring_search(struct key *keyring, key_ref_t keyring_search(key_ref_t keyring_ref,
const struct key_type *type, const struct key_type *type,
const char *description) const char *description)
This searches the keyring tree specified for a matching key. Error ENOKEY This searches the keyring tree specified for a matching key. Error ENOKEY
is returned upon failure. If successful, the returned key will need to be is returned upon failure (use IS_ERR/PTR_ERR to determine). If successful,
released. the returned key will need to be released.
The possession attribute from the keyring reference is used to control
access through the permissions mask and is propagated to the returned key
reference pointer if successful.
(*) To check the validity of a key, this function can be called: (*) To check the validity of a key, this function can be called:
...@@ -732,7 +768,7 @@ More complex payload contents must be allocated and a pointer to them set in ...@@ -732,7 +768,7 @@ More complex payload contents must be allocated and a pointer to them set in
key->payload.data. One of the following ways must be selected to access the key->payload.data. One of the following ways must be selected to access the
data: data:
(1) Unmodifyable key type. (1) Unmodifiable key type.
If the key type does not have a modify method, then the key's payload can If the key type does not have a modify method, then the key's payload can
be accessed without any form of locking, provided that it's known to be be accessed without any form of locking, provided that it's known to be
......
...@@ -42,11 +42,14 @@ struct keyring_list { ...@@ -42,11 +42,14 @@ struct keyring_list {
/* /*
* check to see whether permission is granted to use a key in the desired way * check to see whether permission is granted to use a key in the desired way
*/ */
static inline int key_permission(const struct key *key, key_perm_t perm) static inline int key_permission(const key_ref_t key_ref, key_perm_t perm)
{ {
struct key *key = key_ref_to_ptr(key_ref);
key_perm_t kperm; key_perm_t kperm;
if (key->uid == current->fsuid) if (is_key_possessed(key_ref))
kperm = key->perm >> 24;
else if (key->uid == current->fsuid)
kperm = key->perm >> 16; kperm = key->perm >> 16;
else if (key->gid != -1 && else if (key->gid != -1 &&
key->perm & KEY_GRP_ALL && key->perm & KEY_GRP_ALL &&
...@@ -65,11 +68,14 @@ static inline int key_permission(const struct key *key, key_perm_t perm) ...@@ -65,11 +68,14 @@ static inline int key_permission(const struct key *key, key_perm_t perm)
* check to see whether permission is granted to use a key in at least one of * check to see whether permission is granted to use a key in at least one of
* the desired ways * the desired ways
*/ */
static inline int key_any_permission(const struct key *key, key_perm_t perm) static inline int key_any_permission(const key_ref_t key_ref, key_perm_t perm)
{ {
struct key *key = key_ref_to_ptr(key_ref);
key_perm_t kperm; key_perm_t kperm;
if (key->uid == current->fsuid) if (is_key_possessed(key_ref))
kperm = key->perm >> 24;
else if (key->uid == current->fsuid)
kperm = key->perm >> 16; kperm = key->perm >> 16;
else if (key->gid != -1 && else if (key->gid != -1 &&
key->perm & KEY_GRP_ALL && key->perm & KEY_GRP_ALL &&
...@@ -94,13 +100,17 @@ static inline int key_task_groups_search(struct task_struct *tsk, gid_t gid) ...@@ -94,13 +100,17 @@ static inline int key_task_groups_search(struct task_struct *tsk, gid_t gid)
return ret; return ret;
} }
static inline int key_task_permission(const struct key *key, static inline int key_task_permission(const key_ref_t key_ref,
struct task_struct *context, struct task_struct *context,
key_perm_t perm) key_perm_t perm)
{ {
struct key *key = key_ref_to_ptr(key_ref);
key_perm_t kperm; key_perm_t kperm;
if (key->uid == context->fsuid) { if (is_key_possessed(key_ref)) {
kperm = key->perm >> 24;
}
else if (key->uid == context->fsuid) {
kperm = key->perm >> 16; kperm = key->perm >> 16;
} }
else if (key->gid != -1 && else if (key->gid != -1 &&
...@@ -121,7 +131,7 @@ static inline int key_task_permission(const struct key *key, ...@@ -121,7 +131,7 @@ static inline int key_task_permission(const struct key *key,
} }
extern struct key *lookup_user_key(struct task_struct *context, extern key_ref_t lookup_user_key(struct task_struct *context,
key_serial_t id, int create, int partial, key_serial_t id, int create, int partial,
key_perm_t perm); key_perm_t perm);
......
...@@ -35,11 +35,18 @@ struct key; ...@@ -35,11 +35,18 @@ struct key;
#undef KEY_DEBUGGING #undef KEY_DEBUGGING
#define KEY_USR_VIEW 0x00010000 /* user can view a key's attributes */ #define KEY_POS_VIEW 0x01000000 /* possessor can view a key's attributes */
#define KEY_USR_READ 0x00020000 /* user can read key payload / view keyring */ #define KEY_POS_READ 0x02000000 /* possessor can read key payload / view keyring */
#define KEY_USR_WRITE 0x00040000 /* user can update key payload / add link to keyring */ #define KEY_POS_WRITE 0x04000000 /* possessor can update key payload / add link to keyring */
#define KEY_USR_SEARCH 0x00080000 /* user can find a key in search / search a keyring */ #define KEY_POS_SEARCH 0x08000000 /* possessor can find a key in search / search a keyring */
#define KEY_USR_LINK 0x00100000 /* user can create a link to a key/keyring */ #define KEY_POS_LINK 0x10000000 /* possessor can create a link to a key/keyring */
#define KEY_POS_ALL 0x1f000000
#define KEY_USR_VIEW 0x00010000 /* user permissions... */
#define KEY_USR_READ 0x00020000
#define KEY_USR_WRITE 0x00040000
#define KEY_USR_SEARCH 0x00080000
#define KEY_USR_LINK 0x00100000
#define KEY_USR_ALL 0x001f0000 #define KEY_USR_ALL 0x001f0000
#define KEY_GRP_VIEW 0x00000100 /* group permissions... */ #define KEY_GRP_VIEW 0x00000100 /* group permissions... */
...@@ -65,6 +72,38 @@ struct key_owner; ...@@ -65,6 +72,38 @@ struct key_owner;
struct keyring_list; struct keyring_list;
struct keyring_name; struct keyring_name;
/*****************************************************************************/
/*
* key reference with possession attribute handling
*
* NOTE! key_ref_t is a typedef'd pointer to a type that is not actually
* defined. This is because we abuse the bottom bit of the reference to carry a
* flag to indicate whether the calling process possesses that key in one of
* its keyrings.
*
* the key_ref_t has been made a separate type so that the compiler can reject
* attempts to dereference it without proper conversion.
*
* the three functions are used to assemble and disassemble references
*/
typedef struct __key_reference_with_attributes *key_ref_t;
static inline key_ref_t make_key_ref(const struct key *key,
unsigned long possession)
{
return (key_ref_t) ((unsigned long) key | possession);
}
static inline struct key *key_ref_to_ptr(const key_ref_t key_ref)
{
return (struct key *) ((unsigned long) key_ref & ~1UL);
}
static inline unsigned long is_key_possessed(const key_ref_t key_ref)
{
return (unsigned long) key_ref & 1UL;
}
/*****************************************************************************/ /*****************************************************************************/
/* /*
* authentication token / access credential / keyring * authentication token / access credential / keyring
...@@ -215,20 +254,25 @@ static inline struct key *key_get(struct key *key) ...@@ -215,20 +254,25 @@ static inline struct key *key_get(struct key *key)
return key; return key;
} }
static inline void key_ref_put(key_ref_t key_ref)
{
key_put(key_ref_to_ptr(key_ref));
}
extern struct key *request_key(struct key_type *type, extern struct key *request_key(struct key_type *type,
const char *description, const char *description,
const char *callout_info); const char *callout_info);
extern int key_validate(struct key *key); extern int key_validate(struct key *key);
extern struct key *key_create_or_update(struct key *keyring, extern key_ref_t key_create_or_update(key_ref_t keyring,
const char *type, const char *type,
const char *description, const char *description,
const void *payload, const void *payload,
size_t plen, size_t plen,
int not_in_quota); int not_in_quota);
extern int key_update(struct key *key, extern int key_update(key_ref_t key,
const void *payload, const void *payload,
size_t plen); size_t plen);
...@@ -243,7 +287,7 @@ extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, ...@@ -243,7 +287,7 @@ extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
extern int keyring_clear(struct key *keyring); extern int keyring_clear(struct key *keyring);
extern struct key *keyring_search(struct key *keyring, extern key_ref_t keyring_search(key_ref_t keyring,
struct key_type *type, struct key_type *type,
const char *description); const char *description);
...@@ -285,6 +329,10 @@ extern void key_init(void); ...@@ -285,6 +329,10 @@ extern void key_init(void);
#define key_serial(k) 0 #define key_serial(k) 0
#define key_get(k) ({ NULL; }) #define key_get(k) ({ NULL; })
#define key_put(k) do { } while(0) #define key_put(k) do { } while(0)
#define key_ref_put(k) do { } while(0)
#define make_key_ref(k) ({ NULL; })
#define key_ref_to_ptr(k) ({ NULL; })
#define is_key_possessed(k) 0
#define alloc_uid_keyring(u) 0 #define alloc_uid_keyring(u) 0
#define switch_uid_keyring(u) do { } while(0) #define switch_uid_keyring(u) do { } while(0)
#define __install_session_keyring(t, k) ({ NULL; }) #define __install_session_keyring(t, k) ({ NULL; })
......
...@@ -71,7 +71,7 @@ extern void keyring_publish_name(struct key *keyring); ...@@ -71,7 +71,7 @@ extern void keyring_publish_name(struct key *keyring);
extern int __key_link(struct key *keyring, struct key *key); extern int __key_link(struct key *keyring, struct key *key);
extern struct key *__keyring_search_one(struct key *keyring, extern key_ref_t __keyring_search_one(key_ref_t keyring_ref,
const struct key_type *type, const struct key_type *type,
const char *description, const char *description,
key_perm_t perm); key_perm_t perm);
...@@ -81,13 +81,13 @@ extern struct key *keyring_search_instkey(struct key *keyring, ...@@ -81,13 +81,13 @@ extern struct key *keyring_search_instkey(struct key *keyring,
typedef int (*key_match_func_t)(const struct key *, const void *); typedef int (*key_match_func_t)(const struct key *, const void *);
extern struct key *keyring_search_aux(struct key *keyring, extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
struct task_struct *tsk, struct task_struct *tsk,
struct key_type *type, struct key_type *type,
const void *description, const void *description,
key_match_func_t match); key_match_func_t match);
extern struct key *search_process_keyrings(struct key_type *type, extern key_ref_t search_process_keyrings(struct key_type *type,
const void *description, const void *description,
key_match_func_t match, key_match_func_t match,
struct task_struct *tsk); struct task_struct *tsk);
......
...@@ -693,14 +693,15 @@ void key_type_put(struct key_type *ktype) ...@@ -693,14 +693,15 @@ void key_type_put(struct key_type *ktype)
* - the key has an incremented refcount * - the key has an incremented refcount
* - we need to put the key if we get an error * - we need to put the key if we get an error
*/ */
static inline struct key *__key_update(struct key *key, const void *payload, static inline key_ref_t __key_update(key_ref_t key_ref,
size_t plen) const void *payload, size_t plen)
{ {
struct key *key = key_ref_to_ptr(key_ref);
int ret; int ret;
/* need write permission on the key to update it */ /* need write permission on the key to update it */
ret = -EACCES; ret = -EACCES;
if (!key_permission(key, KEY_WRITE)) if (!key_permission(key_ref, KEY_WRITE))
goto error; goto error;
ret = -EEXIST; ret = -EEXIST;
...@@ -719,12 +720,12 @@ static inline struct key *__key_update(struct key *key, const void *payload, ...@@ -719,12 +720,12 @@ static inline struct key *__key_update(struct key *key, const void *payload,
if (ret < 0) if (ret < 0)
goto error; goto error;
out: out:
return key; return key_ref;
error: error:
key_put(key); key_put(key);
key = ERR_PTR(ret); key_ref = ERR_PTR(ret);
goto out; goto out;
} /* end __key_update() */ } /* end __key_update() */
...@@ -734,7 +735,7 @@ static inline struct key *__key_update(struct key *key, const void *payload, ...@@ -734,7 +735,7 @@ 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 * search the specified keyring for a key of the same description; if one is
* found, update it, otherwise add a new one * found, update it, otherwise add a new one
*/ */
struct key *key_create_or_update(struct key *keyring, key_ref_t key_create_or_update(key_ref_t keyring_ref,
const char *type, const char *type,
const char *description, const char *description,
const void *payload, const void *payload,
...@@ -742,44 +743,48 @@ struct key *key_create_or_update(struct key *keyring, ...@@ -742,44 +743,48 @@ struct key *key_create_or_update(struct key *keyring,
int not_in_quota) int not_in_quota)
{ {
struct key_type *ktype; struct key_type *ktype;
struct key *key = NULL; struct key *keyring, *key = NULL;
key_perm_t perm; key_perm_t perm;
key_ref_t key_ref;
int ret; int ret;
key_check(keyring);
/* look up the key type to see if it's one of the registered kernel /* look up the key type to see if it's one of the registered kernel
* types */ * types */
ktype = key_type_lookup(type); ktype = key_type_lookup(type);
if (IS_ERR(ktype)) { if (IS_ERR(ktype)) {
key = ERR_PTR(-ENODEV); key_ref = ERR_PTR(-ENODEV);
goto error; goto error;
} }
ret = -EINVAL; key_ref = ERR_PTR(-EINVAL);
if (!ktype->match || !ktype->instantiate) if (!ktype->match || !ktype->instantiate)
goto error_2; 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 /* search for an existing key of the same type and description in the
* destination keyring * destination keyring
*/ */
down_write(&keyring->sem); key_ref = __keyring_search_one(keyring_ref, ktype, description, 0);
if (!IS_ERR(key_ref))
key = __keyring_search_one(keyring, ktype, description, 0);
if (!IS_ERR(key))
goto found_matching_key; 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 */ /* 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) if (ktype->read)
perm |= KEY_USR_READ; perm |= KEY_POS_READ | KEY_USR_READ;
if (ktype == &key_type_keyring || ktype->update) if (ktype == &key_type_keyring || ktype->update)
perm |= KEY_USR_WRITE; perm |= KEY_USR_WRITE;
...@@ -788,7 +793,7 @@ struct key *key_create_or_update(struct key *keyring, ...@@ -788,7 +793,7 @@ struct key *key_create_or_update(struct key *keyring,
key = key_alloc(ktype, description, current->fsuid, current->fsgid, key = key_alloc(ktype, description, current->fsuid, current->fsgid,
perm, not_in_quota); perm, not_in_quota);
if (IS_ERR(key)) { if (IS_ERR(key)) {
ret = PTR_ERR(key); key_ref = ERR_PTR(PTR_ERR(key));
goto error_3; goto error_3;
} }
...@@ -796,15 +801,18 @@ struct key *key_create_or_update(struct key *keyring, ...@@ -796,15 +801,18 @@ struct key *key_create_or_update(struct key *keyring,
ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL); ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL);
if (ret < 0) { if (ret < 0) {
key_put(key); 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: error_3:
up_write(&keyring->sem); up_write(&keyring->sem);
error_2: error_2:
key_type_put(ktype); key_type_put(ktype);
error: error:
return key; return key_ref;
found_matching_key: found_matching_key:
/* we found a matching key, so we're going to try to update it /* 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, ...@@ -813,7 +821,7 @@ struct key *key_create_or_update(struct key *keyring,
up_write(&keyring->sem); up_write(&keyring->sem);
key_type_put(ktype); key_type_put(ktype);
key = __key_update(key, payload, plen); key_ref = __key_update(key_ref, payload, plen);
goto error; goto error;
} /* end key_create_or_update() */ } /* end key_create_or_update() */
...@@ -824,15 +832,16 @@ EXPORT_SYMBOL(key_create_or_update); ...@@ -824,15 +832,16 @@ EXPORT_SYMBOL(key_create_or_update);
/* /*
* update a key * 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; int ret;
key_check(key); key_check(key);
/* the key must be writable */ /* the key must be writable */
ret = -EACCES; ret = -EACCES;
if (!key_permission(key, KEY_WRITE)) if (!key_permission(key_ref, KEY_WRITE))
goto error; goto error;
/* attempt to update it if supported */ /* attempt to update it if supported */
......
...@@ -34,7 +34,7 @@ asmlinkage long sys_add_key(const char __user *_type, ...@@ -34,7 +34,7 @@ asmlinkage long sys_add_key(const char __user *_type,
size_t plen, size_t plen,
key_serial_t ringid) key_serial_t ringid)
{ {
struct key *keyring, *key; key_ref_t keyring_ref, key_ref;
char type[32], *description; char type[32], *description;
void *payload; void *payload;
long dlen, ret; long dlen, ret;
...@@ -86,25 +86,25 @@ asmlinkage long sys_add_key(const char __user *_type, ...@@ -86,25 +86,25 @@ asmlinkage long sys_add_key(const char __user *_type,
} }
/* find the target keyring (which must be writable) */ /* find the target keyring (which must be writable) */
keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) { if (IS_ERR(keyring_ref)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring_ref);
goto error3; goto error3;
} }
/* create or update the requested key and add it to the target /* create or update the requested key and add it to the target
* keyring */ * keyring */
key = key_create_or_update(keyring, type, description, key_ref = key_create_or_update(keyring_ref, type, description,
payload, plen, 0); payload, plen, 0);
if (!IS_ERR(key)) { if (!IS_ERR(key_ref)) {
ret = key->serial; ret = key_ref_to_ptr(key_ref)->serial;
key_put(key); key_ref_put(key_ref);
} }
else { else {
ret = PTR_ERR(key); ret = PTR_ERR(key_ref);
} }
key_put(keyring); key_ref_put(keyring_ref);
error3: error3:
kfree(payload); kfree(payload);
error2: error2:
...@@ -131,7 +131,8 @@ asmlinkage long sys_request_key(const char __user *_type, ...@@ -131,7 +131,8 @@ asmlinkage long sys_request_key(const char __user *_type,
key_serial_t destringid) key_serial_t destringid)
{ {
struct key_type *ktype; struct key_type *ktype;
struct key *key, *dest; struct key *key;
key_ref_t dest_ref;
char type[32], *description, *callout_info; char type[32], *description, *callout_info;
long dlen, ret; long dlen, ret;
...@@ -187,11 +188,11 @@ asmlinkage long sys_request_key(const char __user *_type, ...@@ -187,11 +188,11 @@ asmlinkage long sys_request_key(const char __user *_type,
} }
/* get the destination keyring if specified */ /* get the destination keyring if specified */
dest = NULL; dest_ref = NULL;
if (destringid) { if (destringid) {
dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE); dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
if (IS_ERR(dest)) { if (IS_ERR(dest_ref)) {
ret = PTR_ERR(dest); ret = PTR_ERR(dest_ref);
goto error3; goto error3;
} }
} }
...@@ -204,7 +205,8 @@ asmlinkage long sys_request_key(const char __user *_type, ...@@ -204,7 +205,8 @@ asmlinkage long sys_request_key(const char __user *_type,
} }
/* do the search */ /* 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)) { if (IS_ERR(key)) {
ret = PTR_ERR(key); ret = PTR_ERR(key);
goto error5; goto error5;
...@@ -216,7 +218,7 @@ asmlinkage long sys_request_key(const char __user *_type, ...@@ -216,7 +218,7 @@ asmlinkage long sys_request_key(const char __user *_type,
error5: error5:
key_type_put(ktype); key_type_put(ktype);
error4: error4:
key_put(dest); key_ref_put(dest_ref);
error3: error3:
kfree(callout_info); kfree(callout_info);
error2: error2:
...@@ -234,17 +236,17 @@ asmlinkage long sys_request_key(const char __user *_type, ...@@ -234,17 +236,17 @@ asmlinkage long sys_request_key(const char __user *_type,
*/ */
long keyctl_get_keyring_ID(key_serial_t id, int create) long keyctl_get_keyring_ID(key_serial_t id, int create)
{ {
struct key *key; key_ref_t key_ref;
long ret; long ret;
key = lookup_user_key(NULL, id, create, 0, KEY_SEARCH); key_ref = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
if (IS_ERR(key)) { if (IS_ERR(key_ref)) {
ret = PTR_ERR(key); ret = PTR_ERR(key_ref);
goto error; goto error;
} }
ret = key->serial; ret = key_ref_to_ptr(key_ref)->serial;
key_put(key); key_ref_put(key_ref);
error: error:
return ret; return ret;
...@@ -302,7 +304,7 @@ long keyctl_update_key(key_serial_t id, ...@@ -302,7 +304,7 @@ long keyctl_update_key(key_serial_t id,
const void __user *_payload, const void __user *_payload,
size_t plen) size_t plen)
{ {
struct key *key; key_ref_t key_ref;
void *payload; void *payload;
long ret; long ret;
...@@ -324,16 +326,16 @@ long keyctl_update_key(key_serial_t id, ...@@ -324,16 +326,16 @@ long keyctl_update_key(key_serial_t id,
} }
/* find the target key (which must be writable) */ /* find the target key (which must be writable) */
key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE); key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
if (IS_ERR(key)) { if (IS_ERR(key_ref)) {
ret = PTR_ERR(key); ret = PTR_ERR(key_ref);
goto error2; goto error2;
} }
/* update the key */ /* 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: error2:
kfree(payload); kfree(payload);
error: error:
...@@ -349,19 +351,19 @@ long keyctl_update_key(key_serial_t id, ...@@ -349,19 +351,19 @@ long keyctl_update_key(key_serial_t id,
*/ */
long keyctl_revoke_key(key_serial_t id) long keyctl_revoke_key(key_serial_t id)
{ {
struct key *key; key_ref_t key_ref;
long ret; long ret;
key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE); key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
if (IS_ERR(key)) { if (IS_ERR(key_ref)) {
ret = PTR_ERR(key); ret = PTR_ERR(key_ref);
goto error; goto error;
} }
key_revoke(key); key_revoke(key_ref_to_ptr(key_ref));
ret = 0; ret = 0;
key_put(key); key_ref_put(key_ref);
error: error:
return ret; return ret;
...@@ -375,18 +377,18 @@ long keyctl_revoke_key(key_serial_t id) ...@@ -375,18 +377,18 @@ long keyctl_revoke_key(key_serial_t id)
*/ */
long keyctl_keyring_clear(key_serial_t ringid) long keyctl_keyring_clear(key_serial_t ringid)
{ {
struct key *keyring; key_ref_t keyring_ref;
long ret; long ret;
keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) { if (IS_ERR(keyring_ref)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring_ref);
goto error; goto error;
} }
ret = keyring_clear(keyring); ret = keyring_clear(key_ref_to_ptr(keyring_ref));
key_put(keyring); key_ref_put(keyring_ref);
error: error:
return ret; return ret;
...@@ -401,26 +403,26 @@ long keyctl_keyring_clear(key_serial_t ringid) ...@@ -401,26 +403,26 @@ long keyctl_keyring_clear(key_serial_t ringid)
*/ */
long keyctl_keyring_link(key_serial_t id, 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; long ret;
keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) { if (IS_ERR(keyring_ref)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring_ref);
goto error; goto error;
} }
key = lookup_user_key(NULL, id, 1, 0, KEY_LINK); key_ref = lookup_user_key(NULL, id, 1, 0, KEY_LINK);
if (IS_ERR(key)) { if (IS_ERR(key_ref)) {
ret = PTR_ERR(key); ret = PTR_ERR(key_ref);
goto error2; 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: error2:
key_put(keyring); key_ref_put(keyring_ref);
error: error:
return ret; return ret;
...@@ -435,26 +437,26 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) ...@@ -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) 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; long ret;
keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE); keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
if (IS_ERR(keyring)) { if (IS_ERR(keyring_ref)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring_ref);
goto error; goto error;
} }
key = lookup_user_key(NULL, id, 0, 0, 0); key_ref = lookup_user_key(NULL, id, 0, 0, 0);
if (IS_ERR(key)) { if (IS_ERR(key_ref)) {
ret = PTR_ERR(key); ret = PTR_ERR(key_ref);
goto error2; 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: error2:
key_put(keyring); key_ref_put(keyring_ref);
error: error:
return ret; return ret;
...@@ -476,24 +478,26 @@ long keyctl_describe_key(key_serial_t keyid, ...@@ -476,24 +478,26 @@ long keyctl_describe_key(key_serial_t keyid,
size_t buflen) size_t buflen)
{ {
struct key *key, *instkey; struct key *key, *instkey;
key_ref_t key_ref;
char *tmpbuf; char *tmpbuf;
long ret; long ret;
key = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW); key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
if (IS_ERR(key)) { if (IS_ERR(key_ref)) {
/* viewing a key under construction is permitted if we have the /* viewing a key under construction is permitted if we have the
* authorisation token handy */ * authorisation token handy */
if (PTR_ERR(key) == -EACCES) { if (PTR_ERR(key_ref) == -EACCES) {
instkey = key_get_instantiation_authkey(keyid); instkey = key_get_instantiation_authkey(keyid);
if (!IS_ERR(instkey)) { if (!IS_ERR(instkey)) {
key_put(instkey); key_put(instkey);
key = lookup_user_key(NULL, keyid, 0, 1, 0); key_ref = lookup_user_key(NULL, keyid,
if (!IS_ERR(key)) 0, 1, 0);
if (!IS_ERR(key_ref))
goto okay; goto okay;
} }
} }
ret = PTR_ERR(key); ret = PTR_ERR(key_ref);
goto error; goto error;
} }
...@@ -504,13 +508,16 @@ long keyctl_describe_key(key_serial_t keyid, ...@@ -504,13 +508,16 @@ long keyctl_describe_key(key_serial_t keyid,
if (!tmpbuf) if (!tmpbuf)
goto error2; goto error2;
key = key_ref_to_ptr(key_ref);
ret = snprintf(tmpbuf, PAGE_SIZE - 1, ret = snprintf(tmpbuf, PAGE_SIZE - 1,
"%s;%d;%d;%06x;%s", "%s;%d;%d;%08x;%s",
key->type->name, key_ref_to_ptr(key_ref)->type->name,
key->uid, key_ref_to_ptr(key_ref)->uid,
key->gid, key_ref_to_ptr(key_ref)->gid,
key->perm, key_ref_to_ptr(key_ref)->perm,
key->description ? key->description :"" key_ref_to_ptr(key_ref)->description ?
key_ref_to_ptr(key_ref)->description : ""
); );
/* include a NUL char at the end of the data */ /* include a NUL char at the end of the data */
...@@ -530,7 +537,7 @@ long keyctl_describe_key(key_serial_t keyid, ...@@ -530,7 +537,7 @@ long keyctl_describe_key(key_serial_t keyid,
kfree(tmpbuf); kfree(tmpbuf);
error2: error2:
key_put(key); key_ref_put(key_ref);
error: error:
return ret; return ret;
...@@ -552,7 +559,7 @@ long keyctl_keyring_search(key_serial_t ringid, ...@@ -552,7 +559,7 @@ long keyctl_keyring_search(key_serial_t ringid,
key_serial_t destringid) key_serial_t destringid)
{ {
struct key_type *ktype; struct key_type *ktype;
struct key *keyring, *key, *dest; key_ref_t keyring_ref, key_ref, dest_ref;
char type[32], *description; char type[32], *description;
long dlen, ret; long dlen, ret;
...@@ -581,18 +588,18 @@ long keyctl_keyring_search(key_serial_t ringid, ...@@ -581,18 +588,18 @@ long keyctl_keyring_search(key_serial_t ringid,
goto error2; goto error2;
/* get the keyring at which to begin the search */ /* get the keyring at which to begin the search */
keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH); keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
if (IS_ERR(keyring)) { if (IS_ERR(keyring_ref)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring_ref);
goto error2; goto error2;
} }
/* get the destination keyring if specified */ /* get the destination keyring if specified */
dest = NULL; dest_ref = NULL;
if (destringid) { if (destringid) {
dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE); dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
if (IS_ERR(dest)) { if (IS_ERR(dest_ref)) {
ret = PTR_ERR(dest); ret = PTR_ERR(dest_ref);
goto error3; goto error3;
} }
} }
...@@ -605,9 +612,9 @@ long keyctl_keyring_search(key_serial_t ringid, ...@@ -605,9 +612,9 @@ long keyctl_keyring_search(key_serial_t ringid,
} }
/* do the search */ /* do the search */
key = keyring_search(keyring, ktype, description); key_ref = keyring_search(keyring_ref, ktype, description);
if (IS_ERR(key)) { if (IS_ERR(key_ref)) {
ret = PTR_ERR(key); ret = PTR_ERR(key_ref);
/* treat lack or presence of a negative key the same */ /* treat lack or presence of a negative key the same */
if (ret == -EAGAIN) if (ret == -EAGAIN)
...@@ -616,26 +623,26 @@ long keyctl_keyring_search(key_serial_t ringid, ...@@ -616,26 +623,26 @@ long keyctl_keyring_search(key_serial_t ringid,
} }
/* link the resulting key to the destination keyring if we can */ /* link the resulting key to the destination keyring if we can */
if (dest) { if (dest_ref) {
ret = -EACCES; ret = -EACCES;
if (!key_permission(key, KEY_LINK)) if (!key_permission(key_ref, KEY_LINK))
goto error6; 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) if (ret < 0)
goto error6; goto error6;
} }
ret = key->serial; ret = key_ref_to_ptr(key_ref)->serial;
error6: error6:
key_put(key); key_ref_put(key_ref);
error5: error5:
key_type_put(ktype); key_type_put(ktype);
error4: error4:
key_put(dest); key_ref_put(dest_ref);
error3: error3:
key_put(keyring); key_ref_put(keyring_ref);
error2: error2:
kfree(description); kfree(description);
error: error:
...@@ -643,16 +650,6 @@ long keyctl_keyring_search(key_serial_t ringid, ...@@ -643,16 +650,6 @@ long keyctl_keyring_search(key_serial_t ringid,
} /* end keyctl_keyring_search() */ } /* end keyctl_keyring_search() */
/*****************************************************************************/
/*
* 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 * read a user key's payload
...@@ -665,38 +662,33 @@ static int keyctl_read_key_same(const struct key *key, const void *target) ...@@ -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) 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; long ret;
/* find the key first */ /* find the key first */
key = lookup_user_key(NULL, keyid, 0, 0, 0); key_ref = lookup_user_key(NULL, keyid, 0, 0, 0);
if (!IS_ERR(key)) { if (IS_ERR(key_ref)) {
ret = -ENOKEY;
goto error;
}
key = key_ref_to_ptr(key_ref);
/* see if we can read it directly */ /* see if we can read it directly */
if (key_permission(key, KEY_READ)) if (key_permission(key_ref, KEY_READ))
goto can_read_key; goto can_read_key;
/* we can't; see if it's searchable from this process's /* we can't; see if it's searchable from this process's keyrings
* keyrings
* - we automatically take account of the fact that it may be * - we automatically take account of the fact that it may be
* dangling off an instantiation key * dangling off an instantiation key
*/ */
skey = search_process_keyrings(key->type, key, if (!is_key_possessed(key_ref)) {
keyctl_read_key_same, current);
if (!IS_ERR(skey))
goto can_read_key2;
ret = PTR_ERR(skey);
if (ret == -EAGAIN)
ret = -EACCES; ret = -EACCES;
goto error2; goto error2;
} }
ret = -ENOKEY;
goto error;
/* the key is probably readable - now try to read it */ /* the key is probably readable - now try to read it */
can_read_key2:
key_put(skey);
can_read_key: can_read_key:
ret = key_validate(key); ret = key_validate(key);
if (ret == 0) { if (ret == 0) {
...@@ -727,18 +719,21 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) ...@@ -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) long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
{ {
struct key *key; struct key *key;
key_ref_t key_ref;
long ret; long ret;
ret = 0; ret = 0;
if (uid == (uid_t) -1 && gid == (gid_t) -1) if (uid == (uid_t) -1 && gid == (gid_t) -1)
goto error; goto error;
key = lookup_user_key(NULL, id, 1, 1, 0); key_ref = lookup_user_key(NULL, id, 1, 1, 0);
if (IS_ERR(key)) { if (IS_ERR(key_ref)) {
ret = PTR_ERR(key); ret = PTR_ERR(key_ref);
goto error; goto error;
} }
key = key_ref_to_ptr(key_ref);
/* make the changes with the locks held to prevent chown/chown races */ /* make the changes with the locks held to prevent chown/chown races */
ret = -EACCES; ret = -EACCES;
down_write(&key->sem); down_write(&key->sem);
...@@ -784,18 +779,21 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) ...@@ -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) long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
{ {
struct key *key; struct key *key;
key_ref_t key_ref;
long ret; long ret;
ret = -EINVAL; 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; goto error;
key = lookup_user_key(NULL, id, 1, 1, 0); key_ref = lookup_user_key(NULL, id, 1, 1, 0);
if (IS_ERR(key)) { if (IS_ERR(key_ref)) {
ret = PTR_ERR(key); ret = PTR_ERR(key_ref);
goto error; goto error;
} }
key = key_ref_to_ptr(key_ref);
/* make the changes with the locks held to prevent chown/chmod races */ /* make the changes with the locks held to prevent chown/chmod races */
ret = -EACCES; ret = -EACCES;
down_write(&key->sem); down_write(&key->sem);
...@@ -824,7 +822,8 @@ long keyctl_instantiate_key(key_serial_t id, ...@@ -824,7 +822,8 @@ long keyctl_instantiate_key(key_serial_t id,
key_serial_t ringid) key_serial_t ringid)
{ {
struct request_key_auth *rka; struct request_key_auth *rka;
struct key *instkey, *keyring; struct key *instkey;
key_ref_t keyring_ref;
void *payload; void *payload;
long ret; long ret;
...@@ -857,21 +856,21 @@ long keyctl_instantiate_key(key_serial_t id, ...@@ -857,21 +856,21 @@ long keyctl_instantiate_key(key_serial_t id,
/* find the destination keyring amongst those belonging to the /* find the destination keyring amongst those belonging to the
* requesting task */ * requesting task */
keyring = NULL; keyring_ref = NULL;
if (ringid) { if (ringid) {
keyring = lookup_user_key(rka->context, ringid, 1, 0, keyring_ref = lookup_user_key(rka->context, ringid, 1, 0,
KEY_WRITE); KEY_WRITE);
if (IS_ERR(keyring)) { if (IS_ERR(keyring_ref)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring_ref);
goto error3; goto error3;
} }
} }
/* instantiate the key and link it into a keyring */ /* instantiate the key and link it into a keyring */
ret = key_instantiate_and_link(rka->target_key, payload, plen, 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: error3:
key_put(instkey); key_put(instkey);
error2: error2:
...@@ -889,7 +888,8 @@ long keyctl_instantiate_key(key_serial_t id, ...@@ -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) long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
{ {
struct request_key_auth *rka; struct request_key_auth *rka;
struct key *instkey, *keyring; struct key *instkey;
key_ref_t keyring_ref;
long ret; long ret;
/* find the instantiation authorisation key */ /* find the instantiation authorisation key */
...@@ -903,19 +903,20 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) ...@@ -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 /* find the destination keyring if present (which must also be
* writable) */ * writable) */
keyring = NULL; keyring_ref = NULL;
if (ringid) { if (ringid) {
keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) { if (IS_ERR(keyring_ref)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring_ref);
goto error2; goto error2;
} }
} }
/* instantiate the key and link it into a keyring */ /* 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: error2:
key_put(instkey); key_put(instkey);
error: error:
......
...@@ -309,7 +309,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, ...@@ -309,7 +309,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
int ret; int ret;
keyring = key_alloc(&key_type_keyring, description, 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)) { if (!IS_ERR(keyring)) {
ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
...@@ -333,8 +333,9 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, ...@@ -333,8 +333,9 @@ 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 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 -EAGAIN if we didn't find any matching key
* - we return -ENOKEY if we only found negative matching keys * - 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, key_ref_t keyring_search_aux(key_ref_t keyring_ref,
struct task_struct *context, struct task_struct *context,
struct key_type *type, struct key_type *type,
const void *description, const void *description,
...@@ -347,29 +348,33 @@ struct key *keyring_search_aux(struct key *keyring, ...@@ -347,29 +348,33 @@ struct key *keyring_search_aux(struct key *keyring,
struct keyring_list *keylist; struct keyring_list *keylist;
struct timespec now; struct timespec now;
struct key *key; unsigned long possessed;
struct key *keyring, *key;
key_ref_t key_ref;
long err; long err;
int sp, kix; int sp, kix;
keyring = key_ref_to_ptr(keyring_ref);
possessed = is_key_possessed(keyring_ref);
key_check(keyring); key_check(keyring);
rcu_read_lock();
/* top keyring must have search permission to begin the search */ /* top keyring must have search permission to begin the search */
key = ERR_PTR(-EACCES); key_ref = ERR_PTR(-EACCES);
if (!key_task_permission(keyring, context, KEY_SEARCH)) if (!key_task_permission(keyring_ref, context, KEY_SEARCH))
goto error; goto error;
key = ERR_PTR(-ENOTDIR); key_ref = ERR_PTR(-ENOTDIR);
if (keyring->type != &key_type_keyring) if (keyring->type != &key_type_keyring)
goto error; goto error;
rcu_read_lock();
now = current_kernel_time(); now = current_kernel_time();
err = -EAGAIN; err = -EAGAIN;
sp = 0; sp = 0;
/* start processing a new keyring */ /* start processing a new keyring */
descend: descend:
if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
goto not_this_keyring; goto not_this_keyring;
...@@ -397,7 +402,8 @@ struct key *keyring_search_aux(struct key *keyring, ...@@ -397,7 +402,8 @@ struct key *keyring_search_aux(struct key *keyring,
continue; continue;
/* key must have search permissions */ /* 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; continue;
/* we set a different error code if we find a negative key */ /* we set a different error code if we find a negative key */
...@@ -411,7 +417,7 @@ struct key *keyring_search_aux(struct key *keyring, ...@@ -411,7 +417,7 @@ struct key *keyring_search_aux(struct key *keyring,
/* search through the keyrings nested in this one */ /* search through the keyrings nested in this one */
kix = 0; kix = 0;
ascend: ascend:
for (; kix < keylist->nkeys; kix++) { for (; kix < keylist->nkeys; kix++) {
key = keylist->keys[kix]; key = keylist->keys[kix];
if (key->type != &key_type_keyring) if (key->type != &key_type_keyring)
...@@ -423,7 +429,8 @@ struct key *keyring_search_aux(struct key *keyring, ...@@ -423,7 +429,8 @@ struct key *keyring_search_aux(struct key *keyring,
if (sp >= KEYRING_SEARCH_MAX_DEPTH) if (sp >= KEYRING_SEARCH_MAX_DEPTH)
continue; continue;
if (!key_task_permission(key, context, KEY_SEARCH)) if (!key_task_permission(make_key_ref(key, possessed),
context, KEY_SEARCH))
continue; continue;
/* stack the current position */ /* stack the current position */
...@@ -438,7 +445,7 @@ struct key *keyring_search_aux(struct key *keyring, ...@@ -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 /* the keyring we're looking at was disqualified or didn't contain a
* matching key */ * matching key */
not_this_keyring: not_this_keyring:
if (sp > 0) { if (sp > 0) {
/* resume the processing of a keyring higher up in the tree */ /* resume the processing of a keyring higher up in the tree */
sp--; sp--;
...@@ -447,16 +454,18 @@ struct key *keyring_search_aux(struct key *keyring, ...@@ -447,16 +454,18 @@ struct key *keyring_search_aux(struct key *keyring,
goto ascend; goto ascend;
} }
key = ERR_PTR(err); key_ref = ERR_PTR(err);
goto error; goto error_2;
/* we found a viable match */ /* we found a viable match */
found: found:
atomic_inc(&key->usage); atomic_inc(&key->usage);
key_check(key); key_check(key);
error: key_ref = make_key_ref(key, possessed);
error_2:
rcu_read_unlock(); rcu_read_unlock();
return key; error:
return key_ref;
} /* end keyring_search_aux() */ } /* end keyring_search_aux() */
...@@ -469,7 +478,7 @@ struct key *keyring_search_aux(struct key *keyring, ...@@ -469,7 +478,7 @@ struct key *keyring_search_aux(struct key *keyring,
* - we return -EAGAIN if we didn't find any matching key * - we return -EAGAIN if we didn't find any matching key
* - we return -ENOKEY if we only found negative matching keys * - we return -ENOKEY if we only found negative matching keys
*/ */
struct key *keyring_search(struct key *keyring, key_ref_t keyring_search(key_ref_t keyring,
struct key_type *type, struct key_type *type,
const char *description) const char *description)
{ {
...@@ -488,15 +497,19 @@ EXPORT_SYMBOL(keyring_search); ...@@ -488,15 +497,19 @@ EXPORT_SYMBOL(keyring_search);
* search the given keyring only (no recursion) * search the given keyring only (no recursion)
* - keyring must be locked by caller * - keyring must be locked by caller
*/ */
struct key *__keyring_search_one(struct key *keyring, key_ref_t __keyring_search_one(key_ref_t keyring_ref,
const struct key_type *ktype, const struct key_type *ktype,
const char *description, const char *description,
key_perm_t perm) key_perm_t perm)
{ {
struct keyring_list *klist; struct keyring_list *klist;
struct key *key; unsigned long possessed;
struct key *keyring, *key;
int loop; int loop;
keyring = key_ref_to_ptr(keyring_ref);
possessed = is_key_possessed(keyring_ref);
rcu_read_lock(); rcu_read_lock();
klist = rcu_dereference(keyring->payload.subscriptions); klist = rcu_dereference(keyring->payload.subscriptions);
...@@ -507,21 +520,21 @@ struct key *__keyring_search_one(struct key *keyring, ...@@ -507,21 +520,21 @@ struct key *__keyring_search_one(struct key *keyring,
if (key->type == ktype && if (key->type == ktype &&
(!key->type->match || (!key->type->match ||
key->type->match(key, description)) && key->type->match(key, description)) &&
key_permission(key, perm) && key_permission(make_key_ref(key, possessed),
perm) &&
!test_bit(KEY_FLAG_REVOKED, &key->flags) !test_bit(KEY_FLAG_REVOKED, &key->flags)
) )
goto found; goto found;
} }
} }
key = ERR_PTR(-ENOKEY); rcu_read_unlock();
goto error; return ERR_PTR(-ENOKEY);
found: found:
atomic_inc(&key->usage); atomic_inc(&key->usage);
error:
rcu_read_unlock(); rcu_read_unlock();
return key; return make_key_ref(key, possessed);
} /* end __keyring_search_one() */ } /* end __keyring_search_one() */
...@@ -603,7 +616,8 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound) ...@@ -603,7 +616,8 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound)
if (strcmp(keyring->description, name) != 0) if (strcmp(keyring->description, name) != 0)
continue; continue;
if (!key_permission(keyring, KEY_SEARCH)) if (!key_permission(make_key_ref(keyring, 0),
KEY_SEARCH))
continue; continue;
/* found a potential candidate, but we still need to /* found a potential candidate, but we still need to
......
...@@ -167,7 +167,7 @@ static int proc_keys_show(struct seq_file *m, void *v) ...@@ -167,7 +167,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
#define showflag(KEY, LETTER, FLAG) \ #define showflag(KEY, LETTER, FLAG) \
(test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') (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, key->serial,
showflag(key, 'I', KEY_FLAG_INSTANTIATED), showflag(key, 'I', KEY_FLAG_INSTANTIATED),
showflag(key, 'R', KEY_FLAG_REVOKED), showflag(key, 'R', KEY_FLAG_REVOKED),
......
...@@ -39,7 +39,7 @@ struct key root_user_keyring = { ...@@ -39,7 +39,7 @@ struct key root_user_keyring = {
.type = &key_type_keyring, .type = &key_type_keyring,
.user = &root_key_user, .user = &root_key_user,
.sem = __RWSEM_INITIALIZER(root_user_keyring.sem), .sem = __RWSEM_INITIALIZER(root_user_keyring.sem),
.perm = KEY_USR_ALL, .perm = KEY_POS_ALL | KEY_USR_ALL,
.flags = 1 << KEY_FLAG_INSTANTIATED, .flags = 1 << KEY_FLAG_INSTANTIATED,
.description = "_uid.0", .description = "_uid.0",
#ifdef KEY_DEBUGGING #ifdef KEY_DEBUGGING
...@@ -54,7 +54,7 @@ struct key root_session_keyring = { ...@@ -54,7 +54,7 @@ struct key root_session_keyring = {
.type = &key_type_keyring, .type = &key_type_keyring,
.user = &root_key_user, .user = &root_key_user,
.sem = __RWSEM_INITIALIZER(root_session_keyring.sem), .sem = __RWSEM_INITIALIZER(root_session_keyring.sem),
.perm = KEY_USR_ALL, .perm = KEY_POS_ALL | KEY_USR_ALL,
.flags = 1 << KEY_FLAG_INSTANTIATED, .flags = 1 << KEY_FLAG_INSTANTIATED,
.description = "_uid_ses.0", .description = "_uid_ses.0",
#ifdef KEY_DEBUGGING #ifdef KEY_DEBUGGING
...@@ -98,7 +98,7 @@ int alloc_uid_keyring(struct user_struct *user) ...@@ -98,7 +98,7 @@ int alloc_uid_keyring(struct user_struct *user)
user->session_keyring = session_keyring; user->session_keyring = session_keyring;
ret = 0; ret = 0;
error: error:
return ret; return ret;
} /* end alloc_uid_keyring() */ } /* end alloc_uid_keyring() */
...@@ -156,7 +156,7 @@ int install_thread_keyring(struct task_struct *tsk) ...@@ -156,7 +156,7 @@ int install_thread_keyring(struct task_struct *tsk)
ret = 0; ret = 0;
key_put(old); key_put(old);
error: error:
return ret; return ret;
} /* end install_thread_keyring() */ } /* end install_thread_keyring() */
...@@ -193,7 +193,7 @@ int install_process_keyring(struct task_struct *tsk) ...@@ -193,7 +193,7 @@ int install_process_keyring(struct task_struct *tsk)
} }
ret = 0; ret = 0;
error: error:
return ret; return ret;
} /* end install_process_keyring() */ } /* end install_process_keyring() */
...@@ -236,7 +236,7 @@ static int install_session_keyring(struct task_struct *tsk, ...@@ -236,7 +236,7 @@ static int install_session_keyring(struct task_struct *tsk,
/* we're using RCU on the pointer */ /* we're using RCU on the pointer */
synchronize_rcu(); synchronize_rcu();
key_put(old); key_put(old);
error: error:
return ret; return ret;
} /* end install_session_keyring() */ } /* end install_session_keyring() */
...@@ -376,13 +376,13 @@ void key_fsgid_changed(struct task_struct *tsk) ...@@ -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 -EAGAIN if we didn't find any matching key
* - we return -ENOKEY if we found only negative matching keys * - we return -ENOKEY if we found only negative matching keys
*/ */
struct key *search_process_keyrings(struct key_type *type, key_ref_t search_process_keyrings(struct key_type *type,
const void *description, const void *description,
key_match_func_t match, key_match_func_t match,
struct task_struct *context) struct task_struct *context)
{ {
struct request_key_auth *rka; 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 /* 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; * 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, ...@@ -391,46 +391,48 @@ struct key *search_process_keyrings(struct key_type *type,
* *
* in terms of priority: success > -ENOKEY > -EAGAIN > other error * in terms of priority: success > -ENOKEY > -EAGAIN > other error
*/ */
key = NULL; key_ref = NULL;
ret = NULL; ret = NULL;
err = ERR_PTR(-EAGAIN); err = ERR_PTR(-EAGAIN);
/* search the thread keyring first */ /* search the thread keyring first */
if (context->thread_keyring) { if (context->thread_keyring) {
key = keyring_search_aux(context->thread_keyring, key_ref = keyring_search_aux(
make_key_ref(context->thread_keyring, 1),
context, type, description, match); context, type, description, match);
if (!IS_ERR(key)) if (!IS_ERR(key_ref))
goto found; goto found;
switch (PTR_ERR(key)) { switch (PTR_ERR(key_ref)) {
case -EAGAIN: /* no key */ case -EAGAIN: /* no key */
if (ret) if (ret)
break; break;
case -ENOKEY: /* negative key */ case -ENOKEY: /* negative key */
ret = key; ret = key_ref;
break; break;
default: default:
err = key; err = key_ref;
break; break;
} }
} }
/* search the process keyring second */ /* search the process keyring second */
if (context->signal->process_keyring) { if (context->signal->process_keyring) {
key = keyring_search_aux(context->signal->process_keyring, key_ref = keyring_search_aux(
make_key_ref(context->signal->process_keyring, 1),
context, type, description, match); context, type, description, match);
if (!IS_ERR(key)) if (!IS_ERR(key_ref))
goto found; goto found;
switch (PTR_ERR(key)) { switch (PTR_ERR(key_ref)) {
case -EAGAIN: /* no key */ case -EAGAIN: /* no key */
if (ret) if (ret)
break; break;
case -ENOKEY: /* negative key */ case -ENOKEY: /* negative key */
ret = key; ret = key_ref;
break; break;
default: default:
err = key; err = key_ref;
break; break;
} }
} }
...@@ -438,23 +440,25 @@ struct key *search_process_keyrings(struct key_type *type, ...@@ -438,23 +440,25 @@ struct key *search_process_keyrings(struct key_type *type,
/* search the session keyring */ /* search the session keyring */
if (context->signal->session_keyring) { if (context->signal->session_keyring) {
rcu_read_lock(); rcu_read_lock();
key = keyring_search_aux( key_ref = keyring_search_aux(
rcu_dereference(context->signal->session_keyring), make_key_ref(rcu_dereference(
context->signal->session_keyring),
1),
context, type, description, match); context, type, description, match);
rcu_read_unlock(); rcu_read_unlock();
if (!IS_ERR(key)) if (!IS_ERR(key_ref))
goto found; goto found;
switch (PTR_ERR(key)) { switch (PTR_ERR(key_ref)) {
case -EAGAIN: /* no key */ case -EAGAIN: /* no key */
if (ret) if (ret)
break; break;
case -ENOKEY: /* negative key */ case -ENOKEY: /* negative key */
ret = key; ret = key_ref;
break; break;
default: default:
err = key; err = key_ref;
break; break;
} }
...@@ -465,51 +469,54 @@ struct key *search_process_keyrings(struct key_type *type, ...@@ -465,51 +469,54 @@ struct key *search_process_keyrings(struct key_type *type,
goto no_key; goto no_key;
rcu_read_lock(); rcu_read_lock();
instkey = __keyring_search_one( instkey_ref = __keyring_search_one(
rcu_dereference(context->signal->session_keyring), make_key_ref(rcu_dereference(
context->signal->session_keyring),
1),
&key_type_request_key_auth, NULL, 0); &key_type_request_key_auth, NULL, 0);
rcu_read_unlock(); rcu_read_unlock();
if (IS_ERR(instkey)) if (IS_ERR(instkey_ref))
goto no_key; goto no_key;
rka = instkey->payload.data; rka = key_ref_to_ptr(instkey_ref)->payload.data;
key = search_process_keyrings(type, description, match, key_ref = search_process_keyrings(type, description, match,
rka->context); rka->context);
key_put(instkey); key_ref_put(instkey_ref);
if (!IS_ERR(key)) if (!IS_ERR(key_ref))
goto found; goto found;
switch (PTR_ERR(key)) { switch (PTR_ERR(key_ref)) {
case -EAGAIN: /* no key */ case -EAGAIN: /* no key */
if (ret) if (ret)
break; break;
case -ENOKEY: /* negative key */ case -ENOKEY: /* negative key */
ret = key; ret = key_ref;
break; break;
default: default:
err = key; err = key_ref;
break; break;
} }
} }
/* or search the user-session keyring */ /* or search the user-session keyring */
else { else {
key = keyring_search_aux(context->user->session_keyring, key_ref = keyring_search_aux(
make_key_ref(context->user->session_keyring, 1),
context, type, description, match); context, type, description, match);
if (!IS_ERR(key)) if (!IS_ERR(key_ref))
goto found; goto found;
switch (PTR_ERR(key)) { switch (PTR_ERR(key_ref)) {
case -EAGAIN: /* no key */ case -EAGAIN: /* no key */
if (ret) if (ret)
break; break;
case -ENOKEY: /* negative key */ case -ENOKEY: /* negative key */
ret = key; ret = key_ref;
break; break;
default: default:
err = key; err = key_ref;
break; break;
} }
} }
...@@ -517,29 +524,40 @@ struct key *search_process_keyrings(struct key_type *type, ...@@ -517,29 +524,40 @@ struct key *search_process_keyrings(struct key_type *type,
no_key: no_key:
/* no key - decide on the error we're going to go for */ /* no key - decide on the error we're going to go for */
key = ret ? ret : err; key_ref = ret ? ret : err;
found: found:
return key; return key_ref;
} /* end search_process_keyrings() */ } /* 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 * lookup a key given a key ID from userspace with a given permissions mask
* - don't create special keyrings unless so requested * - don't create special keyrings unless so requested
* - partially constructed keys aren't found unless requested * - partially constructed keys aren't found unless requested
*/ */
struct key *lookup_user_key(struct task_struct *context, key_serial_t id, key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
int create, int partial, key_perm_t perm) int create, int partial, key_perm_t perm)
{ {
key_ref_t key_ref, skey_ref;
struct key *key; struct key *key;
int ret; int ret;
if (!context) if (!context)
context = current; context = current;
key = ERR_PTR(-ENOKEY); key_ref = ERR_PTR(-ENOKEY);
switch (id) { switch (id) {
case KEY_SPEC_THREAD_KEYRING: case KEY_SPEC_THREAD_KEYRING:
...@@ -556,6 +574,7 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id, ...@@ -556,6 +574,7 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
key = context->thread_keyring; key = context->thread_keyring;
atomic_inc(&key->usage); atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1);
break; break;
case KEY_SPEC_PROCESS_KEYRING: case KEY_SPEC_PROCESS_KEYRING:
...@@ -572,6 +591,7 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id, ...@@ -572,6 +591,7 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
key = context->signal->process_keyring; key = context->signal->process_keyring;
atomic_inc(&key->usage); atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1);
break; break;
case KEY_SPEC_SESSION_KEYRING: case KEY_SPEC_SESSION_KEYRING:
...@@ -588,16 +608,19 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id, ...@@ -588,16 +608,19 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
key = rcu_dereference(context->signal->session_keyring); key = rcu_dereference(context->signal->session_keyring);
atomic_inc(&key->usage); atomic_inc(&key->usage);
rcu_read_unlock(); rcu_read_unlock();
key_ref = make_key_ref(key, 1);
break; break;
case KEY_SPEC_USER_KEYRING: case KEY_SPEC_USER_KEYRING:
key = context->user->uid_keyring; key = context->user->uid_keyring;
atomic_inc(&key->usage); atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1);
break; break;
case KEY_SPEC_USER_SESSION_KEYRING: case KEY_SPEC_USER_SESSION_KEYRING:
key = context->user->session_keyring; key = context->user->session_keyring;
atomic_inc(&key->usage); atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1);
break; break;
case KEY_SPEC_GROUP_KEYRING: case KEY_SPEC_GROUP_KEYRING:
...@@ -606,13 +629,28 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id, ...@@ -606,13 +629,28 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
goto error; goto error;
default: default:
key = ERR_PTR(-EINVAL); key_ref = ERR_PTR(-EINVAL);
if (id < 1) if (id < 1)
goto error; goto error;
key = key_lookup(id); key = key_lookup(id);
if (IS_ERR(key)) if (IS_ERR(key)) {
key_ref = ERR_PTR(PTR_ERR(key));
goto error; 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; break;
} }
...@@ -630,15 +668,15 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id, ...@@ -630,15 +668,15 @@ struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
/* check the permissions */ /* check the permissions */
ret = -EACCES; ret = -EACCES;
if (!key_task_permission(key, context, perm)) if (!key_task_permission(key_ref, context, perm))
goto invalid_key; goto invalid_key;
error: error:
return key; return key_ref;
invalid_key: invalid_key:
key_put(key); key_ref_put(key_ref);
key = ERR_PTR(ret); key_ref = ERR_PTR(ret);
goto error; goto error;
} /* end lookup_user_key() */ } /* end lookup_user_key() */
...@@ -694,9 +732,9 @@ long join_session_keyring(const char *name) ...@@ -694,9 +732,9 @@ long join_session_keyring(const char *name)
ret = keyring->serial; ret = keyring->serial;
key_put(keyring); key_put(keyring);
error2: error2:
up(&key_session_sem); up(&key_session_sem);
error: error:
return ret; return ret;
} /* end join_session_keyring() */ } /* end join_session_keyring() */
...@@ -129,7 +129,7 @@ static struct key *__request_key_construction(struct key_type *type, ...@@ -129,7 +129,7 @@ static struct key *__request_key_construction(struct key_type *type,
/* create a key and add it to the queue */ /* create a key and add it to the queue */
key = key_alloc(type, description, 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)) if (IS_ERR(key))
goto alloc_failed; goto alloc_failed;
...@@ -365,14 +365,24 @@ struct key *request_key_and_link(struct key_type *type, ...@@ -365,14 +365,24 @@ struct key *request_key_and_link(struct key_type *type,
{ {
struct key_user *user; struct key_user *user;
struct key *key; struct key *key;
key_ref_t key_ref;
kenter("%s,%s,%s,%p", kenter("%s,%s,%s,%p",
type->name, description, callout_info, dest_keyring); type->name, description, callout_info, dest_keyring);
/* search all the process keyrings for a key */ /* 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);
if (PTR_ERR(key) == -EAGAIN) { kdebug("search 1: %p", key_ref);
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 /* the search failed, but the keyrings were searchable, so we
* should consult userspace if we can */ * should consult userspace if we can */
key = ERR_PTR(-ENOKEY); key = ERR_PTR(-ENOKEY);
...@@ -384,7 +394,7 @@ struct key *request_key_and_link(struct key_type *type, ...@@ -384,7 +394,7 @@ struct key *request_key_and_link(struct key_type *type,
if (!user) if (!user)
goto nomem; goto nomem;
do { for (;;) {
if (signal_pending(current)) if (signal_pending(current))
goto interrupted; goto interrupted;
...@@ -397,10 +407,22 @@ struct key *request_key_and_link(struct key_type *type, ...@@ -397,10 +407,22 @@ struct key *request_key_and_link(struct key_type *type,
/* someone else made the key we want, so we need to /* someone else made the key we want, so we need to
* search again as it might now be available to us */ * search again as it might now be available to us */
key = search_process_keyrings(type, description, key_ref = search_process_keyrings(type, description,
type->match, current); 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); key_user_put(user);
......
...@@ -126,7 +126,7 @@ struct key *request_key_auth_new(struct key *target, struct key **_rkakey) ...@@ -126,7 +126,7 @@ struct key *request_key_auth_new(struct key *target, struct key **_rkakey)
rkakey = key_alloc(&key_type_request_key_auth, desc, rkakey = key_alloc(&key_type_request_key_auth, desc,
current->fsuid, current->fsgid, current->fsuid, current->fsgid,
KEY_USR_VIEW, 1); KEY_POS_VIEW | KEY_USR_VIEW, 1);
if (IS_ERR(rkakey)) { if (IS_ERR(rkakey)) {
key_put(keyring); key_put(keyring);
kleave("= %ld", PTR_ERR(rkakey)); kleave("= %ld", PTR_ERR(rkakey));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment