diff options
| author | Eric W. Biederman <ebiederm@xmission.com> | 2012-02-08 10:53:04 -0500 |
|---|---|---|
| committer | Eric W. Biederman <ebiederm@xmission.com> | 2012-09-13 21:28:02 -0400 |
| commit | 9a56c2db49e7349c7963f0ce66c1ef578d44ebd3 (patch) | |
| tree | de29b56483bb00efabca3ba35c7001cab2aab7be /security | |
| parent | 5fce5e0bbd44263c36f58ad1113b599d06ed1978 (diff) | |
userns: Convert security/keys to the new userns infrastructure
- Replace key_user ->user_ns equality checks with kuid_has_mapping checks.
- Use from_kuid to generate key descriptions
- Use kuid_t and kgid_t and the associated helpers instead of uid_t and gid_t
- Avoid potential problems with file descriptor passing by displaying
keys in the user namespace of the opener of key status proc files.
Cc: linux-security-module@vger.kernel.org
Cc: keyrings@linux-nfs.org
Cc: David Howells <dhowells@redhat.com>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Diffstat (limited to 'security')
| -rw-r--r-- | security/keys/internal.h | 6 | ||||
| -rw-r--r-- | security/keys/key.c | 23 | ||||
| -rw-r--r-- | security/keys/keyctl.c | 50 | ||||
| -rw-r--r-- | security/keys/keyring.c | 4 | ||||
| -rw-r--r-- | security/keys/permission.c | 14 | ||||
| -rw-r--r-- | security/keys/proc.c | 44 | ||||
| -rw-r--r-- | security/keys/process_keys.c | 15 | ||||
| -rw-r--r-- | security/keys/request_key.c | 6 |
8 files changed, 79 insertions, 83 deletions
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 { | |||
| 52 | atomic_t usage; /* for accessing qnkeys & qnbytes */ | 52 | atomic_t usage; /* for accessing qnkeys & qnbytes */ |
| 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 | kuid_t uid; |
| 56 | struct user_namespace *user_ns; | ||
| 57 | int qnkeys; /* number of keys allocated to this user */ | 56 | int qnkeys; /* number of keys allocated to this user */ |
| 58 | int qnbytes; /* number of bytes allocated to this user */ | 57 | int qnbytes; /* number of bytes allocated to this user */ |
| 59 | }; | 58 | }; |
| @@ -62,8 +61,7 @@ extern struct rb_root key_user_tree; | |||
| 62 | extern spinlock_t key_user_lock; | 61 | extern spinlock_t key_user_lock; |
| 63 | extern struct key_user root_key_user; | 62 | extern struct key_user root_key_user; |
| 64 | 63 | ||
| 65 | extern struct key_user *key_user_lookup(uid_t uid, | 64 | extern struct key_user *key_user_lookup(kuid_t uid); |
| 66 | struct user_namespace *user_ns); | ||
| 67 | extern void key_user_put(struct key_user *user); | 65 | extern void key_user_put(struct key_user *user); |
| 68 | 66 | ||
| 69 | /* | 67 | /* |
diff --git a/security/keys/key.c b/security/keys/key.c index 50d96d4e06f2..4289c5ba2710 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
| @@ -18,7 +18,6 @@ | |||
| 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> | ||
| 22 | #include "internal.h" | 21 | #include "internal.h" |
| 23 | 22 | ||
| 24 | struct kmem_cache *key_jar; | 23 | struct kmem_cache *key_jar; |
| @@ -52,7 +51,7 @@ void __key_check(const struct key *key) | |||
| 52 | * Get the key quota record for a user, allocating a new record if one doesn't | 51 | * Get the key quota record for a user, allocating a new record if one doesn't |
| 53 | * already exist. | 52 | * already exist. |
| 54 | */ | 53 | */ |
| 55 | struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns) | 54 | struct key_user *key_user_lookup(kuid_t uid) |
| 56 | { | 55 | { |
| 57 | struct key_user *candidate = NULL, *user; | 56 | struct key_user *candidate = NULL, *user; |
| 58 | struct rb_node *parent = NULL; | 57 | struct rb_node *parent = NULL; |
| @@ -67,13 +66,9 @@ try_again: | |||
| 67 | parent = *p; | 66 | parent = *p; |
| 68 | user = rb_entry(parent, struct key_user, node); | 67 | user = rb_entry(parent, struct key_user, node); |
| 69 | 68 | ||
| 70 | if (uid < user->uid) | 69 | if (uid_lt(uid, user->uid)) |
| 71 | p = &(*p)->rb_left; | 70 | p = &(*p)->rb_left; |
| 72 | else if (uid > user->uid) | 71 | else if (uid_gt(uid, user->uid)) |
| 73 | p = &(*p)->rb_right; | ||
| 74 | else if (user_ns < user->user_ns) | ||
| 75 | p = &(*p)->rb_left; | ||
| 76 | else if (user_ns > user->user_ns) | ||
| 77 | p = &(*p)->rb_right; | 72 | p = &(*p)->rb_right; |
| 78 | else | 73 | else |
| 79 | goto found; | 74 | goto found; |
| @@ -102,7 +97,6 @@ try_again: | |||
| 102 | atomic_set(&candidate->nkeys, 0); | 97 | atomic_set(&candidate->nkeys, 0); |
| 103 | atomic_set(&candidate->nikeys, 0); | 98 | atomic_set(&candidate->nikeys, 0); |
| 104 | candidate->uid = uid; | 99 | candidate->uid = uid; |
| 105 | candidate->user_ns = get_user_ns(user_ns); | ||
| 106 | candidate->qnkeys = 0; | 100 | candidate->qnkeys = 0; |
| 107 | candidate->qnbytes = 0; | 101 | candidate->qnbytes = 0; |
| 108 | spin_lock_init(&candidate->lock); | 102 | spin_lock_init(&candidate->lock); |
| @@ -131,7 +125,6 @@ void key_user_put(struct key_user *user) | |||
| 131 | if (atomic_dec_and_lock(&user->usage, &key_user_lock)) { | 125 | if (atomic_dec_and_lock(&user->usage, &key_user_lock)) { |
| 132 | rb_erase(&user->node, &key_user_tree); | 126 | rb_erase(&user->node, &key_user_tree); |
| 133 | spin_unlock(&key_user_lock); | 127 | spin_unlock(&key_user_lock); |
| 134 | put_user_ns(user->user_ns); | ||
| 135 | 128 | ||
| 136 | kfree(user); | 129 | kfree(user); |
| 137 | } | 130 | } |
| @@ -229,7 +222,7 @@ serial_exists: | |||
| 229 | * key_alloc() calls don't race with module unloading. | 222 | * key_alloc() calls don't race with module unloading. |
| 230 | */ | 223 | */ |
| 231 | struct key *key_alloc(struct key_type *type, const char *desc, | 224 | struct key *key_alloc(struct key_type *type, const char *desc, |
| 232 | uid_t uid, gid_t gid, const struct cred *cred, | 225 | kuid_t uid, kgid_t gid, const struct cred *cred, |
| 233 | key_perm_t perm, unsigned long flags) | 226 | key_perm_t perm, unsigned long flags) |
| 234 | { | 227 | { |
| 235 | struct key_user *user = NULL; | 228 | struct key_user *user = NULL; |
| @@ -253,16 +246,16 @@ struct key *key_alloc(struct key_type *type, const char *desc, | |||
| 253 | quotalen = desclen + type->def_datalen; | 246 | quotalen = desclen + type->def_datalen; |
| 254 | 247 | ||
| 255 | /* get hold of the key tracking for this user */ | 248 | /* get hold of the key tracking for this user */ |
| 256 | user = key_user_lookup(uid, cred->user_ns); | 249 | user = key_user_lookup(uid); |
| 257 | if (!user) | 250 | if (!user) |
| 258 | goto no_memory_1; | 251 | goto no_memory_1; |
| 259 | 252 | ||
| 260 | /* check that the user's quota permits allocation of another key and | 253 | /* check that the user's quota permits allocation of another key and |
| 261 | * its description */ | 254 | * its description */ |
| 262 | if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { | 255 | if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { |
| 263 | unsigned maxkeys = (uid == 0) ? | 256 | unsigned maxkeys = uid_eq(uid, GLOBAL_ROOT_UID) ? |
| 264 | key_quota_root_maxkeys : key_quota_maxkeys; | 257 | key_quota_root_maxkeys : key_quota_maxkeys; |
| 265 | unsigned maxbytes = (uid == 0) ? | 258 | unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ? |
| 266 | key_quota_root_maxbytes : key_quota_maxbytes; | 259 | key_quota_root_maxbytes : key_quota_maxbytes; |
| 267 | 260 | ||
| 268 | spin_lock(&user->lock); | 261 | spin_lock(&user->lock); |
| @@ -380,7 +373,7 @@ int key_payload_reserve(struct key *key, size_t datalen) | |||
| 380 | 373 | ||
| 381 | /* contemplate the quota adjustment */ | 374 | /* contemplate the quota adjustment */ |
| 382 | if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | 375 | if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { |
| 383 | unsigned maxbytes = (key->user->uid == 0) ? | 376 | unsigned maxbytes = uid_eq(key->user->uid, GLOBAL_ROOT_UID) ? |
| 384 | key_quota_root_maxbytes : key_quota_maxbytes; | 377 | key_quota_root_maxbytes : key_quota_maxbytes; |
| 385 | 378 | ||
| 386 | spin_lock(&key->user->lock); | 379 | spin_lock(&key->user->lock); |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 3364fbf46807..1ecc0f79906e 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
| @@ -569,8 +569,8 @@ okay: | |||
| 569 | ret = snprintf(tmpbuf, PAGE_SIZE - 1, | 569 | ret = snprintf(tmpbuf, PAGE_SIZE - 1, |
| 570 | "%s;%d;%d;%08x;%s", | 570 | "%s;%d;%d;%08x;%s", |
| 571 | key->type->name, | 571 | key->type->name, |
| 572 | key->uid, | 572 | from_kuid_munged(current_user_ns(), key->uid), |
| 573 | key->gid, | 573 | from_kgid_munged(current_user_ns(), key->gid), |
| 574 | key->perm, | 574 | key->perm, |
| 575 | key->description ?: ""); | 575 | key->description ?: ""); |
| 576 | 576 | ||
| @@ -766,15 +766,25 @@ error: | |||
| 766 | * | 766 | * |
| 767 | * If successful, 0 will be returned. | 767 | * If successful, 0 will be returned. |
| 768 | */ | 768 | */ |
| 769 | long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | 769 | long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group) |
| 770 | { | 770 | { |
| 771 | struct key_user *newowner, *zapowner = NULL; | 771 | struct key_user *newowner, *zapowner = NULL; |
| 772 | struct key *key; | 772 | struct key *key; |
| 773 | key_ref_t key_ref; | 773 | key_ref_t key_ref; |
| 774 | long ret; | 774 | long ret; |
| 775 | kuid_t uid; | ||
| 776 | kgid_t gid; | ||
| 777 | |||
| 778 | uid = make_kuid(current_user_ns(), user); | ||
| 779 | gid = make_kgid(current_user_ns(), group); | ||
| 780 | ret = -EINVAL; | ||
| 781 | if ((user != (uid_t) -1) && !uid_valid(uid)) | ||
| 782 | goto error; | ||
| 783 | if ((group != (gid_t) -1) && !gid_valid(gid)) | ||
| 784 | goto error; | ||
| 775 | 785 | ||
| 776 | ret = 0; | 786 | ret = 0; |
