summaryrefslogtreecommitdiffstats
path: root/security/keys
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2012-10-28 19:28:52 +0100
committerJiri Kosina <jkosina@suse.cz>2012-10-28 19:29:19 +0100
commit3bd7bf1f0fe14f591c089ae61bbfa9bd356f178a (patch)
tree0058693cc9e70b7461dae551f8a19aff2efd13ca /security/keys
parentf16f84937d769c893492160b1a8c3672e3992beb (diff)
parente657e078d3dfa9f96976db7a2b5fd7d7c9f1f1a6 (diff)
downloadlinux-stable-3bd7bf1f0fe14f591c089ae61bbfa9bd356f178a.tar.gz
linux-stable-3bd7bf1f0fe14f591c089ae61bbfa9bd356f178a.tar.bz2
linux-stable-3bd7bf1f0fe14f591c089ae61bbfa9bd356f178a.zip
Merge branch 'master' into for-next
Sync up with Linus' tree to be able to apply Cesar's patch against newer version of the code. Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'security/keys')
-rw-r--r--security/keys/encrypted-keys/encrypted.c16
-rw-r--r--security/keys/gc.c8
-rw-r--r--security/keys/internal.h6
-rw-r--r--security/keys/key.c139
-rw-r--r--security/keys/keyctl.c70
-rw-r--r--security/keys/keyring.c10
-rw-r--r--security/keys/permission.c14
-rw-r--r--security/keys/proc.c44
-rw-r--r--security/keys/process_keys.c15
-rw-r--r--security/keys/request_key.c6
-rw-r--r--security/keys/request_key_auth.c8
-rw-r--r--security/keys/trusted.c70
-rw-r--r--security/keys/user_defined.c14
13 files changed, 225 insertions, 195 deletions
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index 2d1bb8af7696..9e1e005c7596 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -773,8 +773,8 @@ static int encrypted_init(struct encrypted_key_payload *epayload,
*
* On success, return 0. Otherwise return errno.
*/
-static int encrypted_instantiate(struct key *key, const void *data,
- size_t datalen)
+static int encrypted_instantiate(struct key *key,
+ struct key_preparsed_payload *prep)
{
struct encrypted_key_payload *epayload = NULL;
char *datablob = NULL;
@@ -782,16 +782,17 @@ static int encrypted_instantiate(struct key *key, const void *data,
char *master_desc = NULL;
char *decrypted_datalen = NULL;
char *hex_encoded_iv = NULL;
+ size_t datalen = prep->datalen;
int ret;
- if (datalen <= 0 || datalen > 32767 || !data)
+ if (datalen <= 0 || datalen > 32767 || !prep->data)
return -EINVAL;
datablob = kmalloc(datalen + 1, GFP_KERNEL);
if (!datablob)
return -ENOMEM;
datablob[datalen] = 0;
- memcpy(datablob, data, datalen);
+ memcpy(datablob, prep->data, datalen);
ret = datablob_parse(datablob, &format, &master_desc,
&decrypted_datalen, &hex_encoded_iv);
if (ret < 0)
@@ -834,16 +835,17 @@ static void encrypted_rcu_free(struct rcu_head *rcu)
*
* On success, return 0. Otherwise return errno.
*/
-static int encrypted_update(struct key *key, const void *data, size_t datalen)
+static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
{
struct encrypted_key_payload *epayload = key->payload.data;
struct encrypted_key_payload *new_epayload;
char *buf;
char *new_master_desc = NULL;
const char *format = NULL;
+ size_t datalen = prep->datalen;
int ret = 0;
- if (datalen <= 0 || datalen > 32767 || !data)
+ if (datalen <= 0 || datalen > 32767 || !prep->data)
return -EINVAL;
buf = kmalloc(datalen + 1, GFP_KERNEL);
@@ -851,7 +853,7 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen)
return -ENOMEM;
buf[datalen] = 0;
- memcpy(buf, data, datalen);
+ memcpy(buf, prep->data, datalen);
ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL);
if (ret < 0)
goto out;
diff --git a/security/keys/gc.c b/security/keys/gc.c
index 61ab7c82ebb1..d67c97bb1025 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -62,7 +62,7 @@ void key_schedule_gc(time_t gc_at)
if (gc_at <= now || test_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags)) {
kdebug("IMMEDIATE");
- queue_work(system_nrt_wq, &key_gc_work);
+ schedule_work(&key_gc_work);
} else if (gc_at < key_gc_next_run) {
kdebug("DEFERRED");
key_gc_next_run = gc_at;
@@ -77,7 +77,7 @@ void key_schedule_gc(time_t gc_at)
void key_schedule_gc_links(void)
{
set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags);
- queue_work(system_nrt_wq, &key_gc_work);
+ schedule_work(&key_gc_work);
}
/*
@@ -120,7 +120,7 @@ void key_gc_keytype(struct key_type *ktype)
set_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags);
kdebug("schedule");
- queue_work(system_nrt_wq, &key_gc_work);
+ schedule_work(&key_gc_work);
kdebug("sleep");
wait_on_bit(&key_gc_flags, KEY_GC_REAPING_KEYTYPE, key_gc_wait_bit,
@@ -369,7 +369,7 @@ maybe_resched:
}
if (gc_state & KEY_GC_REAP_AGAIN)
- queue_work(system_nrt_wq, &key_gc_work);
+ schedule_work(&key_gc_work);
kleave(" [end %x]", gc_state);
return;
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 22ff05269e3d..8bbefc3b55d4 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -52,8 +52,7 @@ struct key_user {
atomic_t usage; /* for accessing qnkeys & qnbytes */
atomic_t nkeys; /* number of keys */
atomic_t nikeys; /* number of instantiated keys */
- uid_t uid;
- struct user_namespace *user_ns;
+ kuid_t uid;
int qnkeys; /* number of keys allocated to this user */
int qnbytes; /* number of bytes allocated to this user */
};
@@ -62,8 +61,7 @@ extern struct rb_root key_user_tree;
extern spinlock_t key_user_lock;
extern struct key_user root_key_user;
-extern struct key_user *key_user_lookup(uid_t uid,
- struct user_namespace *user_ns);
+extern struct key_user *key_user_lookup(kuid_t uid);
extern void key_user_put(struct key_user *user);
/*
diff --git a/security/keys/key.c b/security/keys/key.c
index 50d96d4e06f2..a15c9da8f971 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -18,7 +18,6 @@
#include <linux/workqueue.h>
#include <linux/random.h>
#include <linux/err.h>
-#include <linux/user_namespace.h>
#include "internal.h"
struct kmem_cache *key_jar;
@@ -52,7 +51,7 @@ void __key_check(const struct key *key)
* Get the key quota record for a user, allocating a new record if one doesn't
* already exist.
*/
-struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns)
+struct key_user *key_user_lookup(kuid_t uid)
{
struct key_user *candidate = NULL, *user;
struct rb_node *parent = NULL;
@@ -67,13 +66,9 @@ try_again:
parent = *p;
user = rb_entry(parent, struct key_user, node);
- if (uid < user->uid)
+ if (uid_lt(uid, user->uid))
p = &(*p)->rb_left;
- else if (uid > user->uid)
- p = &(*p)->rb_right;
- else if (user_ns < user->user_ns)
- p = &(*p)->rb_left;
- else if (user_ns > user->user_ns)
+ else if (uid_gt(uid, user->uid))
p = &(*p)->rb_right;
else
goto found;
@@ -102,7 +97,6 @@ try_again:
atomic_set(&candidate->nkeys, 0);
atomic_set(&candidate->nikeys, 0);
candidate->uid = uid;
- candidate->user_ns = get_user_ns(user_ns);
candidate->qnkeys = 0;
candidate->qnbytes = 0;
spin_lock_init(&candidate->lock);
@@ -131,7 +125,6 @@ void key_user_put(struct key_user *user)
if (atomic_dec_and_lock(&user->usage, &key_user_lock)) {
rb_erase(&user->node, &key_user_tree);
spin_unlock(&key_user_lock);
- put_user_ns(user->user_ns);
kfree(user);
}
@@ -229,7 +222,7 @@ serial_exists:
* key_alloc() calls don't race with module unloading.
*/
struct key *key_alloc(struct key_type *type, const char *desc,
- uid_t uid, gid_t gid, const struct cred *cred,
+ kuid_t uid, kgid_t gid, const struct cred *cred,
key_perm_t perm, unsigned long flags)
{
struct key_user *user = NULL;
@@ -253,16 +246,16 @@ struct key *key_alloc(struct key_type *type, const char *desc,
quotalen = desclen + type->def_datalen;
/* get hold of the key tracking for this user */
- user = key_user_lookup(uid, cred->user_ns);
+ user = key_user_lookup(uid);
if (!user)
goto no_memory_1;
/* check that the user's quota permits allocation of another key and
* its description */
if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
- unsigned maxkeys = (uid == 0) ?
+ unsigned maxkeys = uid_eq(uid, GLOBAL_ROOT_UID) ?
key_quota_root_maxkeys : key_quota_maxkeys;
- unsigned maxbytes = (uid == 0) ?
+ unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ?
key_quota_root_maxbytes : key_quota_maxbytes;
spin_lock(&user->lock);
@@ -380,7 +373,7 @@ int key_payload_reserve(struct key *key, size_t datalen)
/* contemplate the quota adjustment */
if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
- unsigned maxbytes = (key->user->uid == 0) ?
+ unsigned maxbytes = uid_eq(key->user->uid, GLOBAL_ROOT_UID) ?
key_quota_root_maxbytes : key_quota_maxbytes;
spin_lock(&key->user->lock);
@@ -412,8 +405,7 @@ EXPORT_SYMBOL(key_payload_reserve);
* key_construction_mutex.
*/
static int __key_instantiate_and_link(struct key *key,
- const void *data,
- size_t datalen,
+ struct key_preparsed_payload *prep,
struct key *keyring,
struct key *authkey,
unsigned long *_prealloc)
@@ -431,7 +423,7 @@ static int __key_instantiate_and_link(struct key *key,
/* can't instantiate twice */
if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
/* instantiate the key */
- ret = key->type->instantiate(key, data, datalen);
+ ret = key->type->instantiate(key, prep);
if (ret == 0) {
/* mark the key as being instantiated */
@@ -482,22 +474,37 @@ int key_instantiate_and_link(struct key *key,
struct key *keyring,
struct key *authkey)
{
+ struct key_preparsed_payload prep;
unsigned long prealloc;
int ret;
+ memset(&prep, 0, sizeof(prep));
+ prep.data = data;
+ prep.datalen = datalen;
+ prep.quotalen = key->type->def_datalen;
+ if (key->type->preparse) {
+ ret = key->type->preparse(&prep);
+ if (ret < 0)
+ goto error;
+ }
+
if (keyring) {
ret = __key_link_begin(keyring, key->type, key->description,
&prealloc);
if (ret < 0)
- return ret;
+ goto error_free_preparse;
}
- ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey,
+ ret = __key_instantiate_and_link(key, &prep, keyring, authkey,
&prealloc);
if (keyring)
__key_link_end(keyring, key->type, prealloc);
+error_free_preparse:
+ if (key->type->preparse)
+ key->type->free_preparse(&prep);
+error:
return ret;
}
@@ -598,7 +605,7 @@ void key_put(struct key *key)
key_check(key);
if (atomic_dec_and_test(&key->usage))
- queue_work(system_nrt_wq, &key_gc_work);
+ schedule_work(&key_gc_work);
}
}
EXPORT_SYMBOL(key_put);
@@ -706,7 +713,7 @@ void key_type_put(struct key_type *ktype)
* if we get an error.
*/
static inline key_ref_t __key_update(key_ref_t key_ref,
- const void *payload, size_t plen)
+ struct key_preparsed_payload *prep)
{
struct key *key = key_ref_to_ptr(key_ref);
int ret;
@@ -722,7 +729,7 @@ static inline key_ref_t __key_update(key_ref_t key_ref,
down_write(&key->sem);
- ret = key->type->update(key, payload, plen);
+ ret = key->type->update(key, prep);
if (ret == 0)
/* updating a negative key instantiates it */
clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
@@ -774,6 +781,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
unsigned long flags)
{
unsigned long prealloc;
+ struct key_preparsed_payload prep;
const struct cred *cred = current_cred();
struct key_type *ktype;
struct key *keyring, *key = NULL;
@@ -789,8 +797,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
}
key_ref = ERR_PTR(-EINVAL);
- if (!ktype->match || !ktype->instantiate)
- goto error_2;
+ if (!ktype->match || !ktype->instantiate ||
+ (!description && !ktype->preparse))
+ goto error_put_type;
keyring = key_ref_to_ptr(keyring_ref);
@@ -798,18 +807,37 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
key_ref = ERR_PTR(-ENOTDIR);
if (keyring->type != &key_type_keyring)
- goto error_2;
+ goto error_put_type;
+
+ memset(&prep, 0, sizeof(prep));
+ prep.data = payload;
+ prep.datalen = plen;
+ prep.quotalen = ktype->def_datalen;
+ if (ktype->preparse) {
+ ret = ktype->preparse(&prep);
+ if (ret < 0) {
+ key_ref = ERR_PTR(ret);
+ goto error_put_type;
+ }
+ if (!description)
+ description = prep.description;
+ key_ref = ERR_PTR(-EINVAL);
+ if (!description)
+ goto error_free_prep;
+ }
ret = __key_link_begin(keyring, ktype, description, &prealloc);
- if (ret < 0)
- goto error_2;
+ if (ret < 0) {
+ key_ref = ERR_PTR(ret);
+ goto error_free_prep;
+ }
/* if we're going to allocate a new key, we're going to have
* to modify the keyring */
ret = key_permission(keyring_ref, KEY_WRITE);
if (ret < 0) {
key_ref = ERR_PTR(ret);
- goto error_3;
+ goto error_link_end;
}
/* if it's possible to update this type of key, search for an existing
@@ -840,25 +868,27 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
perm, flags);
if (IS_ERR(key)) {
key_ref = ERR_CAST(key);
- goto error_3;
+ goto error_link_end;
}
/* instantiate it and link it into the target keyring */
- ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL,
- &prealloc);
+ ret = __key_instantiate_and_link(key, &prep, keyring, NULL, &prealloc);
if (ret < 0) {
key_put(key);
key_ref = ERR_PTR(ret);
- goto error_3;
+ goto error_link_end;
}
key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
- error_3:
+error_link_end:
__key_link_end(keyring, ktype, prealloc);
- error_2:
+error_free_prep:
+ if (ktype->preparse)
+ ktype->free_preparse(&prep);
+error_put_type:
key_type_put(ktype);
- error:
+error:
return key_ref;
found_matching_key:
@@ -866,10 +896,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
* - we can drop the locks first as we have the key pinned
*/
__key_link_end(keyring, ktype, prealloc);
- key_type_put(ktype);
- key_ref = __key_update(key_ref, payload, plen);
- goto error;
+ key_ref = __key_update(key_ref, &prep);
+ goto error_free_prep;
}
EXPORT_SYMBOL(key_create_or_update);
@@ -888,6 +917,7 @@ EXPORT_SYMBOL(key_create_or_update);
*/
int key_update(key_ref_t key_ref, const void *payload, size_t plen)
{
+ struct key_preparsed_payload prep;
struct key *key = key_ref_to_ptr(key_ref);
int ret;
@@ -900,18 +930,31 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
/* attempt to update it if supported */
ret = -EOPNOTSUPP;
- if (key->type->update) {
- down_write(&key->sem);
-
- ret = key->type->update(key, payload, plen);
- if (ret == 0)
- /* updating a negative key instantiates it */
- clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
+ if (!key->type->update)
+ goto error;
- up_write(&key->sem);
+ memset(&prep, 0, sizeof(prep));
+ prep.data = payload;
+ prep.datalen = plen;
+ prep.quotalen = key->type->def_datalen;
+ if (key->type->preparse) {
+ ret = key->type->preparse(&prep);
+ if (ret < 0)
+ goto error;
}
- error:
+ down_write(&key->sem);
+
+ ret = key->type->update(key, &prep);
+ if (ret == 0)
+ /* updating a negative key instantiates it */
+ clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
+
+ up_write(&key->sem);
+
+ if (key->type->preparse)
+ key->type->free_preparse(&prep);
+error:
return ret;
}
EXPORT_SYMBOL(key_update);
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 3364fbf46807..5d34b4e827d6 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -46,6 +46,9 @@ static int key_get_type_from_user(char *type,
* Extract the description of a new key from userspace and either add it as a
* new key to the specified keyring or update a matching key in that keyring.
*
+ * If the description is NULL or an empty string, the key type is asked to
+ * generate one from the payload.
+ *
* The keyring must be writable so that we can attach the key to it.
*
* If successful, the new key's serial number is returned, otherwise an error
@@ -72,10 +75,17 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
if (ret < 0)
goto error;
- description = strndup_user(_description, PAGE_SIZE);
- if (IS_ERR(description)) {
- ret = PTR_ERR(description);
- goto error;
+ description = NULL;
+ if (_description) {
+ description = strndup_user(_description, PAGE_SIZE);
+ if (IS_ERR(description)) {
+ ret = PTR_ERR(description);
+ goto error;
+ }
+ if (!*description) {
+ kfree(description);
+ description = NULL;
+ }
}
/* pull the payload in if one was supplied */
@@ -569,8 +579,8 @@ okay:
ret = snprintf(tmpbuf, PAGE_SIZE - 1,
"%s;%d;%d;%08x;%s",
key->type->name,
- key->uid,
- key->gid,
+ from_kuid_munged(current_user_ns(), key->uid),
+ from_kgid_munged(current_user_ns(), key->gid),
key->perm,
key->description ?: "");
@@ -766,15 +776,25 @@ error:
*
* If successful, 0 will be returned.
*/
-long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
+long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group)
{
struct key_user *newowner, *zapowner = NULL;
struct key *key;
key_ref_t key_ref;
long ret;
+ kuid_t uid;
+ kgid_t gid;
+
+ uid = make_kuid(current_user_ns(), user);
+ gid = make_kgid(current_user_ns(), group);
+ ret = -EINVAL;
+ if ((user != (uid_t) -1) && !uid_valid(uid))
+ goto error;
+ if ((group != (gid_t) -1) && !gid_valid(gid))
+ goto error;
ret = 0;
- if (uid == (uid_t) -1 && gid == (gid_t) -1)
+ if (user == (uid_t) -1 && group == (gid_t) -1)
goto error;
key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
@@ -792,27 +812,27 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
if (!capable(CAP_SYS_ADMIN)) {
/* only the sysadmin can chown a key to some other UID */
- if (uid != (uid_t) -1 && key->uid != uid)
+ if (user != (uid_t) -1 && !uid_eq(key->uid, uid))
goto error_put;
/* only the sysadmin can set the key's GID to a group other
* than one of those that the current process subscribes to */
- if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid))
+ if (group != (gid_t) -1 && !gid_eq(gid, key->gid) && !in_group_p(gid))
goto error_put;
}
/* change the UID */
- if (uid != (uid_t) -1 && uid != key->uid) {
+ if (user != (uid_t) -1 && !uid_eq(uid, key->uid)) {
ret = -ENOMEM;
- newowner = key_user_lookup(uid, current_user_ns());
+ newowner = key_user_lookup(uid);
if (!newowner)
goto error_put;
/* transfer the quota burden to the new user */
if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
- unsigned maxkeys = (uid == 0) ?
+ unsigned maxkeys = uid_eq(uid, GLOBAL_ROOT_UID) ?
key_quota_root_maxkeys : key_quota_maxkeys;
- unsigned maxbytes = (uid == 0) ?
+ unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ?
key_quota_root_maxbytes : key_quota_maxbytes;
spin_lock(&newowner->lock);
@@ -846,7 +866,7 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
}
/* change the GID */
- if (gid != (gid_t) -1)
+ if (group != (gid_t) -1)
key->gid = gid;
ret = 0;
@@ -897,7 +917,7 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
down_write(&key->sem);
/* if we're not the sysadmin, we can only change a key that we own */
- if (capable(CAP_SYS_ADMIN) || key->uid == current_fsuid()) {
+ if (capable(CAP_SYS_ADMIN) || uid_eq(key->uid, current_fsuid())) {
key->perm = perm;
ret = 0;
}
@@ -1486,7 +1506,6 @@ long keyctl_session_to_parent(void)
oldwork = NULL;
parent = me->real_parent;
- task_lock(parent);
/* the parent mustn't be init and mustn't be a kernel thread */
if (parent->pid <= 1 || !parent->mm)
goto unlock;
@@ -1507,18 +1526,18 @@ long keyctl_session_to_parent(void)
/* the parent must have the same effective ownership and mustn't be
* SUID/SGID */
- if (pcred->uid != mycred->euid ||
- pcred->euid != mycred->euid ||
- pcred->suid != mycred->euid ||
- pcred->gid != mycred->egid ||
- pcred->egid != mycred->egid ||
- pcred->sgid != mycred->egid)
+ if (!uid_eq(pcred->uid, mycred->euid) ||
+ !uid_eq(pcred->euid, mycred->euid) ||
+ !uid_eq(pcred->suid, mycred->euid) ||
+ !gid_eq(pcred->gid, mycred->egid) ||
+ !gid_eq(pcred->egid, mycred->egid) ||
+ !gid_eq(pcred->sgid, mycred->egid))
goto unlock;
/* the keyrings must have the same UID */
if ((pcred->tgcred->session_keyring &&
- pcred->tgcred->session_keyring->uid != mycred->euid) ||
- mycred->tgcred->session_keyring->uid != mycred->euid)
+ !uid_eq(pcred->tgcred->session_keyring->uid, mycred->euid)) ||
+ !uid_eq(mycred->tgcred->session_keyring->uid, mycred->euid))
goto unlock;
/* cancel an already pending keyring replacement */
@@ -1530,7 +1549,6 @@ long keyctl_session_to_parent(void)
if (!ret)
newwork = NULL;
unlock:
- task_unlock(parent);
write_unlock_irq(&tasklist_lock);
rcu_read_unlock();
if (oldwork)
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 81e7852d281d..6e42df15a24c 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -66,7 +66,7 @@ static inline unsigned keyring_hash(const char *desc)
* operations.
*/
static int keyring_instantiate(struct key *keyring,
- const void *data, size_t datalen);
+ struct key_preparsed_payload *prep);
static int keyring_match(const struct key *keyring, const void *criterion);
static void keyring_revoke(struct key *keyring);
static void keyring_destroy(struct key *keyring);
@@ -121,12 +121,12 @@ static void keyring_publish_name(struct key *keyring)
* Returns 0 on success, -EINVAL if given any data.
*/
static int keyring_instantiate(struct key *keyring,
- const void *data, size_t datalen)
+ struct key_preparsed_payload *prep)
{
int ret;
ret = -EINVAL;
- if (datalen == 0) {
+ if (prep->datalen == 0) {
/* make the keyring available by name if it has one */
keyring_publish_name(keyring);
ret = 0;
@@ -256,7 +256,7 @@ error:
/*
* Allocate a keyring and link into the destination keyring.
*/
-struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
+struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
const struct cred *cred, unsigned long flags,
struct key *dest)
{
@@ -612,7 +612,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
&keyring_name_hash[bucket],
type_data.link
) {
- if (keyring->user->user_ns != current_user_ns())
+ if (!kuid_has_mapping(current_user_ns(), keyring->user->uid))
continue;
if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
diff --git a/security/keys/permission.c b/security/keys/permission.c
index 0b4d019e027d..efcc0c855a0d 100644
--- a/security/keys/permission.c
+++ b/security/keys/permission.c
@@ -36,33 +36,27 @@ int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
key = key_ref_to_ptr(key_ref);
- if (key->user->user_ns != cred->user_ns)
- goto use_other_perms;
-
/* use the second 8-bits of permissions for keys the caller owns */
- if (key->uid == cred->fsuid) {
+ if (uid_eq(key->uid, cred->fsuid)) {
kperm = key->perm >> 16;
goto use_these_perms;
}
/* use the third 8-bits of permissions for keys the caller has a group
* membership in common with */
- if (key->gid != -1 && key->perm & KEY_GRP_ALL) {
- if (key->gid == cred->fsgid) {
+ if (gid_valid(key->gid) && key->perm & KEY_GRP_ALL) {
+ if (gid_eq(key->gid, cred->fsgid)) {
kperm = key->perm >> 8;
goto use_these_perms;
}
- ret = groups_search(cred->group_info,
- make_kgid(current_user_ns(), key->gid));
+ ret = groups_search(cred->group_info, key->gid);
if (ret) {
kperm = key->perm >> 8;
goto use_these_perms;
}
}
-use_other_perms:
-
/* otherwise use the least-significant 8-bits */
kperm = key->perm;
diff --git a/security/keys/proc.c b/security/keys/proc.c
index 30d1ddfd9cef..217b6855e815 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -88,14 +88,14 @@ __initcall(key_proc_init);
*/
#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
-static struct rb_node *key_serial_next(struct rb_node *n)
+static struct rb_node *key_serial_next(struct seq_file *p, struct rb_node *n)
{
- struct user_namespace *user_ns = current_user_ns();
+ struct user_namespace *user_ns = seq_user_ns(p);
n = rb_next(n);
while (n) {
struct key *key = rb_entry(n, struct key, serial_node);
- if (key->user->user_ns == user_ns)
+ if (kuid_has_mapping(user_ns, key->user->uid))
break;
n = rb_next(n);
}
@@ -107,9 +107,9 @@ static int proc_keys_open(struct inode *inode, struct file *file)
return seq_open(file, &proc_keys_ops);
}
-static struct key *find_ge_key(key_serial_t id)
+static struct key *find_ge_key(struct seq_file *p, key_serial_t id)
{
- struct user_namespace *user_ns = current_user_ns();
+ struct user_namespace *user_ns = seq_user_ns(p);
struct rb_node *n = key_serial_tree.rb_node;
struct key *minkey = NULL;
@@ -132,7 +132,7 @@ static struct key *find_ge_key(key_serial_t id)
return NULL;
for (;;) {
- if (minkey->user->user_ns == user_ns)
+ if (kuid_has_mapping(user_ns, minkey->user->uid))
return minkey;
n = rb_next(&minkey->serial_node);
if (!n)
@@ -151,7 +151,7 @@ static void *proc_keys_start(struct seq_file *p, loff_t *_pos)
if (*_pos > INT_MAX)
return NULL;
- key = find_ge_key(pos);
+ key = find_ge_key(p, pos);
if (!key)
return NULL;
*_pos = key->serial;
@@ -168,7 +168,7 @@ static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos)
{
struct rb_node *n;
- n = key_serial_next(v);
+ n = key_serial_next(p, v);
if (n)
*_pos = key_node_serial(n);
return n;
@@ -254,8 +254,8 @@ static int proc_keys_show(struct seq_file *m, void *v)
atomic_read(&key->usage),
xbuf,
key->perm,
- key->uid,
- key->gid,
+ from_kuid_munged(seq_user_ns(m), key->uid),
+ from_kgid_munged(seq_user_ns(m), key->gid),
key->type->name);
#undef showflag
@@ -270,26 +270,26 @@ static int proc_keys_show(struct seq_file *m, void *v)
#endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */
-static struct rb_node *__key_user_next(struct rb_node *n)
+static struct rb_node *__key_user_next(struct user_namespace *user_ns, struct rb_node *n)
{
while (n) {
struct key_user *user = rb_entry(n, struct key_user, node);
- if (user->user_ns == current_user_ns())
+ if (kuid_has_mapping(user_ns, user->uid))
break;
n = rb_next(n);
}
return n;
}
-static struct rb_node *key_user_next(struct rb_node *n)
+static struct rb_node *key_user_next(struct user_namespace *user_ns, struct rb_node *n)
{
- return __key_user_next(rb_next(n));
+ return __key_user_next(user_ns, rb_next(n));
}
-static struct rb_node *key_user_first(struct rb_root *r)
+static struct rb_node *key_user_first(struct user_namespace *user_ns, struct rb_root *r)
{
struct rb_node *n = rb_first(r);
- return __key_user_next(n);
+ return __key_user_next(user_ns, n);
}
/*
@@ -309,10 +309,10 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos)
spin_lock(&key_user_lock);
- _p = key_user_first(&key_user_tree);
+ _p = key_user_first(seq_user_ns(p), &key_user_tree);
while (pos > 0 && _p) {
pos--;
- _p = key_user_next(_p);
+ _p = key_user_next(seq_user_ns(p), _p);
}
return _p;
@@ -321,7 +321,7 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos)
static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos)
{
(*_pos)++;
- return key_user_next((struct rb_node *)v);
+ return key_user_next(seq_user_ns(p), (struct rb_node *)v);
}
static void proc_key_users_stop(struct seq_file *p, void *v)
@@ -334,13 +334,13 @@ static int proc_key_users_show(struct seq_file *m, void *v)
{
struct rb_node *_p = v;
struct key_user *user = rb_entry(_p, struct key_user, node);
- unsigned maxkeys = (user->uid == 0) ?
+ unsigned maxkeys = uid_eq(user->uid, GLOBAL_ROOT_UID) ?
key_quota_root_maxkeys : key_quota_maxkeys;
- unsigned maxbytes = (user->uid == 0) ?
+ unsigned maxbytes = uid_eq(user->uid, GLOBAL_ROOT_UID) ?
key_quota_root_maxbytes : key_quota_maxbytes;
seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n",
- user->uid,
+ from_kuid_munged(seq_user_ns(m), user->uid),
atomic_read(&user->usage),
atomic_read(&user->nkeys),
atomic_read(&user->nikeys),
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 178b8c3b130a..86468f385fc8 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -34,8 +34,7 @@ struct key_user root_key_user = {
.lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock),
.nkeys = ATOMIC_INIT(2),
.nikeys = ATOMIC_INIT(2),
- .uid = 0,
- .user_ns = &init_user_ns,
+ .uid = GLOBAL_ROOT_UID,
};
/*
@@ -48,11 +47,13 @@ int install_user_keyrings(void)
struct key *uid_keyring, *session_keyring;
char buf[20];
int ret;
+ uid_t uid;
cred = current_cred();
user = cred->user;
+ uid = from_kuid(cred->user_ns, user->uid);
- kenter("%p{%u}", user, user->uid);
+ kenter("%p{%u}", user, uid);
if (user->uid_keyring) {
kleave(" = 0 [exist]");
@@ -67,11 +68,11 @@ int install_user_keyrings(void)
* - there may be one in existence already as it may have been
* pinned by a session, but the user_struct pointing to it
* may have been destroyed by setuid */
- sprintf(buf, "_uid.%u", user->uid);
+ sprintf(buf, "_uid.%u", uid);
uid_keyring = find_keyring_by_name(buf, true);
if (IS_ERR(uid_keyring)) {
- uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
+ uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID,
cred, KEY_ALLOC_IN_QUOTA,
NULL);
if (IS_ERR(uid_keyring)) {
@@ -82,12 +83,12 @@ int install_user_keyrings(void)
/* get a default session keyring (which might also exist
* already) */
- sprintf(buf, "_uid_ses.%u", user->uid);
+ sprintf(buf, "_uid_ses.%u", uid);
session_keyring = find_keyring_by_name(buf, true);
if (IS_ERR(session_keyring)) {
session_keyring =
- keyring_alloc(buf, user->uid, (gid_t) -1,
+ keyring_alloc(buf, user->uid, INVALID_GID,
cred, KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(session_keyring)) {
ret = PTR_ERR(session_keyring);
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 000e75017520..66e21184b559 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -139,8 +139,8 @@ static int call_sbin_request_key(struct key_construction *cons,
goto error_link;
/* record the UID and GID */
- sprintf(uid_str, "%d", cred->fsuid);
- sprintf(gid_str, "%d", cred->fsgid);
+ sprintf(uid_str, "%d", from_kuid(&init_user_ns, cred->fsuid));
+ sprintf(gid_str, "%d", from_kgid(&init_user_ns, cred->fsgid));
/* we say which key is under construction */
sprintf(key_str, "%d", key->serial);
@@ -442,7 +442,7 @@ static struct key *construct_key_and_link(struct key_type *type,
kenter("");
- user = key_user_lookup(current_fsuid(), current_user_ns());
+ user = key_user_lookup(current_fsuid());
if (!user)
return ERR_PTR(-ENOMEM);
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index 60d4e3f5e4bb..85730d5a5a59 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -19,7 +19,8 @@
#include <asm/uaccess.h>
#include "internal.h"
-static int request_key_auth_instantiate(struct key *, const void *, size_t);
+static int request_key_auth_instantiate(struct key *,
+ struct key_preparsed_payload *);
static void request_key_auth_describe(const struct key *, struct seq_file *);
static void request_key_auth_revoke(struct key *);
static void request_key_auth_destroy(struct key *);
@@ -42,10 +43,9 @@ struct key_type key_type_request_key_auth = {
* Instantiate a request-key authorisation key.
*/
static int request_key_auth_instantiate(struct key *key,
- const void *data,
- size_t datalen)
+ struct key_preparsed_payload *prep)
{
- key->payload.data = (struct request_key_auth *) data;
+ key->payload.data = (struct request_key_auth *)prep->data;
return 0;
}
diff --git a/security/keys/trusted.c b/security/keys/trusted.c
index 2d5d041f2049..e13fcf7636f7 100644
--- a/security/keys/trusted.c
+++ b/security/keys/trusted.c
@@ -369,38 +369,6 @@ static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd,
}
/*
- * get a random value from TPM
- */
-static int tpm_get_random(struct tpm_buf *tb, unsigned char *buf, uint32_t len)
-{
- int ret;
-
- INIT_BUF(tb);
- store16(tb, TPM_TAG_RQU_COMMAND);
- store32(tb, TPM_GETRANDOM_SIZE);
- store32(tb, TPM_ORD_GETRANDOM);
- store32(tb, len);
- ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, sizeof tb->data);
- if (!ret)
- memcpy(buf, tb->data + TPM_GETRANDOM_SIZE, len);
- return ret;
-}
-
-static int my_get_random(unsigned char *buf, int len)
-{
- struct tpm_buf *tb;
- int ret;
-
- tb = kmalloc(sizeof *tb, GFP_KERNEL);
- if (!tb)
- return -ENOMEM;
- ret = tpm_get_random(tb, buf, len);
-
- kfree(tb);
- return ret;
-}
-
-/*
* Lock a trusted key, by extending a selected PCR.
*
* Prevents a trusted key that is sealed to PCRs from being accessed.
@@ -413,8 +381,8 @@ static int pcrlock(const int pcrnum)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- ret = my_get_random(hash, SHA1_DIGEST_SIZE);
- if (ret < 0)
+ ret = tpm_get_random(TPM_ANY_NUM, hash, SHA1_DIGEST_SIZE);
+ if (ret != SHA1_DIGEST_SIZE)
return ret;
return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0;
}
@@ -429,8 +397,8 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
unsigned char ononce[TPM_NONCE_SIZE];
int ret;
- ret = tpm_get_random(tb, ononce, TPM_NONCE_SIZE);
- if (ret < 0)
+ ret = tpm_get_random(TPM_ANY_NUM, ononce, TPM_NONCE_SIZE);
+ if (ret != TPM_NONCE_SIZE)
return ret;
INIT_BUF(tb);
@@ -524,8 +492,8 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
if (ret < 0)
goto out;
- ret = tpm_get_random(tb, td->nonceodd, TPM_NONCE_SIZE);
- if (ret < 0)
+ ret = tpm_get_random(TPM_ANY_NUM, td->nonceodd, TPM_NONCE_SIZE);
+ if (ret != TPM_NONCE_SIZE)
goto out;
ordinal = htonl(TPM_ORD_SEAL);
datsize = htonl(datalen);
@@ -634,8 +602,8 @@ static int tpm_unseal(struct tpm_buf *tb,
ordinal = htonl(TPM_ORD_UNSEAL);
keyhndl = htonl(SRKHANDLE);
- ret = tpm_get_random(tb, nonceodd, TPM_NONCE_SIZE);
- if (ret < 0) {
+ ret = tpm_get_random(TPM_ANY_NUM, nonceodd, TPM_NONCE_SIZE);
+ if (ret != TPM_NONCE_SIZE) {
pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
return ret;
}
@@ -927,22 +895,24 @@ static struct trusted_key_payload *trusted_payload_alloc(struct key *key)
*
* On success, return 0. Otherwise return errno.
*/
-static int trusted_instantiate(struct key *key, const void *data,
- size_t datalen)
+static int trusted_instantiate(struct key *key,
+ struct key_preparsed_payload *prep)
{
struct trusted_key_payload *payload = NULL;
struct trusted_key_options *options = NULL;
+ size_t datalen = prep->datalen;
char *datablob;
int ret = 0;
int key_cmd;
+ size_t key_len;
- if (datalen <= 0 || datalen > 32767 || !data)
+ if (datalen <= 0 || datalen > 32767 || !prep->data)
return -EINVAL;
datablob = kmalloc(datalen + 1, GFP_KERNEL);
if (!datablob)
return -ENOMEM;
- memcpy(datablob, data, datalen);
+ memcpy(datablob, prep->data, datalen);
datablob[datalen] = '\0';
options = trusted_options_alloc();
@@ -974,8 +944,9 @@ static int trusted_instantiate(struct key *key, const void *data,
pr_info("trusted_key: key_unseal failed (%d)\n", ret);
break;
case Opt_new:
- ret = my_get_random(payload->key, payload->key_len);
- if (ret < 0) {
+ key_len = payload->key_len;
+ ret = tpm_get_random(TPM_ANY_NUM, payload->key, key_len);
+ if (ret != key_len) {
pr_info("trusted_key: key_create failed (%d)\n", ret);
goto out;
}
@@ -1011,17 +982,18 @@ static void trusted_rcu_free(struct rcu_head *rcu)
/*
* trusted_update - reseal an existing key with new PCR values
*/
-static int trusted_update(struct key *key, const void *data, size_t datalen)
+static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
{
struct trusted_key_payload *p = key->payload.data;
struct trusted_key_payload *new_p;
struct trusted_key_options *new_o;
+ size_t datalen = prep->datalen;
char *datablob;
int ret = 0;
if (!p->migratable)
return -EPERM;
- if (datalen <= 0 || datalen > 32767 || !data)
+ if (datalen <= 0 || datalen > 32767 || !prep->data)
return -EINVAL;
datablob = kmalloc(datalen + 1, GFP_KERNEL);
@@ -1038,7 +1010,7 @@ static int trusted_update(struct key *key, const void *data, size_t datalen)
goto out;
}
- memcpy(datablob, data, datalen);
+ memcpy(datablob, prep->data, datalen);
datablob[datalen] = '\0';
ret = datablob_parse(datablob, new_p, new_o);
if (ret != Opt_update) {
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index c7660a25a3e4..55dc88939185 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -58,13 +58,14 @@ EXPORT_SYMBOL_GPL(key_type_logon);
/*
* instantiate a user defined key
*/
-int user_instantiate(struct key *key, const void *data, size_t datalen)
+int user_instantiate(struct key *key, struct key_preparsed_payload *prep)
{
struct user_key_payload *upayload;
+ size_t datalen = prep->datalen;
int ret;
ret = -EINVAL;
- if (datalen <= 0 || datalen > 32767 || !data)
+ if (datalen <= 0 || datalen > 32767 || !prep->data)
goto error;
ret = key_payload_reserve(key, datalen);
@@ -78,7 +79,7 @@ int user_instantiate(struct key *key, const void *data, size_t datalen)
/* attach the data */
upayload->datalen = datalen;
- memcpy(upayload->data, data, datalen);
+ memcpy(upayload->data, prep->data, datalen);
rcu_assign_keypointer(key, upayload);
ret = 0;
@@ -92,13 +93,14 @@ EXPORT_SYMBOL_GPL(user_instantiate);
* update a user defined key
* - the key's semaphore is write-locked
*/
-int user_update(struct key *key, const void *data, size_t datalen)
+int user_update(struct key *key, struct key_preparsed_payload *prep)
{
struct user_key_payload *upayload, *zap;
+ size_t datalen = prep->datalen;
int ret;
ret = -EINVAL;
- if (datalen <= 0 || datalen > 32767 || !data)
+ if (datalen <= 0 || datalen > 32767 || !prep->data)
goto error;
/* construct a replacement payload */
@@ -108,7 +110,7 @@ int user_update(struct key *key, const void *data, size_t datalen)
goto error;
upayload->datalen = datalen;
- memcpy(upayload->data, data, datalen);
+ memcpy(upayload->data, prep->data, datalen);
/* check the quota and attach the new data */
zap = upayload;