diff options
Diffstat (limited to 'security/keys')
-rw-r--r-- | security/keys/internal.h | 35 | ||||
-rw-r--r-- | security/keys/key.c | 34 | ||||
-rw-r--r-- | security/keys/process_keys.c | 16 | ||||
-rw-r--r-- | security/keys/request_key.c | 556 | ||||
-rw-r--r-- | security/keys/request_key_auth.c | 11 |
5 files changed, 335 insertions, 317 deletions
diff --git a/security/keys/internal.h b/security/keys/internal.h index 1bb416f4bbce..d36d69393356 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* internal.h: authentication token and access key management internal defs | 1 | /* internal.h: authentication token and access key management internal defs |
2 | * | 2 | * |
3 | * Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2003-5, 2007 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -12,17 +12,28 @@ | |||
12 | #ifndef _INTERNAL_H | 12 | #ifndef _INTERNAL_H |
13 | #define _INTERNAL_H | 13 | #define _INTERNAL_H |
14 | 14 | ||
15 | #include <linux/key.h> | 15 | #include <linux/key-type.h> |
16 | #include <linux/key-ui.h> | 16 | #include <linux/key-ui.h> |
17 | 17 | ||
18 | #if 0 | 18 | static inline __attribute__((format(printf, 1, 2))) |
19 | #define kenter(FMT, a...) printk("==> %s("FMT")\n",__FUNCTION__ , ## a) | 19 | void no_printk(const char *fmt, ...) |
20 | #define kleave(FMT, a...) printk("<== %s()"FMT"\n",__FUNCTION__ , ## a) | 20 | { |
21 | #define kdebug(FMT, a...) printk(FMT"\n" , ## a) | 21 | } |
22 | |||
23 | #ifdef __KDEBUG | ||
24 | #define kenter(FMT, ...) \ | ||
25 | printk(KERN_DEBUG "==> %s("FMT")\n", __FUNCTION__, ##__VA_ARGS__) | ||
26 | #define kleave(FMT, ...) \ | ||
27 | printk(KERN_DEBUG "<== %s()"FMT"\n", __FUNCTION__, ##__VA_ARGS__) | ||
28 | #define kdebug(FMT, ...) \ | ||
29 | printk(KERN_DEBUG "xxx" FMT"yyy\n", ##__VA_ARGS__) | ||
22 | #else | 30 | #else |
23 | #define kenter(FMT, a...) do {} while(0) | 31 | #define kenter(FMT, ...) \ |
24 | #define kleave(FMT, a...) do {} while(0) | 32 | no_printk(KERN_DEBUG "==> %s("FMT")\n", __FUNCTION__, ##__VA_ARGS__) |
25 | #define kdebug(FMT, a...) do {} while(0) | 33 | #define kleave(FMT, ...) \ |
34 | no_printk(KERN_DEBUG "<== %s()"FMT"\n", __FUNCTION__, ##__VA_ARGS__) | ||
35 | #define kdebug(FMT, ...) \ | ||
36 | no_printk(KERN_DEBUG FMT"\n", ##__VA_ARGS__) | ||
26 | #endif | 37 | #endif |
27 | 38 | ||
28 | extern struct key_type key_type_user; | 39 | extern struct key_type key_type_user; |
@@ -36,7 +47,7 @@ extern struct key_type key_type_user; | |||
36 | */ | 47 | */ |
37 | struct key_user { | 48 | struct key_user { |
38 | struct rb_node node; | 49 | struct rb_node node; |
39 | struct list_head consq; /* construction queue */ | 50 | struct mutex cons_lock; /* construction initiation lock */ |
40 | spinlock_t lock; | 51 | spinlock_t lock; |
41 | atomic_t usage; /* for accessing qnkeys & qnbytes */ | 52 | atomic_t usage; /* for accessing qnkeys & qnbytes */ |
42 | atomic_t nkeys; /* number of keys */ | 53 | atomic_t nkeys; /* number of keys */ |
@@ -62,7 +73,7 @@ extern void key_user_put(struct key_user *user); | |||
62 | extern struct rb_root key_serial_tree; | 73 | extern struct rb_root key_serial_tree; |
63 | extern spinlock_t key_serial_lock; | 74 | extern spinlock_t key_serial_lock; |
64 | extern struct semaphore key_alloc_sem; | 75 | extern struct semaphore key_alloc_sem; |
65 | extern struct rw_semaphore key_construction_sem; | 76 | extern struct mutex key_construction_mutex; |
66 | extern wait_queue_head_t request_key_conswq; | 77 | extern wait_queue_head_t request_key_conswq; |
67 | 78 | ||
68 | 79 | ||
@@ -109,7 +120,7 @@ extern struct key *request_key_and_link(struct key_type *type, | |||
109 | struct request_key_auth { | 120 | struct request_key_auth { |
110 | struct key *target_key; | 121 | struct key *target_key; |
111 | struct task_struct *context; | 122 | struct task_struct *context; |
112 | const char *callout_info; | 123 | char *callout_info; |
113 | pid_t pid; | 124 | pid_t pid; |
114 | }; | 125 | }; |
115 | 126 | ||
diff --git a/security/keys/key.c b/security/keys/key.c index 01bbc6d9d19b..fdd5ca6d89fc 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* key.c: basic authentication token and access key management | 1 | /* Basic authentication token and access key management |
2 | * | 2 | * |
3 | * Copyright (C) 2004-6 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -34,7 +34,7 @@ static void key_cleanup(struct work_struct *work); | |||
34 | static DECLARE_WORK(key_cleanup_task, key_cleanup); | 34 | static DECLARE_WORK(key_cleanup_task, key_cleanup); |
35 | 35 | ||
36 | /* we serialise key instantiation and link */ | 36 | /* we serialise key instantiation and link */ |
37 | DECLARE_RWSEM(key_construction_sem); | 37 | DEFINE_MUTEX(key_construction_mutex); |
38 | 38 | ||
39 | /* any key who's type gets unegistered will be re-typed to this */ | 39 | /* any key who's type gets unegistered will be re-typed to this */ |
40 | static struct key_type key_type_dead = { | 40 | static struct key_type key_type_dead = { |
@@ -104,7 +104,7 @@ struct key_user *key_user_lookup(uid_t uid) | |||
104 | candidate->qnkeys = 0; | 104 | candidate->qnkeys = 0; |
105 | candidate->qnbytes = 0; | 105 | candidate->qnbytes = 0; |
106 | spin_lock_init(&candidate->lock); | 106 | spin_lock_init(&candidate->lock); |
107 | INIT_LIST_HEAD(&candidate->consq); | 107 | mutex_init(&candidate->cons_lock); |
108 | 108 | ||
109 | rb_link_node(&candidate->node, parent, p); | 109 | rb_link_node(&candidate->node, parent, p); |
110 | rb_insert_color(&candidate->node, &key_user_tree); | 110 | rb_insert_color(&candidate->node, &key_user_tree); |
@@ -418,7 +418,7 @@ static int __key_instantiate_and_link(struct key *key, | |||
418 | awaken = 0; | 418 | awaken = 0; |
419 | ret = -EBUSY; | 419 | ret = -EBUSY; |
420 | 420 | ||
421 | down_write(&key_construction_sem); | 421 | mutex_lock(&key_construction_mutex); |
422 | 422 | ||
423 | /* can't instantiate twice */ | 423 | /* can't instantiate twice */ |
424 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { | 424 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { |
@@ -443,11 +443,11 @@ static int __key_instantiate_and_link(struct key *key, | |||
443 | } | 443 | } |
444 | } | 444 | } |
445 | 445 | ||
446 | up_write(&key_construction_sem); | 446 | mutex_unlock(&key_construction_mutex); |
447 | 447 | ||
448 | /* wake up anyone waiting for a key to be constructed */ | 448 | /* wake up anyone waiting for a key to be constructed */ |
449 | if (awaken) | 449 | if (awaken) |
450 | wake_up_all(&request_key_conswq); | 450 | wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT); |
451 | 451 | ||
452 | return ret; | 452 | return ret; |
453 | 453 | ||
@@ -500,7 +500,7 @@ int key_negate_and_link(struct key *key, | |||
500 | if (keyring) | 500 | if (keyring) |
501 | down_write(&keyring->sem); | 501 | down_write(&keyring->sem); |
502 | 502 | ||
503 | down_write(&key_construction_sem); | 503 | mutex_lock(&key_construction_mutex); |
504 | 504 | ||
505 | /* can't instantiate twice */ | 505 | /* can't instantiate twice */ |
506 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { | 506 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { |
@@ -525,14 +525,14 @@ int key_negate_and_link(struct key *key, | |||
525 | key_revoke(instkey); | 525 | key_revoke(instkey); |
526 | } | 526 | } |
527 | 527 | ||
528 | up_write(&key_construction_sem); | 528 | mutex_unlock(&key_construction_mutex); |
529 | 529 | ||
530 | if (keyring) | 530 | if (keyring) |
531 | up_write(&keyring->sem); | 531 | up_write(&keyring->sem); |
532 | 532 | ||
533 | /* wake up anyone waiting for a key to be constructed */ | 533 | /* wake up anyone waiting for a key to be constructed */ |
534 | if (awaken) | 534 | if (awaken) |
535 | wake_up_all(&request_key_conswq); | 535 | wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT); |
536 | 536 | ||
537 | return ret; | 537 | return ret; |
538 | 538 | ||
@@ -899,12 +899,14 @@ void key_revoke(struct key *key) | |||
899 | { | 899 | { |
900 | key_check(key); | 900 | key_check(key); |
901 | 901 | ||
902 | /* make sure no one's trying to change or use the key when we mark | 902 | /* make sure no one's trying to change or use the key when we mark it |
903 | * it */ | 903 | * - we tell lockdep that we might nest because we might be revoking an |
904 | down_write(&key->sem); | 904 | * authorisation key whilst holding the sem on a key we've just |
905 | set_bit(KEY_FLAG_REVOKED, &key->flags); | 905 | * instantiated |
906 | 906 | */ | |
907 | if (key->type->revoke) | 907 | down_write_nested(&key->sem, 1); |
908 | if (!test_and_set_bit(KEY_FLAG_REVOKED, &key->flags) && | ||
909 | key->type->revoke) | ||
908 | key->type->revoke(key); | 910 | key->type->revoke(key); |
909 | 911 | ||
910 | up_write(&key->sem); | 912 | up_write(&key->sem); |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index b6f86808475a..2a0eb946fc7e 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -26,7 +26,7 @@ static DEFINE_MUTEX(key_session_mutex); | |||
26 | /* the root user's tracking struct */ | 26 | /* the root user's tracking struct */ |
27 | struct key_user root_key_user = { | 27 | struct key_user root_key_user = { |
28 | .usage = ATOMIC_INIT(3), | 28 | .usage = ATOMIC_INIT(3), |
29 | .consq = LIST_HEAD_INIT(root_key_user.consq), | 29 | .cons_lock = __MUTEX_INITIALIZER(root_key_user.cons_lock), |
30 | .lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock), | 30 | .lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock), |
31 | .nkeys = ATOMIC_INIT(2), | 31 | .nkeys = ATOMIC_INIT(2), |
32 | .nikeys = ATOMIC_INIT(2), | 32 | .nikeys = ATOMIC_INIT(2), |
@@ -679,8 +679,18 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id, | |||
679 | break; | 679 | break; |
680 | } | 680 | } |
681 | 681 | ||
682 | /* check the status */ | 682 | if (!partial) { |
683 | if (perm) { | 683 | ret = wait_for_key_construction(key, true); |
684 | switch (ret) { | ||
685 | case -ERESTARTSYS: | ||
686 | goto invalid_key; | ||
687 | default: | ||
688 | if (perm) | ||
689 | goto invalid_key; | ||
690 | case 0: | ||
691 | break; | ||
692 | } | ||
693 | } else if (perm) { | ||
684 | ret = key_validate(key); | 694 | ret = key_validate(key); |
685 | if (ret < 0) | 695 | if (ret < 0) |
686 | goto invalid_key; | 696 | goto invalid_key; |
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 557500110a13..6381e616c477 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* request_key.c: request a key from userspace | 1 | /* Request a key from userspace |
2 | * | 2 | * |
3 | * Copyright (C) 2004-6 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -18,27 +18,54 @@ | |||
18 | #include <linux/keyctl.h> | 18 | #include <linux/keyctl.h> |
19 | #include "internal.h" | 19 | #include "internal.h" |
20 | 20 | ||
21 | struct key_construction { | 21 | /* |
22 | struct list_head link; /* link in construction queue */ | 22 | * wait_on_bit() sleep function for uninterruptible waiting |
23 | struct key *key; /* key being constructed */ | 23 | */ |
24 | }; | 24 | static int key_wait_bit(void *flags) |
25 | { | ||
26 | schedule(); | ||
27 | return 0; | ||
28 | } | ||
29 | |||
30 | /* | ||
31 | * wait_on_bit() sleep function for interruptible waiting | ||
32 | */ | ||
33 | static int key_wait_bit_intr(void *flags) | ||
34 | { | ||
35 | schedule(); | ||
36 | return signal_pending(current) ? -ERESTARTSYS : 0; | ||
37 | } | ||
38 | |||
39 | /* | ||
40 | * call to complete the construction of a key | ||
41 | */ | ||
42 | void complete_request_key(struct key_construction *cons, int error) | ||
43 | { | ||
44 | kenter("{%d,%d},%d", cons->key->serial, cons->authkey->serial, error); | ||
25 | 45 | ||
26 | /* when waiting for someone else's keys, you get added to this */ | 46 | if (error < 0) |
27 | DECLARE_WAIT_QUEUE_HEAD(request_key_conswq); | 47 | key_negate_and_link(cons->key, key_negative_timeout, NULL, |
48 | cons->authkey); | ||
49 | else | ||
50 | key_revoke(cons->authkey); | ||
51 | |||
52 | key_put(cons->key); | ||
53 | key_put(cons->authkey); | ||
54 | kfree(cons); | ||
55 | } | ||
56 | EXPORT_SYMBOL(complete_request_key); | ||
28 | 57 | ||
29 | /*****************************************************************************/ | ||
30 | /* | 58 | /* |
31 | * request userspace finish the construction of a key | 59 | * request userspace finish the construction of a key |
32 | * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>" | 60 | * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>" |
33 | */ | 61 | */ |
34 | static int call_sbin_request_key(struct key *key, | 62 | static int call_sbin_request_key(struct key_construction *cons, |
35 | struct key *authkey, | ||
36 | const char *op, | 63 | const char *op, |
37 | void *aux) | 64 | void *aux) |
38 | { | 65 | { |
39 | struct task_struct *tsk = current; | 66 | struct task_struct *tsk = current; |
40 | key_serial_t prkey, sskey; | 67 | key_serial_t prkey, sskey; |
41 | struct key *keyring; | 68 | struct key *key = cons->key, *authkey = cons->authkey, *keyring; |
42 | char *argv[9], *envp[3], uid_str[12], gid_str[12]; | 69 | char *argv[9], *envp[3], uid_str[12], gid_str[12]; |
43 | char key_str[12], keyring_str[3][12]; | 70 | char key_str[12], keyring_str[3][12]; |
44 | char desc[20]; | 71 | char desc[20]; |
@@ -82,8 +109,7 @@ static int call_sbin_request_key(struct key *key, | |||
82 | rcu_read_lock(); | 109 | rcu_read_lock(); |
83 | sskey = rcu_dereference(tsk->signal->session_keyring)->serial; | 110 | sskey = rcu_dereference(tsk->signal->session_keyring)->serial; |
84 | rcu_read_unlock(); | 111 | rcu_read_unlock(); |
85 | } | 112 | } else { |
86 | else { | ||
87 | sskey = tsk->user->session_keyring->serial; | 113 | sskey = tsk->user->session_keyring->serial; |
88 | } | 114 | } |
89 | 115 | ||
@@ -110,228 +136,77 @@ static int call_sbin_request_key(struct key *key, | |||
110 | /* do it */ | 136 | /* do it */ |
111 | ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, | 137 | ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, |
112 | UMH_WAIT_PROC); | 138 | UMH_WAIT_PROC); |
139 | kdebug("usermode -> 0x%x", ret); | ||
140 | if (ret >= 0) { | ||
141 | /* ret is the exit/wait code */ | ||
142 | if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags) || | ||
143 | key_validate(key) < 0) | ||
144 | ret = -ENOKEY; | ||
145 | else | ||
146 | /* ignore any errors from userspace if the key was | ||
147 | * instantiated */ | ||
148 | ret = 0; | ||
149 | } | ||
113 | 150 | ||
114 | error_link: | 151 | error_link: |
115 | key_put(keyring); | 152 | key_put(keyring); |
116 | 153 | ||
117 | error_alloc: | 154 | error_alloc: |
118 | kleave(" = %d", ret); | 155 | kleave(" = %d", ret); |
156 | complete_request_key(cons, ret); | ||
119 | return ret; | 157 | return ret; |
158 | } | ||
120 | 159 | ||
121 | } /* end call_sbin_request_key() */ | ||
122 | |||
123 | /*****************************************************************************/ | ||
124 | /* | 160 | /* |
125 | * call out to userspace for the key | 161 | * call out to userspace for key construction |
126 | * - called with the construction sem held, but the sem is dropped here | ||
127 | * - we ignore program failure and go on key status instead | 162 | * - we ignore program failure and go on key status instead |
128 | */ | 163 | */ |
129 | static struct key *__request_key_construction(struct key_type *type, | 164 | static int construct_key(struct key *key, const char *callout_info, void *aux) |
130 | const char *description, | ||
131 | const char *callout_info, | ||
132 | void *aux, | ||
133 | unsigned long flags) | ||
134 | { | 165 | { |
166 | struct key_construction *cons; | ||
135 | request_key_actor_t actor; | 167 | request_key_actor_t actor; |
136 | struct key_construction cons; | 168 | struct key *authkey; |
137 | struct timespec now; | 169 | int ret; |
138 | struct key *key, *authkey; | ||
139 | int ret, negated; | ||
140 | 170 | ||
141 | kenter("%s,%s,%s,%lx", type->name, description, callout_info, flags); | 171 | kenter("%d,%s,%p", key->serial, callout_info, aux); |
142 | 172 | ||
143 | /* create a key and add it to the queue */ | 173 | cons = kmalloc(sizeof(*cons), GFP_KERNEL); |
144 | key = key_alloc(type, description, | 174 | if (!cons) |
145 | current->fsuid, current->fsgid, current, KEY_POS_ALL, | 175 | return -ENOMEM; |
146 | flags); | ||
147 | if (IS_ERR(key)) | ||
148 | goto alloc_failed; | ||
149 | |||
150 | set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); | ||
151 | |||
152 | cons.key = key; | ||
153 | list_add_tail(&cons.link, &key->user->consq); | ||
154 | |||
155 | /* we drop the construction sem here on behalf of the caller */ | ||
156 | up_write(&key_construction_sem); | ||
157 | 176 | ||
158 | /* allocate an authorisation key */ | 177 | /* allocate an authorisation key */ |
159 | authkey = request_key_auth_new(key, callout_info); | 178 | authkey = request_key_auth_new(key, callout_info); |
160 | if (IS_ERR(authkey)) { | 179 | if (IS_ERR(authkey)) { |
180 | kfree(cons); | ||
161 | ret = PTR_ERR(authkey); | 181 | ret = PTR_ERR(authkey); |
162 | authkey = NULL; | 182 | authkey = NULL; |
163 | goto alloc_authkey_failed; | 183 | } else { |
164 | } | 184 | cons->authkey = key_get(authkey); |
165 | 185 | cons->key = key_get(key); | |
166 | /* make the call */ | 186 | |
167 | actor = call_sbin_request_key; | 187 | /* make the call */ |
168 | if (type->request_key) | 188 | actor = call_sbin_request_key; |
169 | actor = type->request_key; | 189 | if (key->type->request_key) |
170 | ret = actor(key, authkey, "create", aux); | 190 | actor = key->type->request_key; |
171 | if (ret < 0) | 191 | |
172 | goto request_failed; | 192 | ret = actor(cons, "create", aux); |
173 | 193 | ||
174 | /* if the key wasn't instantiated, then we want to give an error */ | 194 | /* check that the actor called complete_request_key() prior to |
175 | ret = -ENOKEY; | 195 | * returning an error */ |
176 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | 196 | WARN_ON(ret < 0 && |
177 | goto request_failed; | 197 | !test_bit(KEY_FLAG_REVOKED, &authkey->flags)); |
178 | 198 | key_put(authkey); | |
179 | key_revoke(authkey); | ||
180 | key_put(authkey); | ||
181 | |||
182 | down_write(&key_construction_sem); | ||
183 | list_del(&cons.link); | ||
184 | up_write(&key_construction_sem); | ||
185 | |||
186 | /* also give an error if the key was negatively instantiated */ | ||
187 | check_not_negative: | ||
188 | if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { | ||
189 | key_put(key); | ||
190 | key = ERR_PTR(-ENOKEY); | ||
191 | } | ||
192 | |||
193 | out: | ||
194 | kleave(" = %p", key); | ||
195 | return key; | ||
196 | |||
197 | request_failed: | ||
198 | key_revoke(authkey); | ||
199 | key_put(authkey); | ||
200 | |||
201 | alloc_authkey_failed: | ||
202 | /* it wasn't instantiated | ||
203 | * - remove from construction queue | ||
204 | * - mark the key as dead | ||
205 | */ | ||
206 | negated = 0; | ||
207 | down_write(&key_construction_sem); | ||
208 | |||
209 | list_del(&cons.link); | ||
210 | |||
211 | /* check it didn't get instantiated between the check and the down */ | ||
212 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { | ||
213 | set_bit(KEY_FLAG_NEGATIVE, &key->flags); | ||
214 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); | ||
215 | negated = 1; | ||
216 | } | ||
217 | |||
218 | clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); | ||
219 | |||
220 | up_write(&key_construction_sem); | ||
221 | |||
222 | if (!negated) | ||
223 | goto check_not_negative; /* surprisingly, the key got | ||
224 | * instantiated */ | ||
225 | |||
226 | /* set the timeout and store in the session keyring if we can */ | ||
227 | now = current_kernel_time(); | ||
228 | key->expiry = now.tv_sec + key_negative_timeout; | ||
229 | |||
230 | if (current->signal->session_keyring) { | ||
231 | struct key *keyring; | ||
232 | |||
233 | rcu_read_lock(); | ||
234 | keyring = rcu_dereference(current->signal->session_keyring); | ||
235 | atomic_inc(&keyring->usage); | ||
236 | rcu_read_unlock(); | ||
237 | |||
238 | key_link(keyring, key); | ||
239 | key_put(keyring); | ||
240 | } | ||
241 | |||
242 | key_put(key); | ||
243 | |||
244 | /* notify anyone who was waiting */ | ||
245 | wake_up_all(&request_key_conswq); | ||
246 | |||
247 | key = ERR_PTR(ret); | ||
248 | goto out; | ||
249 | |||
250 | alloc_failed: | ||
251 | up_write(&key_construction_sem); | ||
252 | goto out; | ||
253 | |||
254 | } /* end __request_key_construction() */ | ||
255 | |||
256 | /*****************************************************************************/ | ||
257 | /* | ||
258 | * call out to userspace to request the key | ||
259 | * - we check the construction queue first to see if an appropriate key is | ||
260 | * already being constructed by userspace | ||
261 | */ | ||
262 | static struct key *request_key_construction(struct key_type *type, | ||
263 | const char *description, | ||
264 | const char *callout_info, | ||
265 | void *aux, | ||
266 | struct key_user *user, | ||
267 | unsigned long flags) | ||
268 | { | ||
269 | struct key_construction *pcons; | ||
270 | struct key *key, *ckey; | ||
271 | |||
272 | DECLARE_WAITQUEUE(myself, current); | ||
273 | |||
274 | kenter("%s,%s,{%d},%s,%lx", | ||
275 | type->name, description, user->uid, callout_info, flags); | ||
276 | |||
277 | /* see if there's such a key under construction already */ | ||
278 | down_write(&key_construction_sem); | ||
279 | |||
280 | list_for_each_entry(pcons, &user->consq, link) { | ||
281 | ckey = pcons->key; | ||
282 | |||
283 | if (ckey->type != type) | ||
284 | continue; | ||
285 | |||
286 | if (type->match(ckey, description)) | ||
287 | goto found_key_under_construction; | ||
288 | } | 199 | } |
289 | 200 | ||
290 | /* see about getting userspace to construct the key */ | 201 | kleave(" = %d", ret); |
291 | key = __request_key_construction(type, description, callout_info, aux, | 202 | return ret; |
292 | flags); | 203 | } |
293 | error: | ||
294 | kleave(" = %p", key); | ||
295 | return key; | ||
296 | |||
297 | /* someone else has the same key under construction | ||
298 | * - we want to keep an eye on their key | ||
299 | */ | ||
300 | found_key_under_construction: | ||
301 | atomic_inc(&ckey->usage); | ||
302 | up_write(&key_construction_sem); | ||
303 | |||
304 | /* wait for the key to be completed one way or another */ | ||
305 | add_wait_queue(&request_key_conswq, &myself); | ||
306 | |||
307 | for (;;) { | ||
308 | set_current_state(TASK_INTERRUPTIBLE); | ||
309 | if (!test_bit(KEY_FLAG_USER_CONSTRUCT, &ckey->flags)) | ||
310 | break; | ||
311 | if (signal_pending(current)) | ||
312 | break; | ||
313 | schedule(); | ||
314 | } | ||
315 | |||
316 | set_current_state(TASK_RUNNING); | ||
317 | remove_wait_queue(&request_key_conswq, &myself); | ||
318 | |||
319 | /* we'll need to search this process's keyrings to see if the key is | ||
320 | * now there since we can't automatically assume it's also available | ||
321 | * there */ | ||
322 | key_put(ckey); | ||
323 | ckey = NULL; | ||
324 | |||
325 | key = NULL; /* request a retry */ | ||
326 | goto error; | ||
327 | |||
328 | } /* end request_key_construction() */ | ||
329 | 204 | ||
330 | /*****************************************************************************/ | ||
331 | /* | 205 | /* |
332 | * link a freshly minted key to an appropriate destination keyring | 206 | * link a key to the appropriate destination keyring |
207 | * - the caller must hold a write lock on the destination keyring | ||
333 | */ | 208 | */ |
334 | static void request_key_link(struct key *key, struct key *dest_keyring) | 209 | static void construct_key_make_link(struct key *key, struct key *dest_keyring) |
335 | { | 210 | { |
336 | struct task_struct *tsk = current; | 211 | struct task_struct *tsk = current; |
337 | struct key *drop = NULL; | 212 | struct key *drop = NULL; |
@@ -363,11 +238,11 @@ static void request_key_link(struct key *key, struct key *dest_keyring) | |||
363 | break; | 238 | break; |
364 | 239 | ||
365 | case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: | 240 | case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: |
366 | dest_keyring = current->user->session_keyring; | 241 | dest_keyring = tsk->user->session_keyring; |
367 | break; | 242 | break; |
368 | 243 | ||
369 | case KEY_REQKEY_DEFL_USER_KEYRING: | 244 | case KEY_REQKEY_DEFL_USER_KEYRING: |
370 | dest_keyring = current->user->uid_keyring; | 245 | dest_keyring = tsk->user->uid_keyring; |
371 | break; | 246 | break; |
372 | 247 | ||
373 | case KEY_REQKEY_DEFL_GROUP_KEYRING: | 248 | case KEY_REQKEY_DEFL_GROUP_KEYRING: |
@@ -377,15 +252,115 @@ static void request_key_link(struct key *key, struct key *dest_keyring) | |||
377 | } | 252 | } |
378 | 253 | ||
379 | /* and attach the key to it */ | 254 | /* and attach the key to it */ |
380 | key_link(dest_keyring, key); | 255 | __key_link(dest_keyring, key); |
381 | |||
382 | key_put(drop); | 256 | key_put(drop); |
383 | |||
384 | kleave(""); | 257 | kleave(""); |
258 | } | ||
385 | 259 | ||
386 | } /* end request_key_link() */ | 260 | /* |
261 | * allocate a new key in under-construction state and attempt to link it in to | ||
262 | * the requested place | ||
263 | * - may return a key that's already under construction instead | ||
264 | */ | ||
265 | static int construct_alloc_key(struct key_type *type, | ||
266 | const char *description, | ||
267 | struct key *dest_keyring, | ||
268 | unsigned long flags, | ||
269 | struct key_user *user, | ||
270 | struct key **_key) | ||
271 | { | ||
272 | struct key *key; | ||
273 | key_ref_t key_ref; | ||
274 | |||
275 | kenter("%s,%s,,,", type->name, description); | ||
276 | |||
277 | mutex_lock(&user->cons_lock); | ||
278 | |||
279 | key = key_alloc(type, description, | ||
280 | current->fsuid, current->fsgid, current, KEY_POS_ALL, | ||
281 | flags); | ||
282 | if (IS_ERR(key)) | ||
283 | goto alloc_failed; | ||
284 | |||
285 | set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); | ||
286 | |||
287 | if (dest_keyring) | ||
288 | down_write(&dest_keyring->sem); | ||
289 | |||
290 | /* attach the key to the destination keyring under lock, but we do need | ||
291 | * to do another check just in case someone beat us to it whilst we | ||
292 | * waited for locks */ | ||
293 | mutex_lock(&key_construction_mutex); | ||
294 | |||
295 | key_ref = search_process_keyrings(type, description, type->match, | ||
296 | current); | ||
297 | if (!IS_ERR(key_ref)) | ||
298 | goto key_already_present; | ||
299 | |||
300 | if (dest_keyring) | ||
301 | construct_key_make_link(key, dest_keyring); | ||
302 | |||
303 | mutex_unlock(&key_construction_mutex); | ||
304 | if (dest_keyring) | ||
305 | up_write(&dest_keyring->sem); | ||
306 | mutex_unlock(&user->cons_lock); | ||
307 | *_key = key; | ||
308 | kleave(" = 0 [%d]", key_serial(key)); | ||
309 | return 0; | ||
310 | |||
311 | key_already_present: | ||
312 | mutex_unlock(&key_construction_mutex); | ||
313 | if (dest_keyring) | ||
314 | up_write(&dest_keyring->sem); | ||
315 | mutex_unlock(&user->cons_lock); | ||
316 | key_put(key); | ||
317 | *_key = key = key_ref_to_ptr(key_ref); | ||
318 | kleave(" = -EINPROGRESS [%d]", key_serial(key)); | ||
319 | return -EINPROGRESS; | ||
320 | |||
321 | alloc_failed: | ||
322 | mutex_unlock(&user->cons_lock); | ||
323 | *_key = NULL; | ||
324 | kleave(" = %ld", PTR_ERR(key)); | ||
325 | return PTR_ERR(key); | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | * commence key construction | ||
330 | */ | ||
331 | static struct key *construct_key_and_link(struct key_type *type, | ||
332 | const char *description, | ||
333 | const char *callout_info, | ||
334 | void *aux, | ||
335 | struct key *dest_keyring, | ||
336 | unsigned long flags) | ||
337 | { | ||
338 | struct key_user *user; | ||
339 | struct key *key; | ||
340 | int ret; | ||
341 | |||
342 | user = key_user_lookup(current->fsuid); | ||
343 | if (!user) | ||
344 | return ERR_PTR(-ENOMEM); | ||
345 | |||
346 | ret = construct_alloc_key(type, description, dest_keyring, flags, user, | ||
347 | &key); | ||
348 | key_user_put(user); | ||
349 | |||
350 | if (ret == 0) { | ||
351 | ret = construct_key(key, callout_info, aux); | ||
352 | if (ret < 0) | ||
353 | goto construction_failed; | ||
354 | } | ||
355 | |||
356 | return key; | ||
357 | |||
358 | construction_failed: | ||
359 | key_negate_and_link(key, key_negative_timeout, NULL, NULL); | ||
360 | key_put(key); | ||
361 | return ERR_PTR(ret); | ||
362 | } | ||
387 | 363 | ||
388 | /*****************************************************************************/ | ||
389 | /* | 364 | /* |
390 | * request a key | 365 | * request a key |
391 | * - search the process's keyrings | 366 | * - search the process's keyrings |
@@ -400,7 +375,6 @@ struct key *request_key_and_link(struct key_type *type, | |||
400 | struct key *dest_keyring, | 375 | struct key *dest_keyring, |
401 | unsigned long flags) | 376 | unsigned long flags) |
402 | { | 377 | { |
403 | struct key_user *user; | ||
404 | struct key *key; | 378 | struct key *key; |
405 | key_ref_t key_ref; | 379 | key_ref_t key_ref; |
406 | 380 | ||
@@ -412,112 +386,124 @@ struct key *request_key_and_link(struct key_type *type, | |||
412 | key_ref = search_process_keyrings(type, description, type->match, | 386 | key_ref = search_process_keyrings(type, description, type->match, |
413 | current); | 387 | current); |
414 | 388 | ||
415 | kdebug("search 1: %p", key_ref); | ||
416 | |||
417 | if (!IS_ERR(key_ref)) { | 389 | if (!IS_ERR(key_ref)) { |
418 | key = key_ref_to_ptr(key_ref); | 390 | key = key_ref_to_ptr(key_ref); |
419 | } | 391 | } else if (PTR_ERR(key_ref) != -EAGAIN) { |
420 | else if (PTR_ERR(key_ref) != -EAGAIN) { | ||
421 | key = ERR_PTR(PTR_ERR(key_ref)); | 392 | key = ERR_PTR(PTR_ERR(key_ref)); |
422 | } | 393 | } else { |
423 | else { | ||
424 | /* the search failed, but the keyrings were searchable, so we | 394 | /* the search failed, but the keyrings were searchable, so we |
425 | * should consult userspace if we can */ | 395 | * should consult userspace if we can */ |
426 | key = ERR_PTR(-ENOKEY); | 396 | key = ERR_PTR(-ENOKEY); |
427 | if (!callout_info) | 397 | if (!callout_info) |
428 | goto error; | 398 | goto error; |
429 | 399 | ||
430 | /* - get hold of the user's construction queue */ | 400 | key = construct_key_and_link(type, description, callout_info, |
431 | user = key_user_lookup(current->fsuid); | 401 | aux, dest_keyring, flags); |
432 | if (!user) | ||
433 | goto nomem; | ||
434 | |||
435 | for (;;) { | ||
436 | if (signal_pending(current)) | ||
437 | goto interrupted; | ||
438 | |||
439 | /* ask userspace (returns NULL if it waited on a key | ||
440 | * being constructed) */ | ||
441 | key = request_key_construction(type, description, | ||
442 | callout_info, aux, | ||
443 | user, flags); | ||
444 | if (key) | ||
445 | break; | ||
446 | |||
447 | /* someone else made the key we want, so we need to | ||
448 | * search again as it might now be available to us */ | ||
449 | key_ref = search_process_keyrings(type, description, | ||
450 | type->match, | ||
451 | current); | ||
452 | |||
453 | kdebug("search 2: %p", key_ref); | ||
454 | |||
455 | if (!IS_ERR(key_ref)) { | ||
456 | key = key_ref_to_ptr(key_ref); | ||
457 | break; | ||
458 | } | ||
459 | |||
460 | if (PTR_ERR(key_ref) != -EAGAIN) { | ||
461 | key = ERR_PTR(PTR_ERR(key_ref)); | ||
462 | break; | ||
463 | } | ||
464 | } | ||
465 | |||
466 | key_user_put(user); | ||
467 | |||
468 | /* link the new key into the appropriate keyring */ | ||
469 | if (!IS_ERR(key)) | ||
470 | request_key_link(key, dest_keyring); | ||
471 | } | 402 | } |
472 | 403 | ||
473 | error: | 404 | error: |
474 | kleave(" = %p", key); | 405 | kleave(" = %p", key); |
475 | return key; | 406 | return key; |
407 | } | ||
476 | 408 | ||
477 | nomem: | 409 | /* |
478 | key = ERR_PTR(-ENOMEM); | 410 | * wait for construction of a key to complete |
479 | goto error; | 411 | */ |
480 | 412 | int wait_for_key_construction(struct key *key, bool intr) | |
481 | interrupted: | 413 | { |
482 | key_user_put(user); | 414 | int ret; |
483 | key = ERR_PTR(-EINTR); | ||
484 | goto error; | ||
485 | 415 | ||
486 | } /* end request_key_and_link() */ | 416 | ret = wait_on_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT, |
417 | intr ? key_wait_bit_intr : key_wait_bit, | ||
418 | intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); | ||
419 | if (ret < 0) | ||
420 | return ret; | ||
421 | return key_validate(key); | ||
422 | } | ||
423 | EXPORT_SYMBOL(wait_for_key_construction); | ||
487 | 424 | ||
488 | /*****************************************************************************/ | ||
489 | /* | 425 | /* |
490 | * request a key | 426 | * request a key |
491 | * - search the process's keyrings | 427 | * - search the process's keyrings |
492 | * - check the list of keys being created or updated | 428 | * - check the list of keys being created or updated |
493 | * - call out to userspace for a key if supplementary info was provided | 429 | * - call out to userspace for a key if supplementary info was provided |
430 | * - waits uninterruptible for creation to complete | ||
494 | */ | 431 | */ |
495 | struct key *request_key(struct key_type *type, | 432 | struct key *request_key(struct key_type *type, |
496 | const char *description, | 433 | const char *description, |
497 | const char *callout_info) | 434 | const char *callout_info) |
498 | { | 435 | { |
499 | return request_key_and_link(type, description, callout_info, NULL, | 436 | struct key *key; |
500 | NULL, KEY_ALLOC_IN_QUOTA); | 437 | int ret; |
501 | 438 | ||
502 | } /* end request_key() */ | 439 | key = request_key_and_link(type, description, callout_info, NULL, |
503 | 440 | NULL, KEY_ALLOC_IN_QUOTA); | |
441 | if (!IS_ERR(key)) { | ||
442 | ret = wait_for_key_construction(key, false); | ||
443 | if (ret < 0) { | ||
444 | key_put(key); | ||
445 | return ERR_PTR(ret); | ||
446 | } | ||
447 | } | ||
448 | return key; | ||
449 | } | ||
504 | EXPORT_SYMBOL(request_key); | 450 | EXPORT_SYMBOL(request_key); |
505 | 451 | ||
506 | /*****************************************************************************/ | ||
507 | /* | 452 | /* |
508 | * request a key with auxiliary data for the upcaller | 453 | * request a key with auxiliary data for the upcaller |
509 | * - search the process's keyrings | 454 | * - search the process's keyrings |
510 | * - check the list of keys being created or updated | 455 | * - check the list of keys being created or updated |
511 | * - call out to userspace for a key if supplementary info was provided | 456 | * - call out to userspace for a key if supplementary info was provided |
457 | * - waits uninterruptible for creation to complete | ||
512 | */ | 458 | */ |
513 | struct key *request_key_with_auxdata(struct key_type *type, | 459 | struct key *request_key_with_auxdata(struct key_type *type, |
514 | const char *description, | 460 | const char *description, |
515 | const char *callout_info, | 461 | const char *callout_info, |
516 | void *aux) | 462 | void *aux) |
517 | { | 463 | { |
518 | return request_key_and_link(type, description, callout_info, aux, | 464 | struct key *key; |
519 | NULL, KEY_ALLOC_IN_QUOTA); | 465 | int ret; |
466 | |||
467 | key = request_key_and_link(type, description, callout_info, aux, | ||
468 | NULL, KEY_ALLOC_IN_QUOTA); | ||
469 | if (!IS_ERR(key)) { | ||
470 | ret = wait_for_key_construction(key, false); | ||
471 | if (ret < 0) { | ||
472 | key_put(key); | ||
473 | return ERR_PTR(ret); | ||
474 | } | ||
475 | } | ||
476 | return key; | ||
477 | } | ||
478 | EXPORT_SYMBOL(request_key_with_auxdata); | ||
520 | 479 | ||
521 | } /* end request_key_with_auxdata() */ | 480 | /* |
481 | * request a key (allow async construction) | ||
482 | * - search the process's keyrings | ||
483 | * - check the list of keys being created or updated | ||
484 | * - call out to userspace for a key if supplementary info was provided | ||
485 | */ | ||
486 | struct key *request_key_async(struct key_type *type, | ||
487 | const char *description, | ||
488 | const char *callout_info) | ||
489 | { | ||
490 | return request_key_and_link(type, description, callout_info, NULL, | ||
491 | NULL, KEY_ALLOC_IN_QUOTA); | ||
492 | } | ||
493 | EXPORT_SYMBOL(request_key_async); | ||
522 | 494 | ||
523 | EXPORT_SYMBOL(request_key_with_auxdata); | 495 | /* |
496 | * request a key with auxiliary data for the upcaller (allow async construction) | ||
497 | * - search the process's keyrings | ||
498 | * - check the list of keys being created or updated | ||
499 | * - call out to userspace for a key if supplementary info was provided | ||
500 | */ | ||
501 | struct key *request_key_async_with_auxdata(struct key_type *type, | ||
502 | const char *description, | ||
503 | const char *callout_info, | ||
504 | void *aux) | ||
505 | { | ||
506 | return request_key_and_link(type, description, callout_info, aux, | ||
507 | NULL, KEY_ALLOC_IN_QUOTA); | ||
508 | } | ||
509 | EXPORT_SYMBOL(request_key_async_with_auxdata); | ||
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index cbf58a91b00a..510f7be73a2d 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c | |||
@@ -127,6 +127,7 @@ static void request_key_auth_destroy(struct key *key) | |||
127 | } | 127 | } |
128 | 128 | ||
129 | key_put(rka->target_key); | 129 | key_put(rka->target_key); |
130 | kfree(rka->callout_info); | ||
130 | kfree(rka); | 131 | kfree(rka); |
131 | 132 | ||
132 | } /* end request_key_auth_destroy() */ | 133 | } /* end request_key_auth_destroy() */ |
@@ -151,6 +152,12 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info) | |||
151 | kleave(" = -ENOMEM"); | 152 | kleave(" = -ENOMEM"); |
152 | return ERR_PTR(-ENOMEM); | 153 | return ERR_PTR(-ENOMEM); |
153 | } | 154 | } |
155 | rka->callout_info = kmalloc(strlen(callout_info) + 1, GFP_KERNEL); | ||
156 | if (!rka->callout_info) { | ||
157 | kleave(" = -ENOMEM"); | ||
158 | kfree(rka); | ||
159 | return ERR_PTR(-ENOMEM); | ||
160 | } | ||
154 | 161 | ||
155 | /* see if the calling process is already servicing the key request of | 162 | /* see if the calling process is already servicing the key request of |
156 | * another process */ | 163 | * another process */ |
@@ -179,7 +186,7 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info) | |||
179 | } | 186 | } |
180 | 187 | ||
181 | rka->target_key = key_get(target); | 188 | rka->target_key = key_get(target); |
182 | rka->callout_info = callout_info; | 189 | strcpy(rka->callout_info, callout_info); |
183 | 190 | ||
184 | /* allocate the auth key */ | 191 | /* allocate the auth key */ |
185 | sprintf(desc, "%x", target->serial); | 192 | sprintf(desc, "%x", target->serial); |
@@ -203,6 +210,7 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info) | |||
203 | 210 | ||
204 | auth_key_revoked: | 211 | auth_key_revoked: |
205 | up_read(¤t->request_key_auth->sem); | 212 | up_read(¤t->request_key_auth->sem); |
213 | kfree(rka->callout_info); | ||
206 | kfree(rka); | 214 | kfree(rka); |
207 | kleave("= -EKEYREVOKED"); | 215 | kleave("= -EKEYREVOKED"); |
208 | return ERR_PTR(-EKEYREVOKED); | 216 | return ERR_PTR(-EKEYREVOKED); |
@@ -212,6 +220,7 @@ error_inst: | |||
212 | key_put(authkey); | 220 | key_put(authkey); |
213 | error_alloc: | 221 | error_alloc: |
214 | key_put(rka->target_key); | 222 | key_put(rka->target_key); |
223 | kfree(rka->callout_info); | ||
215 | kfree(rka); | 224 | kfree(rka); |
216 | kleave("= %d", ret); | 225 | kleave("= %d", ret); |
217 | return ERR_PTR(ret); | 226 | return ERR_PTR(ret); |