diff options
Diffstat (limited to 'security/keys/request_key.c')
-rw-r--r-- | security/keys/request_key.c | 221 |
1 files changed, 168 insertions, 53 deletions
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 9705b1aeba5d..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 | ||
18 | struct key_construction { | 19 | struct 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 | */ |
32 | static int call_request_key(struct key *key, | 32 | static 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(argv[0], argv, envp, 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 | ||
@@ -105,7 +123,9 @@ static struct key *__request_key_construction(struct key_type *type, | |||
105 | struct key_construction cons; | 123 | struct key_construction cons; |
106 | struct timespec now; | 124 | struct timespec now; |
107 | struct key *key; | 125 | struct key *key; |
108 | int ret, negative; | 126 | int ret, negated; |
127 | |||
128 | kenter("%s,%s,%s", type->name, description, callout_info); | ||
109 | 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, |
@@ -113,9 +133,7 @@ static struct key *__request_key_construction(struct key_type *type, | |||
113 | if (IS_ERR(key)) | 133 | if (IS_ERR(key)) |
114 | goto alloc_failed; | 134 | goto alloc_failed; |
115 | 135 | ||
116 | write_lock(&key->lock); | 136 | set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); |
117 | key->flags |= KEY_FLAG_USER_CONSTRUCT; | ||
118 | write_unlock(&key->lock); | ||
119 | 137 | ||
120 | cons.key = key; | 138 | cons.key = key; |
121 | list_add_tail(&cons.link, &key->user->consq); | 139 | list_add_tail(&cons.link, &key->user->consq); |
@@ -130,7 +148,7 @@ static struct key *__request_key_construction(struct key_type *type, | |||
130 | 148 | ||
131 | /* if the key wasn't instantiated, then we want to give an error */ | 149 | /* if the key wasn't instantiated, then we want to give an error */ |
132 | ret = -ENOKEY; | 150 | ret = -ENOKEY; |
133 | if (!(key->flags & KEY_FLAG_INSTANTIATED)) | 151 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) |
134 | goto request_failed; | 152 | goto request_failed; |
135 | 153 | ||
136 | down_write(&key_construction_sem); | 154 | down_write(&key_construction_sem); |
@@ -139,12 +157,13 @@ static struct key *__request_key_construction(struct key_type *type, | |||
139 | 157 | ||
140 | /* also give an error if the key was negatively instantiated */ | 158 | /* also give an error if the key was negatively instantiated */ |
141 | check_not_negative: | 159 | check_not_negative: |
142 | if (key->flags & KEY_FLAG_NEGATIVE) { | 160 | if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { |
143 | key_put(key); | 161 | key_put(key); |
144 | key = ERR_PTR(-ENOKEY); | 162 | key = ERR_PTR(-ENOKEY); |
145 | } | 163 | } |
146 | 164 | ||
147 | out: | 165 | out: |
166 | kleave(" = %p", key); | ||
148 | return key; | 167 | return key; |
149 | 168 | ||
150 | request_failed: | 169 | request_failed: |
@@ -152,24 +171,23 @@ static struct key *__request_key_construction(struct key_type *type, | |||
152 | * - remove from construction queue | 171 | * - remove from construction queue |
153 | * - mark the key as dead | 172 | * - mark the key as dead |
154 | */ | 173 | */ |
155 | negative = 0; | 174 | negated = 0; |
156 | down_write(&key_construction_sem); | 175 | down_write(&key_construction_sem); |
157 | 176 | ||
158 | list_del(&cons.link); | 177 | list_del(&cons.link); |
159 | 178 | ||
160 | write_lock(&key->lock); | ||
161 | key->flags &= ~KEY_FLAG_USER_CONSTRUCT; | ||
162 | |||
163 | /* check it didn't get instantiated between the check and the down */ | 179 | /* check it didn't get instantiated between the check and the down */ |
164 | if (!(key->flags & KEY_FLAG_INSTANTIATED)) { | 180 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { |
165 | key->flags |= KEY_FLAG_INSTANTIATED | KEY_FLAG_NEGATIVE; | 181 | set_bit(KEY_FLAG_NEGATIVE, &key->flags); |
166 | negative = 1; | 182 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); |
183 | negated = 1; | ||
167 | } | 184 | } |
168 | 185 | ||
169 | write_unlock(&key->lock); | 186 | clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); |
187 | |||
170 | up_write(&key_construction_sem); | 188 | up_write(&key_construction_sem); |
171 | 189 | ||
172 | if (!negative) | 190 | if (!negated) |
173 | goto check_not_negative; /* surprisingly, the key got | 191 | goto check_not_negative; /* surprisingly, the key got |
174 | * instantiated */ | 192 | * instantiated */ |
175 | 193 | ||
@@ -178,13 +196,12 @@ static struct key *__request_key_construction(struct key_type *type, | |||
178 | key->expiry = now.tv_sec + key_negative_timeout; | 196 | key->expiry = now.tv_sec + key_negative_timeout; |
179 | 197 | ||
180 | if (current->signal->session_keyring) { | 198 | if (current->signal->session_keyring) { |
181 | unsigned long flags; | ||
182 | struct key *keyring; | 199 | struct key *keyring; |
183 | 200 | ||
184 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 201 | rcu_read_lock(); |
185 | keyring = current->signal->session_keyring; | 202 | keyring = rcu_dereference(current->signal->session_keyring); |
186 | atomic_inc(&keyring->usage); | 203 | atomic_inc(&keyring->usage); |
187 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 204 | rcu_read_unlock(); |
188 | 205 | ||
189 | key_link(keyring, key); | 206 | key_link(keyring, key); |
190 | key_put(keyring); | 207 | key_put(keyring); |
@@ -220,6 +237,9 @@ static struct key *request_key_construction(struct key_type *type, | |||
220 | 237 | ||
221 | DECLARE_WAITQUEUE(myself, current); | 238 | DECLARE_WAITQUEUE(myself, current); |
222 | 239 | ||
240 | kenter("%s,%s,{%d},%s", | ||
241 | type->name, description, user->uid, callout_info); | ||
242 | |||
223 | /* see if there's such a key under construction already */ | 243 | /* see if there's such a key under construction already */ |
224 | down_write(&key_construction_sem); | 244 | down_write(&key_construction_sem); |
225 | 245 | ||
@@ -236,6 +256,7 @@ static struct key *request_key_construction(struct key_type *type, | |||
236 | /* see about getting userspace to construct the key */ | 256 | /* see about getting userspace to construct the key */ |
237 | key = __request_key_construction(type, description, callout_info); | 257 | key = __request_key_construction(type, description, callout_info); |
238 | error: | 258 | error: |
259 | kleave(" = %p", key); | ||
239 | return key; | 260 | return key; |
240 | 261 | ||
241 | /* someone else has the same key under construction | 262 | /* someone else has the same key under construction |
@@ -249,8 +270,10 @@ static struct key *request_key_construction(struct key_type *type, | |||
249 | add_wait_queue(&request_key_conswq, &myself); | 270 | add_wait_queue(&request_key_conswq, &myself); |
250 | 271 | ||
251 | for (;;) { | 272 | for (;;) { |
252 | set_current_state(TASK_UNINTERRUPTIBLE); | 273 | set_current_state(TASK_INTERRUPTIBLE); |
253 | if (!(ckey->flags & KEY_FLAG_USER_CONSTRUCT)) | 274 | if (!test_bit(KEY_FLAG_USER_CONSTRUCT, &ckey->flags)) |
275 | break; | ||
276 | if (signal_pending(current)) | ||
254 | break; | 277 | break; |
255 | schedule(); | 278 | schedule(); |
256 | } | 279 | } |
@@ -271,21 +294,83 @@ static struct key *request_key_construction(struct key_type *type, | |||
271 | 294 | ||
272 | /*****************************************************************************/ | 295 | /*****************************************************************************/ |
273 | /* | 296 | /* |
297 | * link a freshly minted key to an appropriate destination keyring | ||
298 | */ | ||
299 | static 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 | /* | ||
274 | * request a key | 355 | * request a key |
275 | * - search the process's keyrings | 356 | * - search the process's keyrings |
276 | * - check the list of keys being created or updated | 357 | * - check the list of keys being created or updated |
277 | * - 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 |
278 | * passed) | 359 | * - cache the key in an appropriate keyring |
279 | */ | 360 | */ |
280 | struct key *request_key(struct key_type *type, | 361 | struct key *request_key_and_link(struct key_type *type, |
281 | const char *description, | 362 | const char *description, |
282 | const char *callout_info) | 363 | const char *callout_info, |
364 | struct key *dest_keyring) | ||
283 | { | 365 | { |
284 | struct key_user *user; | 366 | struct key_user *user; |
285 | struct key *key; | 367 | struct key *key; |
286 | 368 | ||
369 | kenter("%s,%s,%s,%p", | ||
370 | type->name, description, callout_info, dest_keyring); | ||
371 | |||
287 | /* search all the process keyrings for a key */ | 372 | /* search all the process keyrings for a key */ |
288 | key = search_process_keyrings_aux(type, description, type->match); | 373 | key = search_process_keyrings(type, description, type->match, current); |
289 | 374 | ||
290 | if (PTR_ERR(key) == -EAGAIN) { | 375 | if (PTR_ERR(key) == -EAGAIN) { |
291 | /* the search failed, but the keyrings were searchable, so we | 376 | /* the search failed, but the keyrings were searchable, so we |
@@ -296,12 +381,13 @@ struct key *request_key(struct key_type *type, | |||
296 | 381 | ||
297 | /* - get hold of the user's construction queue */ | 382 | /* - get hold of the user's construction queue */ |
298 | user = key_user_lookup(current->fsuid); | 383 | user = key_user_lookup(current->fsuid); |
299 | if (!user) { | 384 | if (!user) |
300 | key = ERR_PTR(-ENOMEM); | 385 | goto nomem; |
301 | goto error; | 386 | |
302 | } | 387 | do { |
388 | if (signal_pending(current)) | ||
389 | goto interrupted; | ||
303 | 390 | ||
304 | for (;;) { | ||
305 | /* ask userspace (returns NULL if it waited on a key | 391 | /* ask userspace (returns NULL if it waited on a key |
306 | * being constructed) */ | 392 | * being constructed) */ |
307 | key = request_key_construction(type, description, | 393 | key = request_key_construction(type, description, |
@@ -311,18 +397,46 @@ struct key *request_key(struct key_type *type, | |||
311 | 397 | ||
312 | /* someone else made the key we want, so we need to | 398 | /* someone else made the key we want, so we need to |
313 | * search again as it might now be available to us */ | 399 | * search again as it might now be available to us */ |
314 | key = search_process_keyrings_aux(type, description, | 400 | key = search_process_keyrings(type, description, |
315 | type->match); | 401 | type->match, current); |
316 | if (PTR_ERR(key) != -EAGAIN) | 402 | |
317 | break; | 403 | } while (PTR_ERR(key) == -EAGAIN); |
318 | } | ||
319 | 404 | ||
320 | 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); | ||
321 | } | 410 | } |
322 | 411 | ||
323 | error: | 412 | error: |
413 | kleave(" = %p", key); | ||
324 | return key; | 414 | return key; |
325 | 415 | ||
416 | nomem: | ||
417 | key = ERR_PTR(-ENOMEM); | ||
418 | goto error; | ||
419 | |||
420 | interrupted: | ||
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 | */ | ||
434 | struct 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 | |||
326 | } /* end request_key() */ | 440 | } /* end request_key() */ |
327 | 441 | ||
328 | EXPORT_SYMBOL(request_key); | 442 | EXPORT_SYMBOL(request_key); |
@@ -339,7 +453,8 @@ int key_validate(struct key *key) | |||
339 | if (key) { | 453 | if (key) { |
340 | /* check it's still accessible */ | 454 | /* check it's still accessible */ |
341 | ret = -EKEYREVOKED; | 455 | ret = -EKEYREVOKED; |
342 | if (key->flags & (KEY_FLAG_REVOKED | KEY_FLAG_DEAD)) | 456 | if (test_bit(KEY_FLAG_REVOKED, &key->flags) || |
457 | test_bit(KEY_FLAG_DEAD, &key->flags)) | ||
343 | goto error; | 458 | goto error; |
344 | 459 | ||
345 | /* check it hasn't expired */ | 460 | /* check it hasn't expired */ |