aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerge E. Hallyn <serue@us.ibm.com>2009-02-26 19:27:38 -0500
committerJames Morris <jmorris@namei.org>2009-02-26 20:35:06 -0500
commit1d1e97562e5e2ac60fb7b25437ba619f95f67fab (patch)
tree68a9c52ecbff0782dd9b9438685afc3b40b6f707
parentbe38e0fd5f90a91d09e0a85ffb294b70a7be6259 (diff)
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.c2
-rw-r--r--security/keys/internal.h4
-rw-r--r--security/keys/key.c11
-rw-r--r--security/keys/keyctl.c2
-rw-r--r--security/keys/process_keys.c2
-rw-r--r--security/keys/request_key.c2
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 @@
20 20
21struct user_namespace init_user_ns = { 21struct user_namespace init_user_ns = {
22 .kref = { 22 .kref = {
23 .refcount = ATOMIC_INIT(1), 23 .refcount = ATOMIC_INIT(2),
24 }, 24 },
25 .creator = &root_user, 25 .creator = &root_user,
26}; 26};
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 {
53 atomic_t nkeys; /* number of keys */ 53 atomic_t nkeys; /* number of keys */
54 atomic_t nikeys; /* number of instantiated keys */ 54 atomic_t nikeys; /* number of instantiated keys */
55 uid_t uid; 55 uid_t uid;
56 struct user_namespace *user_ns;
56 int qnkeys; /* number of keys allocated to this user */ 57 int qnkeys; /* number of keys allocated to this user */
57 int qnbytes; /* number of bytes allocated to this user */ 58 int qnbytes; /* number of bytes allocated to this user */
58}; 59};
@@ -61,7 +62,8 @@ extern struct rb_root key_user_tree;
61extern spinlock_t key_user_lock; 62extern spinlock_t key_user_lock;
62extern struct key_user root_key_user; 63extern struct key_user root_key_user;
63 64
64extern struct key_user *key_user_lookup(uid_t uid); 65extern struct key_user *key_user_lookup(uid_t uid,
66 struct user_namespace *user_ns);
65extern void key_user_put(struct key_user *user); 67extern void key_user_put(struct key_user *user);
66 68
67/* 69/*
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 @@
18#include <linux/workqueue.h> 18#include <linux/workqueue.h>
19#include <linux/random.h> 19#include <linux/random.h>
20#include <linux/err.h> 20#include <linux/err.h>
21#include <linux/user_namespace.h>
21#include "internal.h" 22#include "internal.h"
22 23
23static struct kmem_cache *key_jar; 24static struct kmem_cache *key_jar;
@@ -60,7 +61,7 @@ void __key_check(const struct key *key)
60 * get the key quota record for a user, allocating a new record if one doesn't 61 * get the key quota record for a user, allocating a new record if one doesn't
61 * already exist 62 * already exist
62 */ 63 */
63struct key_user *key_user_lookup(uid_t uid) 64struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns)
64{ 65{
65 struct key_user *candidate = NULL, *user; 66 struct key_user *candidate = NULL, *user;
66 struct rb_node *parent = NULL; 67 struct rb_node *parent = NULL;
@@ -79,6 +80,10 @@ struct key_user *key_user_lookup(uid_t uid)
79 p = &(*p)->rb_left; 80 p = &(*p)->rb_left;
80 else if (uid > user->uid) 81 else if (uid > user->uid)
81 p = &(*p)->rb_right; 82 p = &(*p)->rb_right;
83 else if (user_ns < user->user_ns)
84 p = &(*p)->rb_left;
85 else if (user_ns > user->user_ns)
86 p = &(*p)->rb_right;
82 else 87 else
83 goto found; 88 goto found;
84 } 89 }
@@ -106,6 +111,7 @@ struct key_user *key_user_lookup(uid_t uid)
106 atomic_set(&candidate->nkeys, 0); 111 atomic_set(&candidate->nkeys, 0);
107 atomic_set(&candidate->nikeys, 0); 112 atomic_set(&candidate->nikeys, 0);
108 candidate->uid = uid; 113 candidate->uid = uid;
114 candidate->user_ns = get_user_ns(user_ns);
109 candidate->qnkeys = 0; 115 candidate->qnkeys = 0;
110 candidate->qnbytes = 0; 116 candidate->qnbytes = 0;
111 spin_lock_init(&candidate->lock); 117 spin_lock_init(&candidate->lock);
@@ -136,6 +142,7 @@ void key_user_put(struct key_user *user)
136 if (atomic_dec_and_lock(&user->usage, &key_user_lock)) { 142 if (atomic_dec_and_lock(&user->usage, &key_user_lock)) {
137 rb_erase(&user->node, &key_user_tree); 143 rb_erase(&user->node, &key_user_tree);
138 spin_unlock(&key_user_lock); 144 spin_unlock(&key_user_lock);
145 put_user_ns(user->user_ns);
139 146
140 kfree(user); 147 kfree(user);
141 } 148 }
@@ -234,7 +241,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
234 quotalen = desclen + type->def_datalen; 241 quotalen = desclen + type->def_datalen;
235 242
236 /* get hold of the key tracking for this user */ 243 /* get hold of the key tracking for this user */
237 user = key_user_lookup(uid); 244 user = key_user_lookup(uid, cred->user->user_ns);
238 if (!user) 245 if (!user)
239 goto no_memory_1; 246 goto no_memory_1;
240 247
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)
726 /* change the UID */ 726 /* change the UID */
727 if (uid != (uid_t) -1 && uid != key->uid) { 727 if (uid != (uid_t) -1 && uid != key->uid) {
728 ret = -ENOMEM; 728 ret = -ENOMEM;
729 newowner = key_user_lookup(uid); 729 newowner = key_user_lookup(uid, current_user_ns());
730 if (!newowner) 730 if (!newowner)
731 goto error_put; 731 goto error_put;
732 732
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 @@
17#include <linux/fs.h> 17#include <linux/fs.h>
18#include <linux/err.h> 18#include <linux/err.h>
19#include <linux/mutex.h> 19#include <linux/mutex.h>
20#include <linux/user_namespace.h>
20#include <asm/uaccess.h> 21#include <asm/uaccess.h>
21#include "internal.h" 22#include "internal.h"
22 23
@@ -34,6 +35,7 @@ struct key_user root_key_user = {
34 .nkeys = ATOMIC_INIT(2), 35 .nkeys = ATOMIC_INIT(2),
35 .nikeys = ATOMIC_INIT(2), 36 .nikeys = ATOMIC_INIT(2),
36 .uid = 0, 37 .uid = 0,
38 .user_ns = &init_user_ns,
37}; 39};
38 40
39/*****************************************************************************/ 41/*****************************************************************************/
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,
365 365
366 kenter(""); 366 kenter("");
367 367
368 user = key_user_lookup(current_fsuid()); 368 user = key_user_lookup(current_fsuid(), current_user_ns());
369 if (!user) 369 if (!user)
370 return ERR_PTR(-ENOMEM); 370 return ERR_PTR(-ENOMEM);
371 371