diff options
author | David Howells <dhowells@redhat.com> | 2006-06-29 05:24:28 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-29 13:26:20 -0400 |
commit | 4e54f08543d05e519e601368571cc3787fefae96 (patch) | |
tree | 0cd9d982e5bb25abcb9251d26c36ff11e7dc81a5 | |
parent | 94583779e6625154e8d7fce33d097ae7d089e9de (diff) |
[PATCH] Keys: Allow in-kernel key requestor to pass auxiliary data to upcaller
The proposed NFS key type uses its own method of passing key requests to
userspace (upcalling) rather than invoking /sbin/request-key. This is
because the responsible userspace daemon should already be running and will
be contacted through rpc_pipefs.
This patch permits the NFS filesystem to pass auxiliary data to the upcall
operation (struct key_type::request_key) so that the upcaller can use a
pre-existing communications channel more easily.
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-By: Kevin Coffman <kwc@citi.umich.edu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | Documentation/keys-request-key.txt | 54 | ||||
-rw-r--r-- | Documentation/keys.txt | 29 | ||||
-rw-r--r-- | include/linux/key.h | 8 | ||||
-rw-r--r-- | security/keys/internal.h | 1 | ||||
-rw-r--r-- | security/keys/keyctl.c | 2 | ||||
-rw-r--r-- | security/keys/request_key.c | 44 |
6 files changed, 108 insertions, 30 deletions
diff --git a/Documentation/keys-request-key.txt b/Documentation/keys-request-key.txt index 22488d791168..c1f64fdf84cb 100644 --- a/Documentation/keys-request-key.txt +++ b/Documentation/keys-request-key.txt | |||
@@ -3,16 +3,23 @@ | |||
3 | =================== | 3 | =================== |
4 | 4 | ||
5 | The key request service is part of the key retention service (refer to | 5 | The key request service is part of the key retention service (refer to |
6 | Documentation/keys.txt). This document explains more fully how that the | 6 | Documentation/keys.txt). This document explains more fully how the requesting |
7 | requesting algorithm works. | 7 | algorithm works. |
8 | 8 | ||
9 | The process starts by either the kernel requesting a service by calling | 9 | The process starts by either the kernel requesting a service by calling |
10 | request_key(): | 10 | request_key*(): |
11 | 11 | ||
12 | struct key *request_key(const struct key_type *type, | 12 | struct key *request_key(const struct key_type *type, |
13 | const char *description, | 13 | const char *description, |
14 | const char *callout_string); | 14 | const char *callout_string); |
15 | 15 | ||
16 | or: | ||
17 | |||
18 | struct key *request_key_with_auxdata(const struct key_type *type, | ||
19 | const char *description, | ||
20 | const char *callout_string, | ||
21 | void *aux); | ||
22 | |||
16 | Or by userspace invoking the request_key system call: | 23 | Or by userspace invoking the request_key system call: |
17 | 24 | ||
18 | key_serial_t request_key(const char *type, | 25 | key_serial_t request_key(const char *type, |
@@ -20,16 +27,26 @@ Or by userspace invoking the request_key system call: | |||
20 | const char *callout_info, | 27 | const char *callout_info, |
21 | key_serial_t dest_keyring); | 28 | key_serial_t dest_keyring); |
22 | 29 | ||
23 | The main difference between the two access points is that the in-kernel | 30 | The main difference between the access points is that the in-kernel interface |
24 | interface does not need to link the key to a keyring to prevent it from being | 31 | does not need to link the key to a keyring to prevent it from being immediately |
25 | immediately destroyed. The kernel interface returns a pointer directly to the | 32 | destroyed. The kernel interface returns a pointer directly to the key, and |
26 | key, and it's up to the caller to destroy the key. | 33 | it's up to the caller to destroy the key. |
34 | |||
35 | The request_key_with_auxdata() call is like the in-kernel request_key() call, | ||
36 | except that it permits auxiliary data to be passed to the upcaller (the default | ||
37 | is NULL). This is only useful for those key types that define their own upcall | ||
38 | mechanism rather than using /sbin/request-key. | ||
27 | 39 | ||
28 | The userspace interface links the key to a keyring associated with the process | 40 | The userspace interface links the key to a keyring associated with the process |
29 | to prevent the key from going away, and returns the serial number of the key to | 41 | to prevent the key from going away, and returns the serial number of the key to |
30 | the caller. | 42 | the caller. |
31 | 43 | ||
32 | 44 | ||
45 | The following example assumes that the key types involved don't define their | ||
46 | own upcall mechanisms. If they do, then those should be substituted for the | ||
47 | forking and execution of /sbin/request-key. | ||
48 | |||
49 | |||
33 | =========== | 50 | =========== |
34 | THE PROCESS | 51 | THE PROCESS |
35 | =========== | 52 | =========== |
@@ -40,8 +57,8 @@ A request proceeds in the following manner: | |||
40 | interface]. | 57 | interface]. |
41 | 58 | ||
42 | (2) request_key() searches the process's subscribed keyrings to see if there's | 59 | (2) request_key() searches the process's subscribed keyrings to see if there's |
43 | a suitable key there. If there is, it returns the key. If there isn't, and | 60 | a suitable key there. If there is, it returns the key. If there isn't, |
44 | callout_info is not set, an error is returned. Otherwise the process | 61 | and callout_info is not set, an error is returned. Otherwise the process |
45 | proceeds to the next step. | 62 | proceeds to the next step. |
46 | 63 | ||
47 | (3) request_key() sees that A doesn't have the desired key yet, so it creates | 64 | (3) request_key() sees that A doesn't have the desired key yet, so it creates |
@@ -62,7 +79,7 @@ A request proceeds in the following manner: | |||
62 | instantiation. | 79 | instantiation. |
63 | 80 | ||
64 | (7) The program may want to access another key from A's context (say a | 81 | (7) The program may want to access another key from A's context (say a |
65 | Kerberos TGT key). It just requests the appropriate key, and the keyring | 82 | Kerberos TGT key). It just requests the appropriate key, and the keyring |
66 | search notes that the session keyring has auth key V in its bottom level. | 83 | search notes that the session keyring has auth key V in its bottom level. |
67 | 84 | ||
68 | This will permit it to then search the keyrings of process A with the | 85 | This will permit it to then search the keyrings of process A with the |
@@ -79,10 +96,11 @@ A request proceeds in the following manner: | |||
79 | (10) The program then exits 0 and request_key() deletes key V and returns key | 96 | (10) The program then exits 0 and request_key() deletes key V and returns key |
80 | U to the caller. | 97 | U to the caller. |
81 | 98 | ||
82 | This also extends further. If key W (step 7 above) didn't exist, key W would be | 99 | This also extends further. If key W (step 7 above) didn't exist, key W would |
83 | created uninstantiated, another auth key (X) would be created (as per step 3) | 100 | be created uninstantiated, another auth key (X) would be created (as per step |
84 | and another copy of /sbin/request-key spawned (as per step 4); but the context | 101 | 3) and another copy of /sbin/request-key spawned (as per step 4); but the |
85 | specified by auth key X will still be process A, as it was in auth key V. | 102 | context specified by auth key X will still be process A, as it was in auth key |
103 | V. | ||
86 | 104 | ||
87 | This is because process A's keyrings can't simply be attached to | 105 | This is because process A's keyrings can't simply be attached to |
88 | /sbin/request-key at the appropriate places because (a) execve will discard two | 106 | /sbin/request-key at the appropriate places because (a) execve will discard two |
@@ -118,17 +136,17 @@ A search of any particular keyring proceeds in the following fashion: | |||
118 | 136 | ||
119 | (2) It considers all the non-keyring keys within that keyring and, if any key | 137 | (2) It considers all the non-keyring keys within that keyring and, if any key |
120 | matches the criteria specified, calls key_permission(SEARCH) on it to see | 138 | matches the criteria specified, calls key_permission(SEARCH) on it to see |
121 | if the key is allowed to be found. If it is, that key is returned; if | 139 | if the key is allowed to be found. If it is, that key is returned; if |
122 | not, the search continues, and the error code is retained if of higher | 140 | not, the search continues, and the error code is retained if of higher |
123 | priority than the one currently set. | 141 | priority than the one currently set. |
124 | 142 | ||
125 | (3) It then considers all the keyring-type keys in the keyring it's currently | 143 | (3) It then considers all the keyring-type keys in the keyring it's currently |
126 | searching. It calls key_permission(SEARCH) on each keyring, and if this | 144 | searching. It calls key_permission(SEARCH) on each keyring, and if this |
127 | grants permission, it recurses, executing steps (2) and (3) on that | 145 | grants permission, it recurses, executing steps (2) and (3) on that |
128 | keyring. | 146 | keyring. |
129 | 147 | ||
130 | The process stops immediately a valid key is found with permission granted to | 148 | The process stops immediately a valid key is found with permission granted to |
131 | use it. Any error from a previous match attempt is discarded and the key is | 149 | use it. Any error from a previous match attempt is discarded and the key is |
132 | returned. | 150 | returned. |
133 | 151 | ||
134 | When search_process_keyrings() is invoked, it performs the following searches | 152 | When search_process_keyrings() is invoked, it performs the following searches |
@@ -153,7 +171,7 @@ The moment one succeeds, all pending errors are discarded and the found key is | |||
153 | returned. | 171 | returned. |
154 | 172 | ||
155 | Only if all these fail does the whole thing fail with the highest priority | 173 | Only if all these fail does the whole thing fail with the highest priority |
156 | error. Note that several errors may have come from LSM. | 174 | error. Note that several errors may have come from LSM. |
157 | 175 | ||
158 | The error priority is: | 176 | The error priority is: |
159 | 177 | ||
diff --git a/Documentation/keys.txt b/Documentation/keys.txt index 61c0fad2fe2f..e373f0212843 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt | |||
@@ -780,6 +780,17 @@ payload contents" for more information. | |||
780 | See also Documentation/keys-request-key.txt. | 780 | See also Documentation/keys-request-key.txt. |
781 | 781 | ||
782 | 782 | ||
783 | (*) To search for a key, passing auxiliary data to the upcaller, call: | ||
784 | |||
785 | struct key *request_key_with_auxdata(const struct key_type *type, | ||
786 | const char *description, | ||
787 | const char *callout_string, | ||
788 | void *aux); | ||
789 | |||
790 | This is identical to request_key(), except that the auxiliary data is | ||
791 | passed to the key_type->request_key() op if it exists. | ||
792 | |||
793 | |||
783 | (*) When it is no longer required, the key should be released using: | 794 | (*) When it is no longer required, the key should be released using: |
784 | 795 | ||
785 | void key_put(struct key *key); | 796 | void key_put(struct key *key); |
@@ -1031,6 +1042,24 @@ The structure has a number of fields, some of which are mandatory: | |||
1031 | as might happen when the userspace buffer is accessed. | 1042 | as might happen when the userspace buffer is accessed. |
1032 | 1043 | ||
1033 | 1044 | ||
1045 | (*) int (*request_key)(struct key *key, struct key *authkey, const char *op, | ||
1046 | void *aux); | ||
1047 | |||
1048 | This method is optional. If provided, request_key() and | ||
1049 | request_key_with_auxdata() will invoke this function rather than | ||
1050 | upcalling to /sbin/request-key to operate upon a key of this type. | ||
1051 | |||
1052 | The aux parameter is as passed to request_key_with_auxdata() or is NULL | ||
1053 | otherwise. Also passed are the key to be operated upon, the | ||
1054 | authorisation key for this operation and the operation type (currently | ||
1055 | only "create"). | ||
1056 | |||
1057 | This function should return only when the upcall is complete. Upon return | ||
1058 | the authorisation key will be revoked, and the target key will be | ||
1059 | negatively instantiated if it is still uninstantiated. The error will be | ||
1060 | returned to the caller of request_key*(). | ||
1061 | |||
1062 | |||
1034 | ============================ | 1063 | ============================ |
1035 | REQUEST-KEY CALLBACK SERVICE | 1064 | REQUEST-KEY CALLBACK SERVICE |
1036 | ============================ | 1065 | ============================ |
diff --git a/include/linux/key.h b/include/linux/key.h index e693e729bc92..169f05e4863e 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
@@ -177,7 +177,8 @@ struct key { | |||
177 | /* | 177 | /* |
178 | * kernel managed key type definition | 178 | * kernel managed key type definition |
179 | */ | 179 | */ |
180 | typedef int (*request_key_actor_t)(struct key *key, struct key *authkey, const char *op); | 180 | typedef int (*request_key_actor_t)(struct key *key, struct key *authkey, |
181 | const char *op, void *aux); | ||
181 | 182 | ||
182 | struct key_type { | 183 | struct key_type { |
183 | /* name of the type */ | 184 | /* name of the type */ |
@@ -285,6 +286,11 @@ extern struct key *request_key(struct key_type *type, | |||
285 | const char *description, | 286 | const char *description, |
286 | const char *callout_info); | 287 | const char *callout_info); |
287 | 288 | ||
289 | extern struct key *request_key_with_auxdata(struct key_type *type, | ||
290 | const char *description, | ||
291 | const char *callout_info, | ||
292 | void *aux); | ||
293 | |||
288 | extern int key_validate(struct key *key); | 294 | extern int key_validate(struct key *key); |
289 | 295 | ||
290 | extern key_ref_t key_create_or_update(key_ref_t keyring, | 296 | extern key_ref_t key_create_or_update(key_ref_t keyring, |
diff --git a/security/keys/internal.h b/security/keys/internal.h index 3c2877f0663e..1bb416f4bbce 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -99,6 +99,7 @@ extern int install_process_keyring(struct task_struct *tsk); | |||
99 | extern struct key *request_key_and_link(struct key_type *type, | 99 | extern struct key *request_key_and_link(struct key_type *type, |
100 | const char *description, | 100 | const char *description, |
101 | const char *callout_info, | 101 | const char *callout_info, |
102 | void *aux, | ||
102 | struct key *dest_keyring, | 103 | struct key *dest_keyring, |
103 | unsigned long flags); | 104 | unsigned long flags); |
104 | 105 | ||
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 329411cf8768..d9ca15c109cc 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -183,7 +183,7 @@ asmlinkage long sys_request_key(const char __user *_type, | |||
183 | } | 183 | } |
184 | 184 | ||
185 | /* do the search */ | 185 | /* do the search */ |
186 | key = request_key_and_link(ktype, description, callout_info, | 186 | key = request_key_and_link(ktype, description, callout_info, NULL, |
187 | key_ref_to_ptr(dest_ref), | 187 | key_ref_to_ptr(dest_ref), |
188 | KEY_ALLOC_IN_QUOTA); | 188 | KEY_ALLOC_IN_QUOTA); |
189 | if (IS_ERR(key)) { | 189 | if (IS_ERR(key)) { |
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 58d1efd4fc2c..f573ac189a0a 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-5 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-6 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 |
@@ -33,7 +33,8 @@ DECLARE_WAIT_QUEUE_HEAD(request_key_conswq); | |||
33 | */ | 33 | */ |
34 | static int call_sbin_request_key(struct key *key, | 34 | static int call_sbin_request_key(struct key *key, |
35 | struct key *authkey, | 35 | struct key *authkey, |
36 | const char *op) | 36 | const char *op, |
37 | void *aux) | ||
37 | { | 38 | { |
38 | struct task_struct *tsk = current; | 39 | struct task_struct *tsk = current; |
39 | key_serial_t prkey, sskey; | 40 | key_serial_t prkey, sskey; |
@@ -127,6 +128,7 @@ error_alloc: | |||
127 | static struct key *__request_key_construction(struct key_type *type, | 128 | static struct key *__request_key_construction(struct key_type *type, |
128 | const char *description, | 129 | const char *description, |
129 | const char *callout_info, | 130 | const char *callout_info, |
131 | void *aux, | ||
130 | unsigned long flags) | 132 | unsigned long flags) |
131 | { | 133 | { |
132 | request_key_actor_t actor; | 134 | request_key_actor_t actor; |
@@ -164,7 +166,7 @@ static struct key *__request_key_construction(struct key_type *type, | |||
164 | actor = call_sbin_request_key; | 166 | actor = call_sbin_request_key; |
165 | if (type->request_key) | 167 | if (type->request_key) |
166 | actor = type->request_key; | 168 | actor = type->request_key; |
167 | ret = actor(key, authkey, "create"); | 169 | ret = actor(key, authkey, "create", aux); |
168 | if (ret < 0) | 170 | if (ret < 0) |
169 | goto request_failed; | 171 | goto request_failed; |
170 | 172 | ||
@@ -258,8 +260,9 @@ alloc_failed: | |||
258 | */ | 260 | */ |
259 | static struct key *request_key_construction(struct key_type *type, | 261 | static struct key *request_key_construction(struct key_type *type, |
260 | const char *description, | 262 | const char *description, |
261 | struct key_user *user, | ||
262 | const char *callout_info, | 263 | const char *callout_info, |
264 | void *aux, | ||
265 | struct key_user *user, | ||
263 | unsigned long flags) | 266 | unsigned long flags) |
264 | { | 267 | { |
265 | struct key_construction *pcons; | 268 | struct key_construction *pcons; |
@@ -284,7 +287,7 @@ static struct key *request_key_construction(struct key_type *type, | |||
284 | } | 287 | } |
285 | 288 | ||
286 | /* see about getting userspace to construct the key */ | 289 | /* see about getting userspace to construct the key */ |
287 | key = __request_key_construction(type, description, callout_info, | 290 | key = __request_key_construction(type, description, callout_info, aux, |
288 | flags); | 291 | flags); |
289 | error: | 292 | error: |
290 | kleave(" = %p", key); | 293 | kleave(" = %p", key); |
@@ -392,6 +395,7 @@ static void request_key_link(struct key *key, struct key *dest_keyring) | |||
392 | struct key *request_key_and_link(struct key_type *type, | 395 | struct key *request_key_and_link(struct key_type *type, |
393 | const char *description, | 396 | const char *description, |
394 | const char *callout_info, | 397 | const char *callout_info, |
398 | void *aux, | ||
395 | struct key *dest_keyring, | 399 | struct key *dest_keyring, |
396 | unsigned long flags) | 400 | unsigned long flags) |
397 | { | 401 | { |
@@ -399,8 +403,9 @@ struct key *request_key_and_link(struct key_type *type, | |||
399 | struct key *key; | 403 | struct key *key; |
400 | key_ref_t key_ref; | 404 | key_ref_t key_ref; |
401 | 405 | ||
402 | kenter("%s,%s,%s,%p,%lx", | 406 | kenter("%s,%s,%s,%p,%p,%lx", |
403 | type->name, description, callout_info, dest_keyring, flags); | 407 | type->name, description, callout_info, aux, |
408 | dest_keyring, flags); | ||
404 | 409 | ||
405 | /* search all the process keyrings for a key */ | 410 | /* search all the process keyrings for a key */ |
406 | key_ref = search_process_keyrings(type, description, type->match, | 411 | key_ref = search_process_keyrings(type, description, type->match, |
@@ -433,8 +438,8 @@ struct key *request_key_and_link(struct key_type *type, | |||
433 | /* ask userspace (returns NULL if it waited on a key | 438 | /* ask userspace (returns NULL if it waited on a key |
434 | * being constructed) */ | 439 | * being constructed) */ |
435 | key = request_key_construction(type, description, | 440 | key = request_key_construction(type, description, |
436 | user, callout_info, | 441 | callout_info, aux, |
437 | flags); | 442 | user, flags); |
438 | if (key) | 443 | if (key) |
439 | break; | 444 | break; |
440 | 445 | ||
@@ -491,8 +496,27 @@ struct key *request_key(struct key_type *type, | |||
491 | const char *callout_info) | 496 | const char *callout_info) |
492 | { | 497 | { |
493 | return request_key_and_link(type, description, callout_info, NULL, | 498 | return request_key_and_link(type, description, callout_info, NULL, |
494 | KEY_ALLOC_IN_QUOTA); | 499 | NULL, KEY_ALLOC_IN_QUOTA); |
495 | 500 | ||
496 | } /* end request_key() */ | 501 | } /* end request_key() */ |
497 | 502 | ||
498 | EXPORT_SYMBOL(request_key); | 503 | EXPORT_SYMBOL(request_key); |
504 | |||
505 | /*****************************************************************************/ | ||
506 | /* | ||
507 | * request a key with auxiliary data for the upcaller | ||
508 | * - search the process's keyrings | ||
509 | * - check the list of keys being created or updated | ||
510 | * - call out to userspace for a key if supplementary info was provided | ||
511 | */ | ||
512 | struct key *request_key_with_auxdata(struct key_type *type, | ||
513 | const char *description, | ||
514 | const char *callout_info, | ||
515 | void *aux) | ||
516 | { | ||
517 | return request_key_and_link(type, description, callout_info, aux, | ||
518 | NULL, KEY_ALLOC_IN_QUOTA); | ||
519 | |||
520 | } /* end request_key_with_auxdata() */ | ||
521 | |||
522 | EXPORT_SYMBOL(request_key_with_auxdata); | ||