diff options
author | Serge E. Hallyn <serue@us.ibm.com> | 2009-02-26 18:27:38 -0600 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2009-02-27 12:35:06 +1100 |
commit | 1d1e97562e5e2ac60fb7b25437ba619f95f67fab (patch) | |
tree | 68a9c52ecbff0782dd9b9438685afc3b40b6f707 | |
parent | be38e0fd5f90a91d09e0a85ffb294b70a7be6259 (diff) | |
download | linux-1d1e97562e5e2ac60fb7b25437ba619f95f67fab.tar.gz linux-1d1e97562e5e2ac60fb7b25437ba619f95f67fab.tar.bz2 linux-1d1e97562e5e2ac60fb7b25437ba619f95f67fab.zip |
keys: distinguish per-uid keys in different namespaces
per-uid keys were looked by uid only. Use the user namespace
to distinguish the same uid in different namespaces.
This does not address key_permission. So a task can for instance
try to join a keyring owned by the same uid in another namespace.
That will be handled by a separate patch.
Signed-off-by: Serge E. Hallyn <serue@us.ibm.com>
Acked-by: David Howells <dhowells@redhat.com>
Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r-- | kernel/user.c | 2 | ||||
-rw-r--r-- | security/keys/internal.h | 4 | ||||
-rw-r--r-- | security/keys/key.c | 11 | ||||
-rw-r--r-- | security/keys/keyctl.c | 2 | ||||
-rw-r--r-- | security/keys/process_keys.c | 2 | ||||
-rw-r--r-- | security/keys/request_key.c | 2 |
6 files changed, 17 insertions, 6 deletions
diff --git a/kernel/user.c b/kernel/user.c index 477b6660f447..d8b332c3ae3a 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -20,7 +20,7 @@ struct user_namespace init_user_ns = { .kref = { - .refcount = ATOMIC_INIT(1), + .refcount = ATOMIC_INIT(2), }, .creator = &root_user, }; diff --git a/security/keys/internal.h b/security/keys/internal.h index 81932abefe7b..9fb679c66b8a 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -53,6 +53,7 @@ struct key_user { atomic_t nkeys; /* number of keys */ atomic_t nikeys; /* number of instantiated keys */ uid_t uid; + struct user_namespace *user_ns; int qnkeys; /* number of keys allocated to this user */ int qnbytes; /* number of bytes allocated to this user */ }; @@ -61,7 +62,8 @@ 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); +extern struct key_user *key_user_lookup(uid_t uid, + struct user_namespace *user_ns); extern void key_user_put(struct key_user *user); /* diff --git a/security/keys/key.c b/security/keys/key.c index f76c8a546fd3..4a1297d1ada4 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -18,6 +18,7 @@ #include <linux/workqueue.h> #include <linux/random.h> #include <linux/err.h> +#include <linux/user_namespace.h> #include "internal.h" static struct kmem_cache *key_jar; @@ -60,7 +61,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 key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns) { struct key_user *candidate = NULL, *user; struct rb_node *parent = NULL; @@ -79,6 +80,10 @@ struct key_user *key_user_lookup(uid_t 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) + p = &(*p)->rb_right; else goto found; } @@ -106,6 +111,7 @@ struct key_user *key_user_lookup(uid_t uid) 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); @@ -136,6 +142,7 @@ 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); } @@ -234,7 +241,7 @@ 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); + user = key_user_lookup(uid, cred->user->user_ns); if (!user) goto no_memory_1; diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index b1ec3b4ee17d..7f09fb897d2b 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -726,7 +726,7 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) /* change the UID */ if (uid != (uid_t) -1 && uid != key->uid) { ret = -ENOMEM; - newowner = key_user_lookup(uid); + newowner = key_user_lookup(uid, current_user_ns()); if (!newowner) goto error_put; diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 2f5d89e92b85..276d27882ce8 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -17,6 +17,7 @@ #include <linux/fs.h> #include <linux/err.h> #include <linux/mutex.h> +#include <linux/user_namespace.h> #include <asm/uaccess.h> #include "internal.h" @@ -34,6 +35,7 @@ struct key_user root_key_user = { .nkeys = ATOMIC_INIT(2), .nikeys = ATOMIC_INIT(2), .uid = 0, + .user_ns = &init_user_ns, }; /*****************************************************************************/ diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 0e04f72ef2d4..22a31582bfaa 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -365,7 +365,7 @@ static struct key *construct_key_and_link(struct key_type *type, kenter(""); - user = key_user_lookup(current_fsuid()); + user = key_user_lookup(current_fsuid(), current_user_ns()); if (!user) return ERR_PTR(-ENOMEM); |