diff options
Diffstat (limited to 'security/keys')
| -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/keyring.c | 3 | ||||
| -rw-r--r-- | security/keys/permission.c | 5 | ||||
| -rw-r--r-- | security/keys/proc.c | 55 | ||||
| -rw-r--r-- | security/keys/process_keys.c | 2 | ||||
| -rw-r--r-- | security/keys/request_key.c | 2 |
8 files changed, 73 insertions, 11 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/keyring.c b/security/keys/keyring.c index ed851574d073..3dba81c2eba3 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
| @@ -539,6 +539,9 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) | |||
| 539 | &keyring_name_hash[bucket], | 539 | &keyring_name_hash[bucket], |
| 540 | type_data.link | 540 | type_data.link |
| 541 | ) { | 541 | ) { |
| 542 | if (keyring->user->user_ns != current_user_ns()) | ||
| 543 | continue; | ||
| 544 | |||
| 542 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) | 545 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
| 543 | continue; | 546 | continue; |
| 544 | 547 | ||
diff --git a/security/keys/permission.c b/security/keys/permission.c index 5d9fc7b93f2e..0ed802c9e698 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c | |||
| @@ -35,6 +35,9 @@ int key_task_permission(const key_ref_t key_ref, const struct cred *cred, | |||
| 35 | 35 | ||
| 36 | key = key_ref_to_ptr(key_ref); | 36 | key = key_ref_to_ptr(key_ref); |
| 37 | 37 | ||
| 38 | if (key->user->user_ns != cred->user->user_ns) | ||
| 39 | goto use_other_perms; | ||
| 40 | |||
| 38 | /* use the second 8-bits of permissions for keys the caller owns */ | 41 | /* use the second 8-bits of permissions for keys the caller owns */ |
| 39 | if (key->uid == cred->fsuid) { | 42 | if (key->uid == cred->fsuid) { |
| 40 | kperm = key->perm >> 16; | 43 | kperm = key->perm >> 16; |
| @@ -56,6 +59,8 @@ int key_task_permission(const key_ref_t key_ref, const struct cred *cred, | |||
| 56 | } | 59 | } |
| 57 | } | 60 | } |
| 58 | 61 | ||
| 62 | use_other_perms: | ||
| 63 | |||
| 59 | /* otherwise use the least-significant 8-bits */ | 64 | /* otherwise use the least-significant 8-bits */ |
| 60 | kperm = key->perm; | 65 | kperm = key->perm; |
| 61 | 66 | ||
diff --git a/security/keys/proc.c b/security/keys/proc.c index 7f508def50e3..769f9bdfd2b3 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c | |||
| @@ -91,6 +91,28 @@ __initcall(key_proc_init); | |||
| 91 | */ | 91 | */ |
| 92 | #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS | 92 | #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS |
| 93 | 93 | ||
| 94 | static struct rb_node *__key_serial_next(struct rb_node *n) | ||
| 95 | { | ||
| 96 | while (n) { | ||
| 97 | struct key *key = rb_entry(n, struct key, serial_node); | ||
| 98 | if (key->user->user_ns == current_user_ns()) | ||
| 99 | break; | ||
| 100 | n = rb_next(n); | ||
| 101 | } | ||
| 102 | return n; | ||
| 103 | } | ||
| 104 | |||
| 105 | static struct rb_node *key_serial_next(struct rb_node *n) | ||
| 106 | { | ||
| 107 | return __key_serial_next(rb_next(n)); | ||
| 108 | } | ||
| 109 | |||
| 110 | static struct rb_node *key_serial_first(struct rb_root *r) | ||
| 111 | { | ||
| 112 | struct rb_node *n = rb_first(r); | ||
| 113 | return __key_serial_next(n); | ||
| 114 | } | ||
| 115 | |||
| 94 | static int proc_keys_open(struct inode *inode, struct file *file) | 116 | static int proc_keys_open(struct inode *inode, struct file *file) |
| 95 | { | 117 | { |
| 96 | return seq_open(file, &proc_keys_ops); | 118 | return seq_open(file, &proc_keys_ops); |
| @@ -104,10 +126,10 @@ static void *proc_keys_start(struct seq_file *p, loff_t *_pos) | |||
| 104 | 126 | ||
| 105 | spin_lock(&key_serial_lock); | 127 | spin_lock(&key_serial_lock); |
| 106 | 128 | ||
| 107 | _p = rb_first(&key_serial_tree); | 129 | _p = key_serial_first(&key_serial_tree); |
| 108 | while (pos > 0 && _p) { | 130 | while (pos > 0 && _p) { |
| 109 | pos--; | 131 | pos--; |
| 110 | _p = rb_next(_p); | 132 | _p = key_serial_next(_p); |
| 111 | } | 133 | } |
| 112 | 134 | ||
| 113 | return _p; | 135 | return _p; |
| @@ -117,7 +139,7 @@ static void *proc_keys_start(struct seq_file *p, loff_t *_pos) | |||
| 117 | static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) | 139 | static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) |
| 118 | { | 140 | { |
| 119 | (*_pos)++; | 141 | (*_pos)++; |
| 120 | return rb_next((struct rb_node *) v); | 142 | return key_serial_next((struct rb_node *) v); |
| 121 | 143 | ||
| 122 | } | 144 | } |
| 123 | 145 | ||
| @@ -203,6 +225,27 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
| 203 | 225 | ||
| 204 | #endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */ | 226 | #endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */ |
| 205 | 227 | ||
| 228 | static struct rb_node *__key_user_next(struct rb_node *n) | ||
| 229 | { | ||
| 230 | while (n) { | ||
| 231 | struct key_user *user = rb_entry(n, struct key_user, node); | ||
| 232 | if (user->user_ns == current_user_ns()) | ||
| 233 | break; | ||
| 234 | n = rb_next(n); | ||
| 235 | } | ||
| 236 | return n; | ||
| 237 | } | ||
| 238 | |||
| 239 | static struct rb_node *key_user_next(struct rb_node *n) | ||
| 240 | { | ||
| 241 | return __key_user_next(rb_next(n)); | ||
| 242 | } | ||
| 243 | |||
| 244 | static struct rb_node *key_user_first(struct rb_root *r) | ||
| 245 | { | ||
| 246 | struct rb_node *n = rb_first(r); | ||
| 247 | return __key_user_next(n); | ||
| 248 | } | ||
| 206 | /*****************************************************************************/ | 249 | /*****************************************************************************/ |
| 207 | /* | 250 | /* |
| 208 | * implement "/proc/key-users" to provides a list of the key users | 251 | * implement "/proc/key-users" to provides a list of the key users |
| @@ -220,10 +263,10 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) | |||
| 220 | 263 | ||
| 221 | spin_lock(&key_user_lock); | 264 | spin_lock(&key_user_lock); |
| 222 | 265 | ||
| 223 | _p = rb_first(&key_user_tree); | 266 | _p = key_user_first(&key_user_tree); |
| 224 | while (pos > 0 && _p) { | 267 | while (pos > 0 && _p) { |
| 225 | pos--; | 268 | pos--; |
| 226 | _p = rb_next(_p); | 269 | _p = key_user_next(_p); |
| 227 | } | 270 | } |
| 228 | 271 | ||
| 229 | return _p; | 272 | return _p; |
| @@ -233,7 +276,7 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) | |||
| 233 | static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) | 276 | static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) |
| 234 | { | 277 | { |
| 235 | (*_pos)++; | 278 | (*_pos)++; |
| 236 | return rb_next((struct rb_node *) v); | 279 | return key_user_next((struct rb_node *) v); |
| 237 | 280 | ||
| 238 | } | 281 | } |
| 239 | 282 | ||
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 | ||
