diff options
Diffstat (limited to 'security/keys/request_key.c')
-rw-r--r-- | security/keys/request_key.c | 556 |
1 files changed, 271 insertions, 285 deletions
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); | ||