Commit 4e54f08543d05e519e601368571cc3787fefae96
Committed by
Linus Torvalds
1 parent
94583779e6
Exists in
master
and in
7 other branches
[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>
Showing 6 changed files with 108 additions and 30 deletions Side-by-side Diff
Documentation/keys-request-key.txt
... | ... | @@ -3,16 +3,23 @@ |
3 | 3 | =================== |
4 | 4 | |
5 | 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 | |
7 | -requesting algorithm works. | |
6 | +Documentation/keys.txt). This document explains more fully how the requesting | |
7 | +algorithm works. | |
8 | 8 | |
9 | 9 | The process starts by either the kernel requesting a service by calling |
10 | -request_key(): | |
10 | +request_key*(): | |
11 | 11 | |
12 | 12 | struct key *request_key(const struct key_type *type, |
13 | 13 | const char *description, |
14 | 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 | 23 | Or by userspace invoking the request_key system call: |
17 | 24 | |
18 | 25 | key_serial_t request_key(const char *type, |
19 | 26 | |
20 | 27 | |
... | ... | @@ -20,16 +27,26 @@ |
20 | 27 | const char *callout_info, |
21 | 28 | key_serial_t dest_keyring); |
22 | 29 | |
23 | -The main difference between the two access points is that the in-kernel | |
24 | -interface does not need to link the key to a keyring to prevent it from being | |
25 | -immediately destroyed. The kernel interface returns a pointer directly to the | |
26 | -key, and it's up to the caller to destroy the key. | |
30 | +The main difference between the access points is that the in-kernel interface | |
31 | +does not need to link the key to a keyring to prevent it from being immediately | |
32 | +destroyed. The kernel interface returns a pointer directly to the key, and | |
33 | +it's up to the caller to destroy the key. | |
27 | 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. | |
39 | + | |
28 | 40 | The userspace interface links the key to a keyring associated with the process |
29 | 41 | to prevent the key from going away, and returns the serial number of the key to |
30 | 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 | 51 | THE PROCESS |
35 | 52 | =========== |
... | ... | @@ -40,8 +57,8 @@ |
40 | 57 | interface]. |
41 | 58 | |
42 | 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 | |
44 | - callout_info is not set, an error is returned. Otherwise the process | |
60 | + a suitable key there. If there is, it returns the key. If there isn't, | |
61 | + and callout_info is not set, an error is returned. Otherwise the process | |
45 | 62 | proceeds to the next step. |
46 | 63 | |
47 | 64 | (3) request_key() sees that A doesn't have the desired key yet, so it creates |
... | ... | @@ -62,7 +79,7 @@ |
62 | 79 | instantiation. |
63 | 80 | |
64 | 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 | 83 | search notes that the session keyring has auth key V in its bottom level. |
67 | 84 | |
68 | 85 | This will permit it to then search the keyrings of process A with the |
... | ... | @@ -79,10 +96,11 @@ |
79 | 96 | (10) The program then exits 0 and request_key() deletes key V and returns key |
80 | 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 | |
83 | -created uninstantiated, another auth key (X) would be created (as per step 3) | |
84 | -and another copy of /sbin/request-key spawned (as per step 4); but the context | |
85 | -specified by auth key X will still be process A, as it was in auth key V. | |
99 | +This also extends further. If key W (step 7 above) didn't exist, key W would | |
100 | +be created uninstantiated, another auth key (X) would be created (as per step | |
101 | +3) and another copy of /sbin/request-key spawned (as per step 4); but the | |
102 | +context specified by auth key X will still be process A, as it was in auth key | |
103 | +V. | |
86 | 104 | |
87 | 105 | This is because process A's keyrings can't simply be attached to |
88 | 106 | /sbin/request-key at the appropriate places because (a) execve will discard two |
89 | 107 | |
90 | 108 | |
... | ... | @@ -118,17 +136,17 @@ |
118 | 136 | |
119 | 137 | (2) It considers all the non-keyring keys within that keyring and, if any key |
120 | 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 | 140 | not, the search continues, and the error code is retained if of higher |
123 | 141 | priority than the one currently set. |
124 | 142 | |
125 | 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 | 145 | grants permission, it recurses, executing steps (2) and (3) on that |
128 | 146 | keyring. |
129 | 147 | |
130 | 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 | 150 | returned. |
133 | 151 | |
134 | 152 | When search_process_keyrings() is invoked, it performs the following searches |
... | ... | @@ -153,7 +171,7 @@ |
153 | 171 | returned. |
154 | 172 | |
155 | 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 | 176 | The error priority is: |
159 | 177 |
Documentation/keys.txt
... | ... | @@ -780,6 +780,17 @@ |
780 | 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 | 794 | (*) When it is no longer required, the key should be released using: |
784 | 795 | |
785 | 796 | void key_put(struct key *key); |
... | ... | @@ -1029,6 +1040,24 @@ |
1029 | 1040 | prevent the key's payload changing. It is not necessary to use RCU locking |
1030 | 1041 | when accessing the key's payload. It is safe to sleep in this method, such |
1031 | 1042 | as might happen when the userspace buffer is accessed. |
1043 | + | |
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*(). | |
1032 | 1061 | |
1033 | 1062 | |
1034 | 1063 | ============================ |
include/linux/key.h
... | ... | @@ -177,7 +177,8 @@ |
177 | 177 | /* |
178 | 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 | 183 | struct key_type { |
183 | 184 | /* name of the type */ |
... | ... | @@ -284,6 +285,11 @@ |
284 | 285 | extern struct key *request_key(struct key_type *type, |
285 | 286 | const char *description, |
286 | 287 | const char *callout_info); |
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); | |
287 | 293 | |
288 | 294 | extern int key_validate(struct key *key); |
289 | 295 |
security/keys/internal.h
security/keys/keyctl.c
... | ... | @@ -183,7 +183,7 @@ |
183 | 183 | } |
184 | 184 | |
185 | 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 | 187 | key_ref_to_ptr(dest_ref), |
188 | 188 | KEY_ALLOC_IN_QUOTA); |
189 | 189 | if (IS_ERR(key)) { |
security/keys/request_key.c
1 | 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 | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or |
... | ... | @@ -33,7 +33,8 @@ |
33 | 33 | */ |
34 | 34 | static int call_sbin_request_key(struct key *key, |
35 | 35 | struct key *authkey, |
36 | - const char *op) | |
36 | + const char *op, | |
37 | + void *aux) | |
37 | 38 | { |
38 | 39 | struct task_struct *tsk = current; |
39 | 40 | key_serial_t prkey, sskey; |
... | ... | @@ -127,6 +128,7 @@ |
127 | 128 | static struct key *__request_key_construction(struct key_type *type, |
128 | 129 | const char *description, |
129 | 130 | const char *callout_info, |
131 | + void *aux, | |
130 | 132 | unsigned long flags) |
131 | 133 | { |
132 | 134 | request_key_actor_t actor; |
... | ... | @@ -164,7 +166,7 @@ |
164 | 166 | actor = call_sbin_request_key; |
165 | 167 | if (type->request_key) |
166 | 168 | actor = type->request_key; |
167 | - ret = actor(key, authkey, "create"); | |
169 | + ret = actor(key, authkey, "create", aux); | |
168 | 170 | if (ret < 0) |
169 | 171 | goto request_failed; |
170 | 172 | |
171 | 173 | |
... | ... | @@ -258,8 +260,9 @@ |
258 | 260 | */ |
259 | 261 | static struct key *request_key_construction(struct key_type *type, |
260 | 262 | const char *description, |
261 | - struct key_user *user, | |
262 | 263 | const char *callout_info, |
264 | + void *aux, | |
265 | + struct key_user *user, | |
263 | 266 | unsigned long flags) |
264 | 267 | { |
265 | 268 | struct key_construction *pcons; |
... | ... | @@ -284,7 +287,7 @@ |
284 | 287 | } |
285 | 288 | |
286 | 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 | 291 | flags); |
289 | 292 | error: |
290 | 293 | kleave(" = %p", key); |
... | ... | @@ -392,6 +395,7 @@ |
392 | 395 | struct key *request_key_and_link(struct key_type *type, |
393 | 396 | const char *description, |
394 | 397 | const char *callout_info, |
398 | + void *aux, | |
395 | 399 | struct key *dest_keyring, |
396 | 400 | unsigned long flags) |
397 | 401 | { |
... | ... | @@ -399,8 +403,9 @@ |
399 | 403 | struct key *key; |
400 | 404 | key_ref_t key_ref; |
401 | 405 | |
402 | - kenter("%s,%s,%s,%p,%lx", | |
403 | - type->name, description, callout_info, dest_keyring, flags); | |
406 | + kenter("%s,%s,%s,%p,%p,%lx", | |
407 | + type->name, description, callout_info, aux, | |
408 | + dest_keyring, flags); | |
404 | 409 | |
405 | 410 | /* search all the process keyrings for a key */ |
406 | 411 | key_ref = search_process_keyrings(type, description, type->match, |
... | ... | @@ -433,8 +438,8 @@ |
433 | 438 | /* ask userspace (returns NULL if it waited on a key |
434 | 439 | * being constructed) */ |
435 | 440 | key = request_key_construction(type, description, |
436 | - user, callout_info, | |
437 | - flags); | |
441 | + callout_info, aux, | |
442 | + user, flags); | |
438 | 443 | if (key) |
439 | 444 | break; |
440 | 445 | |
441 | 446 | |
... | ... | @@ -491,9 +496,28 @@ |
491 | 496 | const char *callout_info) |
492 | 497 | { |
493 | 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 | 501 | } /* end request_key() */ |
497 | 502 | |
498 | 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); |