diff options
author | Serge E. Hallyn <serue@us.ibm.com> | 2009-02-26 19:27:38 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2009-02-26 20:35:06 -0500 |
commit | 1d1e97562e5e2ac60fb7b25437ba619f95f67fab (patch) | |
tree | 68a9c52ecbff0782dd9b9438685afc3b40b6f707 /security | |
parent | be38e0fd5f90a91d09e0a85ffb294b70a7be6259 (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>
Diffstat (limited to 'security')
-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 |
5 files changed, 16 insertions, 5 deletions
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; | |||
61 | extern spinlock_t key_user_lock; | 62 | extern spinlock_t key_user_lock; |
62 | extern struct key_user root_key_user; | 63 | extern struct key_user root_key_user; |
63 | 64 | ||
64 | extern struct key_user *key_user_lookup(uid_t uid); | 65 | extern struct key_user *key_user_lookup(uid_t uid, |
66 | struct user_namespace *user_ns); | ||
65 | extern void key_user_put(struct key_user *user); | 67 | extern 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 | ||
23 | static struct kmem_cache *key_jar; | 24 | static 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 | */ |
63 | struct key_user *key_user_lookup(uid_t uid) | 64 | struct 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 | ||