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
...@@ -241,16 +241,16 @@ about the status of the key service: ...@@ -241,16 +241,16 @@ about the status of the key service:
type, description and permissions. The payload of the key is not available type, description and permissions. The payload of the key is not available
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,9 +131,9 @@ static inline int key_task_permission(const struct key *key, ...@@ -121,9 +131,9 @@ 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);
extern long join_session_keyring(const char *name); extern long join_session_keyring(const char *name);
......
...@@ -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,9 +287,9 @@ extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, ...@@ -243,9 +287,9 @@ 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);
extern int keyring_add_key(struct key *keyring, extern int keyring_add_key(struct key *keyring,
struct key *key); struct key *key);
...@@ -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,26 +71,26 @@ extern void keyring_publish_name(struct key *keyring); ...@@ -71,26 +71,26 @@ 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);
extern struct key *keyring_search_instkey(struct key *keyring, extern struct key *keyring_search_instkey(struct key *keyring,
key_serial_t target_id); key_serial_t target_id);
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);
extern struct key *find_keyring_by_name(const char *name, key_serial_t bound); extern struct key *find_keyring_by_name(const char *name, key_serial_t bound);
......
...@@ -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,52 +735,56 @@ static inline struct key *__key_update(struct key *key, const void *payload, ...@@ -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 * 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,
size_t plen, size_t plen,
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 */
......
This diff is collapsed.
...@@ -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,12 +333,13 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, ...@@ -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 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,
key_match_func_t match) key_match_func_t match)
{ {
struct { struct {
struct keyring_list *keylist; struct keyring_list *keylist;
...@@ -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,9 +478,9 @@ struct key *keyring_search_aux(struct key *keyring, ...@@ -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 -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)
{ {
if (!type->match) if (!type->match)
return ERR_PTR(-ENOKEY); return ERR_PTR(-ENOKEY);
...@@ -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),
......
This diff is collapsed.
...@@ -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