aboutsummaryrefslogtreecommitdiffstats
path: root/security/keys/request_key.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/keys/request_key.c')
-rw-r--r--security/keys/request_key.c182
1 files changed, 150 insertions, 32 deletions
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 54aa7b70e63b..dfcd983af1fd 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_key.c: request a key from userspace
2 * 2 *
3 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. 3 * Copyright (C) 2004-5 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
@@ -13,6 +13,7 @@
13#include <linux/sched.h> 13#include <linux/sched.h>
14#include <linux/kmod.h> 14#include <linux/kmod.h>
15#include <linux/err.h> 15#include <linux/err.h>
16#include <linux/keyctl.h>
16#include "internal.h" 17#include "internal.h"
17 18
18struct key_construction { 19struct key_construction {
@@ -27,18 +28,26 @@ DECLARE_WAIT_QUEUE_HEAD(request_key_conswq);
27/* 28/*
28 * request userspace finish the construction of a key 29 * request userspace finish the construction of a key
29 * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring> <info>" 30 * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring> <info>"
30 * - if callout_info is an empty string, it'll be rendered as a "-" instead
31 */ 31 */
32static int call_request_key(struct key *key, 32static int call_request_key(struct key *key,
33 const char *op, 33 const char *op,
34 const char *callout_info) 34 const char *callout_info)
35{ 35{
36 struct task_struct *tsk = current; 36 struct task_struct *tsk = current;
37 unsigned long flags;
38 key_serial_t prkey, sskey; 37 key_serial_t prkey, sskey;
38 struct key *session_keyring, *rkakey;
39 char *argv[10], *envp[3], uid_str[12], gid_str[12]; 39 char *argv[10], *envp[3], uid_str[12], gid_str[12];
40 char key_str[12], keyring_str[3][12]; 40 char key_str[12], keyring_str[3][12];
41 int i; 41 int ret, i;
42
43 kenter("{%d},%s,%s", key->serial, op, callout_info);
44
45 /* generate a new session keyring with an auth key in it */
46 session_keyring = request_key_auth_new(key, &rkakey);
47 if (IS_ERR(session_keyring)) {
48 ret = PTR_ERR(session_keyring);
49 goto error;
50 }
42 51
43 /* record the UID and GID */ 52 /* record the UID and GID */
44 sprintf(uid_str, "%d", current->fsuid); 53 sprintf(uid_str, "%d", current->fsuid);
@@ -55,17 +64,17 @@ static int call_request_key(struct key *key,
55 if (tsk->signal->process_keyring) 64 if (tsk->signal->process_keyring)
56 prkey = tsk->signal->process_keyring->serial; 65 prkey = tsk->signal->process_keyring->serial;
57 66
58 sskey = 0; 67 sprintf(keyring_str[1], "%d", prkey);
59 spin_lock_irqsave(&tsk->sighand->siglock, flags);
60 if (tsk->signal->session_keyring)
61 sskey = tsk->signal->session_keyring->serial;
62 spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
63
64 68
65 if (!sskey) 69 if (tsk->signal->session_keyring) {
70 rcu_read_lock();
71 sskey = rcu_dereference(tsk->signal->session_keyring)->serial;
72 rcu_read_unlock();
73 }
74 else {
66 sskey = tsk->user->session_keyring->serial; 75 sskey = tsk->user->session_keyring->serial;
76 }
67 77
68 sprintf(keyring_str[1], "%d", prkey);
69 sprintf(keyring_str[2], "%d", sskey); 78 sprintf(keyring_str[2], "%d", sskey);
70 79
71 /* set up a minimal environment */ 80 /* set up a minimal environment */
@@ -84,11 +93,20 @@ static int call_request_key(struct key *key,
84 argv[i++] = keyring_str[0]; 93 argv[i++] = keyring_str[0];
85 argv[i++] = keyring_str[1]; 94 argv[i++] = keyring_str[1];
86 argv[i++] = keyring_str[2]; 95 argv[i++] = keyring_str[2];
87 argv[i++] = callout_info[0] ? (char *) callout_info : "-"; 96 argv[i++] = (char *) callout_info;
88 argv[i] = NULL; 97 argv[i] = NULL;
89 98
90 /* do it */ 99 /* do it */
91 return call_usermodehelper_keys(argv[0], argv, envp, NULL, 1); 100 ret = call_usermodehelper_keys(argv[0], argv, envp, session_keyring, 1);
101
102 /* dispose of the special keys */
103 key_revoke(rkakey);
104 key_put(rkakey);
105 key_put(session_keyring);
106
107 error:
108 kleave(" = %d", ret);
109 return ret;
92 110
93} /* end call_request_key() */ 111} /* end call_request_key() */
94 112
@@ -107,6 +125,8 @@ static struct key *__request_key_construction(struct key_type *type,
107 struct key *key; 125 struct key *key;
108 int ret, negated; 126 int ret, negated;
109 127
128 kenter("%s,%s,%s", type->name, description, callout_info);
129
110 /* create a key and add it to the queue */ 130 /* create a key and add it to the queue */
111 key = key_alloc(type, description, 131 key = key_alloc(type, description,
112 current->fsuid, current->fsgid, KEY_USR_ALL, 0); 132 current->fsuid, current->fsgid, KEY_USR_ALL, 0);
@@ -143,6 +163,7 @@ static struct key *__request_key_construction(struct key_type *type,
143 } 163 }
144 164
145 out: 165 out:
166 kleave(" = %p", key);
146 return key; 167 return key;
147 168
148 request_failed: 169 request_failed:
@@ -216,6 +237,9 @@ static struct key *request_key_construction(struct key_type *type,
216 237
217 DECLARE_WAITQUEUE(myself, current); 238 DECLARE_WAITQUEUE(myself, current);
218 239
240 kenter("%s,%s,{%d},%s",
241 type->name, description, user->uid, callout_info);
242
219 /* see if there's such a key under construction already */ 243 /* see if there's such a key under construction already */
220 down_write(&key_construction_sem); 244 down_write(&key_construction_sem);
221 245
@@ -232,6 +256,7 @@ static struct key *request_key_construction(struct key_type *type,
232 /* see about getting userspace to construct the key */ 256 /* see about getting userspace to construct the key */
233 key = __request_key_construction(type, description, callout_info); 257 key = __request_key_construction(type, description, callout_info);
234 error: 258 error:
259 kleave(" = %p", key);
235 return key; 260 return key;
236 261
237 /* someone else has the same key under construction 262 /* someone else has the same key under construction
@@ -245,9 +270,11 @@ static struct key *request_key_construction(struct key_type *type,
245 add_wait_queue(&request_key_conswq, &myself); 270 add_wait_queue(&request_key_conswq, &myself);
246 271
247 for (;;) { 272 for (;;) {
248 set_current_state(TASK_UNINTERRUPTIBLE); 273 set_current_state(TASK_INTERRUPTIBLE);
249 if (!test_bit(KEY_FLAG_USER_CONSTRUCT, &ckey->flags)) 274 if (!test_bit(KEY_FLAG_USER_CONSTRUCT, &ckey->flags))
250 break; 275 break;
276 if (signal_pending(current))
277 break;
251 schedule(); 278 schedule();
252 } 279 }
253 280
@@ -267,21 +294,83 @@ static struct key *request_key_construction(struct key_type *type,
267 294
268/*****************************************************************************/ 295/*****************************************************************************/
269/* 296/*
297 * link a freshly minted key to an appropriate destination keyring
298 */
299static void request_key_link(struct key *key, struct key *dest_keyring)
300{
301 struct task_struct *tsk = current;
302 struct key *drop = NULL;
303
304 kenter("{%d},%p", key->serial, dest_keyring);
305
306 /* find the appropriate keyring */
307 if (!dest_keyring) {
308 switch (tsk->jit_keyring) {
309 case KEY_REQKEY_DEFL_DEFAULT:
310 case KEY_REQKEY_DEFL_THREAD_KEYRING:
311 dest_keyring = tsk->thread_keyring;
312 if (dest_keyring)
313 break;
314
315 case KEY_REQKEY_DEFL_PROCESS_KEYRING:
316 dest_keyring = tsk->signal->process_keyring;
317 if (dest_keyring)
318 break;
319
320 case KEY_REQKEY_DEFL_SESSION_KEYRING:
321 rcu_read_lock();
322 dest_keyring = key_get(
323 rcu_dereference(tsk->signal->session_keyring));
324 rcu_read_unlock();
325 drop = dest_keyring;
326
327 if (dest_keyring)
328 break;
329
330 case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
331 dest_keyring = current->user->session_keyring;
332 break;
333
334 case KEY_REQKEY_DEFL_USER_KEYRING:
335 dest_keyring = current->user->uid_keyring;
336 break;
337
338 case KEY_REQKEY_DEFL_GROUP_KEYRING:
339 default:
340 BUG();
341 }
342 }
343
344 /* and attach the key to it */
345 key_link(dest_keyring, key);
346
347 key_put(drop);
348
349 kleave("");
350
351} /* end request_key_link() */
352
353/*****************************************************************************/
354/*
270 * request a key 355 * request a key
271 * - search the process's keyrings 356 * - search the process's keyrings
272 * - check the list of keys being created or updated 357 * - check the list of keys being created or updated
273 * - call out to userspace for a key if requested (supplementary info can be 358 * - call out to userspace for a key if supplementary info was provided
274 * passed) 359 * - cache the key in an appropriate keyring
275 */ 360 */
276struct key *request_key(struct key_type *type, 361struct key *request_key_and_link(struct key_type *type,
277 const char *description, 362 const char *description,
278 const char *callout_info) 363 const char *callout_info,
364 struct key *dest_keyring)
279{ 365{
280 struct key_user *user; 366 struct key_user *user;
281 struct key *key; 367 struct key *key;
282 368
369 kenter("%s,%s,%s,%p",
370 type->name, description, callout_info, dest_keyring);
371
283 /* search all the process keyrings for a key */ 372 /* search all the process keyrings for a key */
284 key = search_process_keyrings_aux(type, description, type->match); 373 key = search_process_keyrings(type, description, type->match, current);
285 374
286 if (PTR_ERR(key) == -EAGAIN) { 375 if (PTR_ERR(key) == -EAGAIN) {
287 /* the search failed, but the keyrings were searchable, so we 376 /* the search failed, but the keyrings were searchable, so we
@@ -292,12 +381,13 @@ struct key *request_key(struct key_type *type,
292 381
293 /* - get hold of the user's construction queue */ 382 /* - get hold of the user's construction queue */
294 user = key_user_lookup(current->fsuid); 383 user = key_user_lookup(current->fsuid);
295 if (!user) { 384 if (!user)
296 key = ERR_PTR(-ENOMEM); 385 goto nomem;
297 goto error; 386
298 } 387 do {
388 if (signal_pending(current))
389 goto interrupted;
299 390
300 for (;;) {
301 /* ask userspace (returns NULL if it waited on a key 391 /* ask userspace (returns NULL if it waited on a key
302 * being constructed) */ 392 * being constructed) */
303 key = request_key_construction(type, description, 393 key = request_key_construction(type, description,
@@ -307,18 +397,46 @@ struct key *request_key(struct key_type *type,
307 397
308 /* someone else made the key we want, so we need to 398 /* someone else made the key we want, so we need to
309 * search again as it might now be available to us */ 399 * search again as it might now be available to us */
310 key = search_process_keyrings_aux(type, description, 400 key = search_process_keyrings(type, description,
311 type->match); 401 type->match, current);
312 if (PTR_ERR(key) != -EAGAIN) 402
313 break; 403 } while (PTR_ERR(key) == -EAGAIN);
314 }
315 404
316 key_user_put(user); 405 key_user_put(user);
406
407 /* link the new key into the appropriate keyring */
408 if (!PTR_ERR(key))
409 request_key_link(key, dest_keyring);
317 } 410 }
318 411
319 error: 412error:
413 kleave(" = %p", key);
320 return key; 414 return key;
321 415
416nomem:
417 key = ERR_PTR(-ENOMEM);
418 goto error;
419
420interrupted:
421 key_user_put(user);
422 key = ERR_PTR(-EINTR);
423 goto error;
424
425} /* end request_key_and_link() */
426
427/*****************************************************************************/
428/*
429 * request a key
430 * - search the process's keyrings
431 * - check the list of keys being created or updated
432 * - call out to userspace for a key if supplementary info was provided
433 */
434struct key *request_key(struct key_type *type,
435 const char *description,
436 const char *callout_info)
437{
438 return request_key_and_link(type, description, callout_info, NULL);
439
322} /* end request_key() */ 440} /* end request_key() */
323 441
324EXPORT_SYMBOL(request_key); 442EXPORT_SYMBOL(request_key);