aboutsummaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/keys/Makefile5
-rw-r--r--security/keys/compat.c7
-rw-r--r--security/keys/internal.h45
-rw-r--r--security/keys/key.c24
-rw-r--r--security/keys/keyctl.c176
-rw-r--r--security/keys/keyring.c67
-rw-r--r--security/keys/process_keys.c179
-rw-r--r--security/keys/request_key.c182
-rw-r--r--security/keys/request_key_auth.c180
9 files changed, 685 insertions, 180 deletions
diff --git a/security/keys/Makefile b/security/keys/Makefile
index ddb495d6506..c392d750b20 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -7,8 +7,9 @@ obj-y := \
keyring.o \
keyctl.o \
process_keys.o \
- user_defined.o \
- request_key.o
+ request_key.o \
+ request_key_auth.o \
+ user_defined.o
obj-$(CONFIG_KEYS_COMPAT) += compat.o
obj-$(CONFIG_PROC_FS) += proc.o
diff --git a/security/keys/compat.c b/security/keys/compat.c
index aff8b22dcb5..3303673c636 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -1,6 +1,6 @@
/* compat.c: 32-bit compatibility syscall for 64-bit systems
*
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -24,7 +24,7 @@
* - if you can, you should call sys_keyctl directly
*/
asmlinkage long compat_sys_keyctl(u32 option,
- u32 arg2, u32 arg3, u32 arg4, u32 arg5)
+ u32 arg2, u32 arg3, u32 arg4, u32 arg5)
{
switch (option) {
case KEYCTL_GET_KEYRING_ID:
@@ -71,6 +71,9 @@ asmlinkage long compat_sys_keyctl(u32 option,
case KEYCTL_NEGATE:
return keyctl_negate_key(arg2, arg3, arg4);
+ case KEYCTL_SET_REQKEY_KEYRING:
+ return keyctl_set_reqkey_keyring(arg2);
+
default:
return -EOPNOTSUPP;
}
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 67b2b93a748..46c8602661c 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -1,6 +1,6 @@
/* internal.h: authentication token and access key management internal defs
*
- * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -15,6 +15,16 @@
#include <linux/key.h>
#include <linux/key-ui.h>
+#if 0
+#define kenter(FMT, a...) printk("==> %s("FMT")\n",__FUNCTION__ , ## a)
+#define kleave(FMT, a...) printk("<== %s()"FMT"\n",__FUNCTION__ , ## a)
+#define kdebug(FMT, a...) printk(FMT"\n" , ## a)
+#else
+#define kenter(FMT, a...) do {} while(0)
+#define kleave(FMT, a...) do {} while(0)
+#define kdebug(FMT, a...) do {} while(0)
+#endif
+
extern struct key_type key_type_dead;
extern struct key_type key_type_user;
@@ -66,20 +76,46 @@ extern struct key *__keyring_search_one(struct key *keyring,
const char *description,
key_perm_t perm);
+extern struct key *keyring_search_instkey(struct key *keyring,
+ key_serial_t target_id);
+
typedef int (*key_match_func_t)(const struct key *, const void *);
extern struct key *keyring_search_aux(struct key *keyring,
+ struct task_struct *tsk,
struct key_type *type,
const void *description,
key_match_func_t match);
-extern struct key *search_process_keyrings_aux(struct key_type *type,
- const void *description,
- key_match_func_t match);
+extern struct key *search_process_keyrings(struct key_type *type,
+ const void *description,
+ key_match_func_t match,
+ struct task_struct *tsk);
extern struct key *find_keyring_by_name(const char *name, key_serial_t bound);
extern int install_thread_keyring(struct task_struct *tsk);
+extern int install_process_keyring(struct task_struct *tsk);
+
+extern struct key *request_key_and_link(struct key_type *type,
+ const char *description,
+ const char *callout_info,
+ struct key *dest_keyring);
+
+/*
+ * request_key authorisation
+ */
+struct request_key_auth {
+ struct key *target_key;
+ struct task_struct *context;
+ pid_t pid;
+};
+
+extern struct key_type key_type_request_key_auth;
+extern struct key *request_key_auth_new(struct key *target,
+ struct key **_rkakey);
+
+extern struct key *key_get_instantiation_authkey(key_serial_t target_id);
/*
* keyctl functions
@@ -100,6 +136,7 @@ extern long keyctl_setperm_key(key_serial_t, key_perm_t);
extern long keyctl_instantiate_key(key_serial_t, const void __user *,
size_t, key_serial_t);
extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t);
+extern long keyctl_set_reqkey_keyring(int);
/*
diff --git a/security/keys/key.c b/security/keys/key.c
index 1fdfccb3fe4..3304d37bb37 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -1,6 +1,6 @@
/* key.c: basic authentication token and access key management
*
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -391,7 +391,8 @@ EXPORT_SYMBOL(key_payload_reserve);
static int __key_instantiate_and_link(struct key *key,
const void *data,
size_t datalen,
- struct key *keyring)
+ struct key *keyring,
+ struct key *instkey)
{
int ret, awaken;
@@ -419,6 +420,10 @@ static int __key_instantiate_and_link(struct key *key,
/* and link it into the destination keyring */
if (keyring)
ret = __key_link(keyring, key);
+
+ /* disable the authorisation key */
+ if (instkey)
+ key_revoke(instkey);
}
}
@@ -439,19 +444,21 @@ static int __key_instantiate_and_link(struct key *key,
int key_instantiate_and_link(struct key *key,
const void *data,
size_t datalen,
- struct key *keyring)
+ struct key *keyring,
+ struct key *instkey)
{
int ret;
if (keyring)
down_write(&keyring->sem);
- ret = __key_instantiate_and_link(key, data, datalen, keyring);
+ ret = __key_instantiate_and_link(key, data, datalen, keyring, instkey);
if (keyring)
up_write(&keyring->sem);
return ret;
+
} /* end key_instantiate_and_link() */
EXPORT_SYMBOL(key_instantiate_and_link);
@@ -462,7 +469,8 @@ EXPORT_SYMBOL(key_instantiate_and_link);
*/
int key_negate_and_link(struct key *key,
unsigned timeout,
- struct key *keyring)
+ struct key *keyring,
+ struct key *instkey)
{
struct timespec now;
int ret, awaken;
@@ -495,6 +503,10 @@ int key_negate_and_link(struct key *key,
/* and link it into the destination keyring */
if (keyring)
ret = __key_link(keyring, key);
+
+ /* disable the authorisation key */
+ if (instkey)
+ key_revoke(instkey);
}
up_write(&key_construction_sem);
@@ -781,7 +793,7 @@ struct key *key_create_or_update(struct key *keyring,
}
/* instantiate it and link it into the target keyring */
- ret = __key_instantiate_and_link(key, payload, plen, keyring);
+ ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL);
if (ret < 0) {
key_put(key);
key = ERR_PTR(ret);
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index cedb7326de2..fea262860ea 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1,6 +1,6 @@
/* keyctl.c: userspace keyctl operations
*
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -49,6 +49,13 @@ asmlinkage long sys_add_key(const char __user *_type,
goto error;
type[31] = '\0';
+ if (!type[0])
+ goto error;
+
+ ret = -EPERM;
+ if (type[0] == '.')
+ goto error;
+
ret = -EFAULT;
dlen = strnlen_user(_description, PAGE_SIZE - 1);
if (dlen <= 0)
@@ -82,7 +89,7 @@ asmlinkage long sys_add_key(const char __user *_type,
}
/* find the target keyring (which must be writable) */
- keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+ keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error3;
@@ -181,7 +188,7 @@ asmlinkage long sys_request_key(const char __user *_type,
/* get the destination keyring if specified */
dest = NULL;
if (destringid) {
- dest = lookup_user_key(destringid, 1, 0, KEY_WRITE);
+ dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
if (IS_ERR(dest)) {
ret = PTR_ERR(dest);
goto error3;
@@ -196,23 +203,15 @@ asmlinkage long sys_request_key(const char __user *_type,
}
/* do the search */
- key = request_key(ktype, description, callout_info);
+ key = request_key_and_link(ktype, description, callout_info, dest);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error5;
}
- /* link the resulting key to the destination keyring */
- if (dest) {
- ret = key_link(dest, key);
- if (ret < 0)
- goto error6;
- }
-
ret = key->serial;
- error6:
- key_put(key);
+ key_put(key);
error5:
key_type_put(ktype);
error4:
@@ -237,7 +236,7 @@ long keyctl_get_keyring_ID(key_serial_t id, int create)
struct key *key;
long ret;
- key = lookup_user_key(id, create, 0, KEY_SEARCH);
+ key = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error;
@@ -324,7 +323,7 @@ long keyctl_update_key(key_serial_t id,
}
/* find the target key (which must be writable) */
- key = lookup_user_key(id, 0, 0, KEY_WRITE);
+ key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error2;
@@ -352,7 +351,7 @@ long keyctl_revoke_key(key_serial_t id)
struct key *key;
long ret;
- key = lookup_user_key(id, 0, 0, KEY_WRITE);
+ key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error;
@@ -378,7 +377,7 @@ long keyctl_keyring_clear(key_serial_t ringid)
struct key *keyring;
long ret;
- keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+ keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
@@ -404,13 +403,13 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
struct key *keyring, *key;
long ret;
- keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+ keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
}
- key = lookup_user_key(id, 1, 0, KEY_LINK);
+ key = lookup_user_key(NULL, id, 1, 0, KEY_LINK);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error2;
@@ -438,13 +437,13 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
struct key *keyring, *key;
long ret;
- keyring = lookup_user_key(ringid, 0, 0, KEY_WRITE);
+ keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
}
- key = lookup_user_key(id, 0, 0, 0);
+ key = lookup_user_key(NULL, id, 0, 0, 0);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error2;
@@ -475,16 +474,29 @@ long keyctl_describe_key(key_serial_t keyid,
char __user *buffer,
size_t buflen)
{
- struct key *key;
+ struct key *key, *instkey;
char *tmpbuf;
long ret;
- key = lookup_user_key(keyid, 0, 1, KEY_VIEW);
+ key = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
if (IS_ERR(key)) {
+ /* viewing a key under construction is permitted if we have the
+ * authorisation token handy */
+ if (PTR_ERR(key) == -EACCES) {
+ instkey = key_get_instantiation_authkey(keyid);
+ if (!IS_ERR(instkey)) {
+ key_put(instkey);
+ key = lookup_user_key(NULL, keyid, 0, 1, 0);
+ if (!IS_ERR(key))
+ goto okay;
+ }
+ }
+
ret = PTR_ERR(key);
goto error;
}
+okay:
/* calculate how much description we're going to return */
ret = -ENOMEM;
tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
@@ -568,7 +580,7 @@ long keyctl_keyring_search(key_serial_t ringid,
goto error2;
/* get the keyring at which to begin the search */
- keyring = lookup_user_key(ringid, 0, 0, KEY_SEARCH);
+ keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error2;
@@ -577,7 +589,7 @@ long keyctl_keyring_search(key_serial_t ringid,
/* get the destination keyring if specified */
dest = NULL;
if (destringid) {
- dest = lookup_user_key(destringid, 1, 0, KEY_WRITE);
+ dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
if (IS_ERR(dest)) {
ret = PTR_ERR(dest);
goto error3;
@@ -656,24 +668,23 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
long ret;
/* find the key first */
- key = lookup_user_key(keyid, 0, 0, 0);
+ key = lookup_user_key(NULL, keyid, 0, 0, 0);
if (!IS_ERR(key)) {
/* see if we can read it directly */
if (key_permission(key, KEY_READ))
goto can_read_key;
- /* can't; see if it's searchable from this process's
- * keyrings */
- ret = -ENOKEY;
- if (key_permission(key, KEY_SEARCH)) {
- /* okay - we do have search permission on the key
- * itself, but do we have the key? */
- skey = search_process_keyrings_aux(key->type, key,
- keyctl_read_key_same);
- if (!IS_ERR(skey))
- goto can_read_key2;
- }
-
+ /* we can't; see if it's searchable from this process's
+ * keyrings
+ * - we automatically take account of the fact that it may be
+ * dangling off an instantiation key
+ */
+ skey = search_process_keyrings(key->type, key,
+ keyctl_read_key_same, current);
+ if (!IS_ERR(skey))
+ goto can_read_key2;
+
+ ret = PTR_ERR(skey);
goto error2;
}
@@ -719,7 +730,7 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
if (uid == (uid_t) -1 && gid == (gid_t) -1)
goto error;
- key = lookup_user_key(id, 1, 1, 0);
+ key = lookup_user_key(NULL, id, 1, 1, 0);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error;
@@ -776,7 +787,7 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
if (perm & ~(KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
goto error;
- key = lookup_user_key(id, 1, 1, 0);
+ key = lookup_user_key(NULL, id, 1, 1, 0);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error;
@@ -809,7 +820,8 @@ long keyctl_instantiate_key(key_serial_t id,
size_t plen,
key_serial_t ringid)
{
- struct key *key, *keyring;
+ struct request_key_auth *rka;
+ struct key *instkey, *keyring;
void *payload;
long ret;
@@ -831,18 +843,21 @@ long keyctl_instantiate_key(key_serial_t id,
goto error2;
}
- /* find the target key (which must be writable) */
- key = lookup_user_key(id, 0, 1, KEY_WRITE);
- if (IS_ERR(key)) {
- ret = PTR_ERR(key);
+ /* find the instantiation authorisation key */
+ instkey = key_get_instantiation_authkey(id);
+ if (IS_ERR(instkey)) {
+ ret = PTR_ERR(instkey);
goto error2;
}
- /* find the destination keyring if present (which must also be
- * writable) */
+ rka = instkey->payload.data;
+
+ /* find the destination keyring amongst those belonging to the
+ * requesting task */
keyring = NULL;
if (ringid) {
- keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+ keyring = lookup_user_key(rka->context, ringid, 1, 0,
+ KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error3;
@@ -850,11 +865,12 @@ long keyctl_instantiate_key(key_serial_t id,
}
/* instantiate the key and link it into a keyring */
- ret = key_instantiate_and_link(key, payload, plen, keyring);
+ ret = key_instantiate_and_link(rka->target_key, payload, plen,
+ keyring, instkey);
key_put(keyring);
error3:
- key_put(key);
+ key_put(instkey);
error2:
kfree(payload);
error:
@@ -869,21 +885,24 @@ long keyctl_instantiate_key(key_serial_t id,
*/
long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
{
- struct key *key, *keyring;
+ struct request_key_auth *rka;
+ struct key *instkey, *keyring;
long ret;
- /* find the target key (which must be writable) */
- key = lookup_user_key(id, 0, 1, KEY_WRITE);
- if (IS_ERR(key)) {
- ret = PTR_ERR(key);
+ /* find the instantiation authorisation key */
+ instkey = key_get_instantiation_authkey(id);
+ if (IS_ERR(instkey)) {
+ ret = PTR_ERR(instkey);
goto error;
}
+ rka = instkey->payload.data;
+
/* find the destination keyring if present (which must also be
* writable) */
keyring = NULL;
if (ringid) {
- keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+ keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error2;
@@ -891,11 +910,11 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
}
/* instantiate the key and link it into a keyring */
- ret = key_negate_and_link(key, timeout, keyring);
+ ret = key_negate_and_link(rka->target_key, timeout, keyring, instkey);
key_put(keyring);
error2:
- key_put(key);
+ key_put(instkey);
error:
return ret;
@@ -903,6 +922,44 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
/*****************************************************************************/
/*
+ * set the default keyring in which request_key() will cache keys
+ * - return the old setting
+ */
+long keyctl_set_reqkey_keyring(int reqkey_defl)
+{
+ int ret;
+
+ switch (reqkey_defl) {
+ case KEY_REQKEY_DEFL_THREAD_KEYRING:
+ ret = install_thread_keyring(current);
+ if (ret < 0)
+ return ret;
+ goto set;
+
+ case KEY_REQKEY_DEFL_PROCESS_KEYRING:
+ ret = install_process_keyring(current);
+ if (ret < 0)
+ return ret;
+
+ case KEY_REQKEY_DEFL_DEFAULT:
+ case KEY_REQKEY_DEFL_SESSION_KEYRING:
+ case KEY_REQKEY_DEFL_USER_KEYRING:
+ case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
+ set:
+ current->jit_keyring = reqkey_defl;
+
+ case KEY_REQKEY_DEFL_NO_CHANGE:
+ return current->jit_keyring;
+
+ case KEY_REQKEY_DEFL_GROUP_KEYRING:
+ default:
+ return -EINVAL;
+ }
+
+} /* end keyctl_set_reqkey_keyring() */
+
+/*****************************************************************************/
+/*
* the key control system call
*/
asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3,
@@ -971,6 +1028,9 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3,
(unsigned) arg3,
(key_serial_t) arg4);
+ case KEYCTL_SET_REQKEY_KEYRING:
+ return keyctl_set_reqkey_keyring(arg2);
+
default:
return -EOPNOTSUPP;
}
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index c9a5de19748..90a551e4da6 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -1,6 +1,6 @@
/* keyring.c: keyring handling
*
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -308,7 +308,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
uid, gid, KEY_USR_ALL, not_in_quota);
if (!IS_ERR(keyring)) {
- ret = key_instantiate_and_link(keyring, NULL, 0, dest);
+ ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
if (ret < 0) {
key_put(keyring);
keyring = ERR_PTR(ret);
@@ -326,11 +326,12 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
* - we only find keys on which we have search permission
* - we use the supplied match function to see if the description (or other
* feature of interest) matches
- * - we readlock the keyrings as we search down the tree
+ * - we rely on RCU to prevent the keyring lists from disappearing on us
* - we return -EAGAIN if we didn't find any matching key
* - we return -ENOKEY if we only found negative matching keys
*/
struct key *keyring_search_aux(struct key *keyring,
+ struct task_struct *context,
struct key_type *type,
const void *description,
key_match_func_t match)
@@ -352,7 +353,7 @@ struct key *keyring_search_aux(struct key *keyring,
/* top keyring must have search permission to begin the search */
key = ERR_PTR(-EACCES);
- if (!key_permission(keyring, KEY_SEARCH))
+ if (!key_task_permission(keyring, context, KEY_SEARCH))
goto error;
key = ERR_PTR(-ENOTDIR);
@@ -392,7 +393,7 @@ struct key *keyring_search_aux(struct key *keyring,
continue;
/* key must have search permissions */
- if (!key_permission(key, KEY_SEARCH))
+ if (!key_task_permission(key, context, KEY_SEARCH))
continue;
/* we set a different error code if we find a negative key */
@@ -418,7 +419,7 @@ struct key *keyring_search_aux(struct key *keyring,
if (sp >= KEYRING_SEARCH_MAX_DEPTH)
continue;
- if (!key_permission(key, KEY_SEARCH))
+ if (!key_task_permission(key, context, KEY_SEARCH))
continue;
/* stack the current position */
@@ -468,7 +469,11 @@ struct key *keyring_search(struct key *keyring,
struct key_type *type,
const char *description)
{
- return keyring_search_aux(keyring, type, description, type->match);
+ if (!type->match)
+ return ERR_PTR(-ENOKEY);
+
+ return keyring_search_aux(keyring, current,
+ type, description, type->match);
} /* end keyring_search() */
@@ -496,7 +501,8 @@ struct key *__keyring_search_one(struct key *keyring,
key = klist->keys[loop];
if (key->type == ktype &&
- key->type->match(key, description) &&
+ (!key->type->match ||
+ key->type->match(key, description)) &&
key_permission(key, perm) &&
!test_bit(KEY_FLAG_REVOKED, &key->flags)
)
@@ -517,6 +523,51 @@ struct key *__keyring_search_one(struct key *keyring,
/*****************************************************************************/
/*
+ * search for an instantiation authorisation key matching a target key
+ * - the RCU read lock must be held by the caller
+ * - a target_id of zero specifies any valid token
+ */
+struct key *keyring_search_instkey(struct key *keyring,
+ key_serial_t target_id)
+{
+ struct request_key_auth *rka;
+ struct keyring_list *klist;
+ struct key *instkey;
+ int loop;
+
+ klist = rcu_dereference(keyring->payload.subscriptions);
+ if (klist) {
+ for (loop = 0; loop < klist->nkeys; loop++) {
+ instkey = klist->keys[loop];
+
+ if (instkey->type != &key_type_request_key_auth)
+ continue;
+
+ rka = instkey->payload.data;
+ if (target_id && rka->target_key->serial != target_id)
+ continue;
+
+ /* the auth key is revoked during instantiation */
+ if (!test_bit(KEY_FLAG_REVOKED, &instkey->flags))
+ goto found;
+
+ instkey = ERR_PTR(-EKEYREVOKED);
+ goto error;
+ }
+ }
+
+ instkey = ERR_PTR(-EACCES);
+ goto error;
+
+found:
+ atomic_inc(&instkey->usage);
+error:
+ return instkey;
+
+} /* end keyring_search_instkey() */
+
+/*****************************************************************************/
+/*
* find a keyring with the specified name
* - all named keyrings are searched
* - only find keyrings with search permission for the process
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 972e3017268..34db087bbcc 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -165,7 +165,7 @@ int install_thread_keyring(struct task_struct *tsk)
/*
* make sure a process keyring is installed
*/
-static int install_process_keyring(struct task_struct *tsk)
+int install_process_keyring(struct task_struct *tsk)
{
unsigned long flags;
struct key *keyring;
@@ -376,12 +376,13 @@ void key_fsgid_changed(struct task_struct *tsk)
* - we return -EAGAIN if we didn't find any matching key
* - we return -ENOKEY if we found only negative matching keys
*/
-struct key *search_process_keyrings_aux(struct key_type *type,
- const void *description,
- key_match_func_t match)
+struct key *search_process_keyrings(struct key_type *type,
+ const void *description,
+ key_match_func_t match,
+ struct task_struct *context)
{
- struct task_struct *tsk = current;
- struct key *key, *ret, *err;
+ struct request_key_auth *rka;
+ struct key *key, *ret, *err, *instkey;
/* 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;
@@ -395,9 +396,9 @@ struct key *search_process_keyrings_aux(struct key_type *type,
err = ERR_PTR(-EAGAIN);
/* search the thread keyring first */
- if (tsk->thread_keyring) {
- key = keyring_search_aux(tsk->thread_keyring, type,
- description, match);
+ if (context->thread_keyring) {
+ key = keyring_search_aux(context->thread_keyring,
+ context, type, description, match);
if (!IS_ERR(key))
goto found;
@@ -415,9 +416,9 @@ struct key *search_process_keyrings_aux(struct key_type *type,
}
/* search the process keyring second */
- if (tsk->signal->process_keyring) {
- key = keyring_search_aux(tsk->signal->process_keyring,
- type, description, match);
+ if (context->signal->process_keyring) {
+ key = keyring_search_aux(context->signal->process_keyring,
+ context, type, description, match);
if (!IS_ERR(key))
goto found;
@@ -434,53 +435,93 @@ struct key *search_process_keyrings_aux(struct key_type *type,
}
}
- /* search the session keyring last */
- if (tsk->signal->session_keyring) {
+ /* search the session keyring */
+ if (context->signal->session_keyring) {
rcu_read_lock();
key = keyring_search_aux(
- rcu_dereference(tsk->signal->session_keyring),
- type, description, match);
+ rcu_dereference(context->signal->session_keyring),
+ context, type, description, match);
rcu_read_unlock();
+
+ if (!IS_ERR(key))
+ goto found;
+
+ switch (PTR_ERR(key)) {
+ case -EAGAIN: /* no key */
+ if (ret)
+ break;
+ case -ENOKEY: /* negative key */
+ ret = key;
+ break;
+ default:
+ err = key;
+ break;
+ }
+
+ /* if this process has a session keyring and that has an
+ * instantiation authorisation key in the bottom level, then we
+ * also search the keyrings of the process mentioned there */
+ if (context != current)
+ goto no_key;
+
+ rcu_read_lock();
+ instkey = __keyring_search_one(
+ rcu_dereference(context->signal->session_keyring),
+ &key_type_request_key_auth, NULL, 0);
+ rcu_read_unlock();
+
+ if (IS_ERR(instkey))
+ goto no_key;
+
+ rka = instkey->payload.data;
+
+ key = search_process_keyrings(type, description, match,
+ rka->context);
+ key_put(instkey);
+
+ if (!IS_ERR(key))
+ goto found;
+
+ switch (PTR_ERR(key)) {
+ case -EAGAIN: /* no key */
+ if (ret)
+ break;
+ case -ENOKEY: /* negative key */
+ ret = key;
+ break;
+ default:
+ err = key;
+ break;
+ }
}
+ /* or search the user-session keyring */
else {
- key = keyring_search_aux(tsk->user->session_keyring,
- type, description, match);
- }
-
- if (!IS_ERR(key))
- goto found;
+ key = keyring_search_aux(context->user->session_keyring,
+ context, type, description, match);
+ if (!IS_ERR(key))
+ goto found;
- switch (PTR_ERR(key)) {
- case -EAGAIN: /* no key */
- if (ret)
+ switch (PTR_ERR(key)) {
+ case -EAGAIN: /* no key */
+ if (ret)
+ break;
+ case -ENOKEY: /* negative key */
+ ret = key;
break;
- case -ENOKEY: /* negative key */
- ret = key;
- break;
- default:
- err = key;
- break;
+ default:
+ err = key;
+ break;
+ }
}
+
+no_key:
/* no key - decide on the error we're going to go for */
key = ret ? ret : err;
- found:
+found:
return key;
-} /* end search_process_keyrings_aux() */
-
-/*****************************************************************************/
-/*
- * search the process keyrings for the first matching key
- * - we return -EAGAIN if we didn't find any matching key
- * - we return -ENOKEY if we found only negative matching keys
- */
-struct key *search_process_keyrings(struct key_type *type,
- const char *description)
-{
- return search_process_keyrings_aux(type, description, type->match);
-
} /* end search_process_keyrings() */
/*****************************************************************************/
@@ -489,72 +530,73 @@ struct key *search_process_keyrings(struct key_type *type,
* - don't create special keyrings unless so requested
* - partially constructed keys aren't found unless requested
*/
-struct key *lookup_user_key(key_serial_t id, int create, int partial,
- key_perm_t perm)
+struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
+ int create, int partial, key_perm_t perm)
{
- struct task_struct *tsk = current;
- unsigned long flags;
struct key *key;
int ret;
+ if (!context)
+ context = current;
+
key = ERR_PTR(-ENOKEY);
switch (id) {
case KEY_SPEC_THREAD_KEYRING:
- if (!tsk->thread_keyring) {
+ if (!context->thread_keyring) {
if (!create)
goto error;
- ret = install_thread_keyring(tsk);
+ ret = install_thread_keyring(context);
if (ret < 0) {
key = ERR_PTR(ret);
goto error;
}
}
- key = tsk->thread_keyring;
+ key = context->thread_keyring;
atomic_inc(&key->usage);
break;
case KEY_SPEC_PROCESS_KEYRING:
- if (!tsk->signal->process_keyring) {
+ if (!context->signal->process_keyring) {
if (!create)
goto error;
- ret = install_process_keyring(tsk);
+ ret = install_process_keyring(context);
if (ret < 0) {
key = ERR_PTR(ret);
goto error;
}
}
- key = tsk->signal->process_keyring;
+ key = context->signal->process_keyring;
atomic_inc(&key->usage);
break;
case KEY_SPEC_SESSION_KEYRING:
- if (!tsk->signal->session_keyring) {
+ if (!context->signal->session_keyring) {
/* always install a session keyring upon access if one
* doesn't exist yet */
ret = install_session_keyring(
- tsk, tsk->user->session_keyring);
+ context, context->user->session_keyring);
if (ret < 0)
goto error;
}
- spin_lock_irqsave(&tsk->sighand->siglock, flags);
- key = tsk->signal->session_keyring;
+ rcu_read_lock();
+ key = rcu_dereference(context->signal->session_keyring);
atomic_inc(&key->usage);
- spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+ rcu_read_unlock();
break;
case KEY_SPEC_USER_KEYRING:
- key = tsk->user->uid_keyring;
+ key = context->user->uid_keyring;
atomic_inc(&key->usage);
break;
case KEY_SPEC_USER_SESSION_KEYRING:
- key = tsk->user->session_keyring;
+ key = context->user->session_keyring;
atomic_inc(&key->usage);
break;
@@ -574,7 +616,7 @@ struct key *lookup_user_key(key_serial_t id, int create, int partial,
break;
}
- /* check the status and permissions */
+ /* check the status */
if (perm) {
ret = key_validate(key);
if (ret < 0)
@@ -585,8 +627,10 @@ struct key *lookup_user_key(key_serial_t id, int create, int partial,
if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
goto invalid_key;
+ /* check the permissions */
ret = -EACCES;
- if (!key_permission(key, perm))
+
+ if (!key_task_permission(key, context, perm))
goto invalid_key;
error:
@@ -609,7 +653,6 @@ struct key *lookup_user_key(key_serial_t id, int create, int partial,
long join_session_keyring(const char *name)
{
struct task_struct *tsk = current;
- unsigned long flags;
struct key *keyring;
long ret;
@@ -619,9 +662,9 @@ long join_session_keyring(const char *name)
if (ret < 0)
goto error;
- spin_lock_irqsave(&tsk->sighand->siglock, flags);
-