aboutsummaryrefslogtreecommitdiffstats
path: root/security/keys/request_key.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2005-06-24 01:00:56 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-24 03:05:19 -0400
commit3e30148c3d524a9c1c63ca28261bc24c457eb07a (patch)
treea2fcc46cc11fe871ad976c07476d934a07313576 /security/keys/request_key.c
parent8589b4e00e352f983259140f25a262d973be6bc5 (diff)
[PATCH] Keys: Make request-key create an authorisation key
The attached patch makes the following changes: (1) There's a new special key type called ".request_key_auth". This is an authorisation key for when one process requests a key and another process is started to construct it. This type of key cannot be created by the user; nor can it be requested by kernel services. Authorisation keys hold two references: (a) Each refers to a key being constructed. When the key being constructed is instantiated the authorisation key is revoked, rendering it of no further use. (b) The "authorising process". This is either: (i) the process that called request_key(), or: (ii) if the process that called request_key() itself had an authorisation key in its session keyring, then the authorising process referred to by that authorisation key will also be referred to by the new authorisation key. This means that the process that initiated a chain of key requests will authorise the lot of them, and will, by default, wind up with the keys obtained from them in its keyrings. (2) request_key() creates an authorisation key which is then passed to /sbin/request-key in as part of a new session keyring. (3) When request_key() is searching for a key to hand back to the caller, if it comes across an authorisation key in the session keyring of the calling process, it will also search the keyrings of the process specified therein and it will use the specified process's credentials (fsuid, fsgid, groups) to do that rather than the calling process's credentials. This allows a process started by /sbin/request-key to find keys belonging to the authorising process. (4) A key can be read, even if the process executing KEYCTL_READ doesn't have direct read or search permission if that key is contained within the keyrings of a process specified by an authorisation key found within the calling process's session keyring, and is searchable using the credentials of the authorising process. This allows a process started by /sbin/request-key to read keys belonging to the authorising process. (5) The magic KEY_SPEC_*_KEYRING key IDs when passed to KEYCTL_INSTANTIATE or KEYCTL_NEGATE will specify a keyring of the authorising process, rather than the process doing the instantiation. (6) One of the process keyrings can be nominated as the default to which request_key() should attach new keys if not otherwise specified. This is done with KEYCTL_SET_REQKEY_KEYRING and one of the KEY_REQKEY_DEFL_* constants. The current setting can also be read using this call. (7) request_key() is partially interruptible. If it is waiting for another process to finish constructing a key, it can be interrupted. This permits a request-key cycle to be broken without recourse to rebooting. Signed-Off-By: David Howells <dhowells@redhat.com> Signed-Off-By: Benoit Boissinot <benoit.boissinot@ens-lyon.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
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);