blob: 90db5c76cf6e5bdad2778f6a18e6a772dd281c51 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* keyctl.c: userspace keyctl operations
2 *
David Howells3e301482005-06-23 22:00:56 -07003 * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/sched.h>
15#include <linux/slab.h>
16#include <linux/syscalls.h>
17#include <linux/keyctl.h>
18#include <linux/fs.h>
Randy.Dunlapc59ede72006-01-11 12:17:46 -080019#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <linux/err.h>
21#include <asm/uaccess.h>
22#include "internal.h"
23
24/*****************************************************************************/
25/*
26 * extract the description of a new key from userspace and either add it as a
27 * new key to the specified keyring or update a matching key in that keyring
28 * - the keyring must be writable
29 * - returns the new key's serial number
30 * - implements add_key()
31 */
32asmlinkage long sys_add_key(const char __user *_type,
33 const char __user *_description,
34 const void __user *_payload,
35 size_t plen,
36 key_serial_t ringid)
37{
David Howells664cceb2005-09-28 17:03:15 +010038 key_ref_t keyring_ref, key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -070039 char type[32], *description;
40 void *payload;
41 long dlen, ret;
42
43 ret = -EINVAL;
44 if (plen > 32767)
45 goto error;
46
47 /* draw all the data into kernel space */
48 ret = strncpy_from_user(type, _type, sizeof(type) - 1);
49 if (ret < 0)
50 goto error;
51 type[31] = '\0';
52
David Howells3e301482005-06-23 22:00:56 -070053 ret = -EPERM;
54 if (type[0] == '.')
55 goto error;
56
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 ret = -EFAULT;
58 dlen = strnlen_user(_description, PAGE_SIZE - 1);
59 if (dlen <= 0)
60 goto error;
61
62 ret = -EINVAL;
63 if (dlen > PAGE_SIZE - 1)
64 goto error;
65
66 ret = -ENOMEM;
67 description = kmalloc(dlen + 1, GFP_KERNEL);
68 if (!description)
69 goto error;
70
71 ret = -EFAULT;
72 if (copy_from_user(description, _description, dlen + 1) != 0)
73 goto error2;
74
75 /* pull the payload in if one was supplied */
76 payload = NULL;
77
78 if (_payload) {
79 ret = -ENOMEM;
80 payload = kmalloc(plen, GFP_KERNEL);
81 if (!payload)
82 goto error2;
83
84 ret = -EFAULT;
85 if (copy_from_user(payload, _payload, plen) != 0)
86 goto error3;
87 }
88
89 /* find the target keyring (which must be writable) */
David Howells664cceb2005-09-28 17:03:15 +010090 keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
91 if (IS_ERR(keyring_ref)) {
92 ret = PTR_ERR(keyring_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 goto error3;
94 }
95
96 /* create or update the requested key and add it to the target
97 * keyring */
David Howells664cceb2005-09-28 17:03:15 +010098 key_ref = key_create_or_update(keyring_ref, type, description,
99 payload, plen, 0);
100 if (!IS_ERR(key_ref)) {
101 ret = key_ref_to_ptr(key_ref)->serial;
102 key_ref_put(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 }
104 else {
David Howells664cceb2005-09-28 17:03:15 +0100105 ret = PTR_ERR(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 }
107
David Howells664cceb2005-09-28 17:03:15 +0100108 key_ref_put(keyring_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 error3:
110 kfree(payload);
111 error2:
112 kfree(description);
113 error:
114 return ret;
115
116} /* end sys_add_key() */
117
118/*****************************************************************************/
119/*
120 * search the process keyrings for a matching key
121 * - nested keyrings may also be searched if they have Search permission
122 * - if a key is found, it will be attached to the destination keyring if
123 * there's one specified
124 * - /sbin/request-key will be invoked if _callout_info is non-NULL
125 * - the _callout_info string will be passed to /sbin/request-key
126 * - if the _callout_info string is empty, it will be rendered as "-"
127 * - implements request_key()
128 */
129asmlinkage long sys_request_key(const char __user *_type,
130 const char __user *_description,
131 const char __user *_callout_info,
132 key_serial_t destringid)
133{
134 struct key_type *ktype;
David Howells664cceb2005-09-28 17:03:15 +0100135 struct key *key;
136 key_ref_t dest_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 char type[32], *description, *callout_info;
138 long dlen, ret;
139
140 /* pull the type into kernel space */
141 ret = strncpy_from_user(type, _type, sizeof(type) - 1);
142 if (ret < 0)
143 goto error;
144 type[31] = '\0';
145
David Howells1260f802005-08-04 11:50:01 +0100146 ret = -EPERM;
147 if (type[0] == '.')
148 goto error;
149
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 /* pull the description into kernel space */
151 ret = -EFAULT;
152 dlen = strnlen_user(_description, PAGE_SIZE - 1);
153 if (dlen <= 0)
154 goto error;
155
156 ret = -EINVAL;
157 if (dlen > PAGE_SIZE - 1)
158 goto error;
159
160 ret = -ENOMEM;
161 description = kmalloc(dlen + 1, GFP_KERNEL);
162 if (!description)
163 goto error;
164
165 ret = -EFAULT;
166 if (copy_from_user(description, _description, dlen + 1) != 0)
167 goto error2;
168
169 /* pull the callout info into kernel space */
170 callout_info = NULL;
171 if (_callout_info) {
172 ret = -EFAULT;
173 dlen = strnlen_user(_callout_info, PAGE_SIZE - 1);
174 if (dlen <= 0)
175 goto error2;
176
177 ret = -EINVAL;
178 if (dlen > PAGE_SIZE - 1)
179 goto error2;
180
181 ret = -ENOMEM;
182 callout_info = kmalloc(dlen + 1, GFP_KERNEL);
183 if (!callout_info)
184 goto error2;
185
186 ret = -EFAULT;
187 if (copy_from_user(callout_info, _callout_info, dlen + 1) != 0)
188 goto error3;
189 }
190
191 /* get the destination keyring if specified */
David Howells664cceb2005-09-28 17:03:15 +0100192 dest_ref = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 if (destringid) {
David Howells664cceb2005-09-28 17:03:15 +0100194 dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
195 if (IS_ERR(dest_ref)) {
196 ret = PTR_ERR(dest_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 goto error3;
198 }
199 }
200
201 /* find the key type */
202 ktype = key_type_lookup(type);
203 if (IS_ERR(ktype)) {
204 ret = PTR_ERR(ktype);
205 goto error4;
206 }
207
208 /* do the search */
David Howells664cceb2005-09-28 17:03:15 +0100209 key = request_key_and_link(ktype, description, callout_info,
210 key_ref_to_ptr(dest_ref));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 if (IS_ERR(key)) {
212 ret = PTR_ERR(key);
213 goto error5;
214 }
215
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 ret = key->serial;
217
David Howells3e301482005-06-23 22:00:56 -0700218 key_put(key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 error5:
220 key_type_put(ktype);
221 error4:
David Howells664cceb2005-09-28 17:03:15 +0100222 key_ref_put(dest_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 error3:
224 kfree(callout_info);
225 error2:
226 kfree(description);
227 error:
228 return ret;
229
230} /* end sys_request_key() */
231
232/*****************************************************************************/
233/*
234 * get the ID of the specified process keyring
235 * - the keyring must have search permission to be found
236 * - implements keyctl(KEYCTL_GET_KEYRING_ID)
237 */
238long keyctl_get_keyring_ID(key_serial_t id, int create)
239{
David Howells664cceb2005-09-28 17:03:15 +0100240 key_ref_t key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 long ret;
242
David Howells664cceb2005-09-28 17:03:15 +0100243 key_ref = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
244 if (IS_ERR(key_ref)) {
245 ret = PTR_ERR(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 goto error;
247 }
248
David Howells664cceb2005-09-28 17:03:15 +0100249 ret = key_ref_to_ptr(key_ref)->serial;
250 key_ref_put(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 error:
252 return ret;
253
254} /* end keyctl_get_keyring_ID() */
255
256/*****************************************************************************/
257/*
258 * join the session keyring
259 * - implements keyctl(KEYCTL_JOIN_SESSION_KEYRING)
260 */
261long keyctl_join_session_keyring(const char __user *_name)
262{
263 char *name;
264 long nlen, ret;
265
266 /* fetch the name from userspace */
267 name = NULL;
268 if (_name) {
269 ret = -EFAULT;
270 nlen = strnlen_user(_name, PAGE_SIZE - 1);
271 if (nlen <= 0)
272 goto error;
273
274 ret = -EINVAL;
275 if (nlen > PAGE_SIZE - 1)
276 goto error;
277
278 ret = -ENOMEM;
279 name = kmalloc(nlen + 1, GFP_KERNEL);
280 if (!name)
281 goto error;
282
283 ret = -EFAULT;
284 if (copy_from_user(name, _name, nlen + 1) != 0)
285 goto error2;
286 }
287
288 /* join the session */
289 ret = join_session_keyring(name);
290
291 error2:
292 kfree(name);
293 error:
294 return ret;
295
296} /* end keyctl_join_session_keyring() */
297
298/*****************************************************************************/
299/*
300 * update a key's data payload
301 * - the key must be writable
302 * - implements keyctl(KEYCTL_UPDATE)
303 */
304long keyctl_update_key(key_serial_t id,
305 const void __user *_payload,
306 size_t plen)
307{
David Howells664cceb2005-09-28 17:03:15 +0100308 key_ref_t key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 void *payload;
310 long ret;
311
312 ret = -EINVAL;
313 if (plen > PAGE_SIZE)
314 goto error;
315
316 /* pull the payload in if one was supplied */
317 payload = NULL;
318 if (_payload) {
319 ret = -ENOMEM;
320 payload = kmalloc(plen, GFP_KERNEL);
321 if (!payload)
322 goto error;
323
324 ret = -EFAULT;
325 if (copy_from_user(payload, _payload, plen) != 0)
326 goto error2;
327 }
328
329 /* find the target key (which must be writable) */
David Howells664cceb2005-09-28 17:03:15 +0100330 key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
331 if (IS_ERR(key_ref)) {
332 ret = PTR_ERR(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 goto error2;
334 }
335
336 /* update the key */
David Howells664cceb2005-09-28 17:03:15 +0100337 ret = key_update(key_ref, payload, plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
David Howells664cceb2005-09-28 17:03:15 +0100339 key_ref_put(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 error2:
341 kfree(payload);
342 error:
343 return ret;
344
345} /* end keyctl_update_key() */
346
347/*****************************************************************************/
348/*
349 * revoke a key
350 * - the key must be writable
351 * - implements keyctl(KEYCTL_REVOKE)
352 */
353long keyctl_revoke_key(key_serial_t id)
354{
David Howells664cceb2005-09-28 17:03:15 +0100355 key_ref_t key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 long ret;
357
David Howells664cceb2005-09-28 17:03:15 +0100358 key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
359 if (IS_ERR(key_ref)) {
360 ret = PTR_ERR(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 goto error;
362 }
363
David Howells664cceb2005-09-28 17:03:15 +0100364 key_revoke(key_ref_to_ptr(key_ref));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 ret = 0;
366
David Howells664cceb2005-09-28 17:03:15 +0100367 key_ref_put(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 error:
David Howells1260f802005-08-04 11:50:01 +0100369 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371} /* end keyctl_revoke_key() */
372
373/*****************************************************************************/
374/*
375 * clear the specified process keyring
376 * - the keyring must be writable
377 * - implements keyctl(KEYCTL_CLEAR)
378 */
379long keyctl_keyring_clear(key_serial_t ringid)
380{
David Howells664cceb2005-09-28 17:03:15 +0100381 key_ref_t keyring_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 long ret;
383
David Howells664cceb2005-09-28 17:03:15 +0100384 keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
385 if (IS_ERR(keyring_ref)) {
386 ret = PTR_ERR(keyring_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 goto error;
388 }
389
David Howells664cceb2005-09-28 17:03:15 +0100390 ret = keyring_clear(key_ref_to_ptr(keyring_ref));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
David Howells664cceb2005-09-28 17:03:15 +0100392 key_ref_put(keyring_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 error:
394 return ret;
395
396} /* end keyctl_keyring_clear() */
397
398/*****************************************************************************/
399/*
400 * link a key into a keyring
401 * - the keyring must be writable
402 * - the key must be linkable
403 * - implements keyctl(KEYCTL_LINK)
404 */
405long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
406{
David Howells664cceb2005-09-28 17:03:15 +0100407 key_ref_t keyring_ref, key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 long ret;
409
David Howells664cceb2005-09-28 17:03:15 +0100410 keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
411 if (IS_ERR(keyring_ref)) {
412 ret = PTR_ERR(keyring_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 goto error;
414 }
415
David Howells664cceb2005-09-28 17:03:15 +0100416 key_ref = lookup_user_key(NULL, id, 1, 0, KEY_LINK);
417 if (IS_ERR(key_ref)) {
418 ret = PTR_ERR(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 goto error2;
420 }
421
David Howells664cceb2005-09-28 17:03:15 +0100422 ret = key_link(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
David Howells664cceb2005-09-28 17:03:15 +0100424 key_ref_put(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 error2:
David Howells664cceb2005-09-28 17:03:15 +0100426 key_ref_put(keyring_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 error:
428 return ret;
429
430} /* end keyctl_keyring_link() */
431
432/*****************************************************************************/
433/*
434 * unlink the first attachment of a key from a keyring
435 * - the keyring must be writable
436 * - we don't need any permissions on the key
437 * - implements keyctl(KEYCTL_UNLINK)
438 */
439long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
440{
David Howells664cceb2005-09-28 17:03:15 +0100441 key_ref_t keyring_ref, key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 long ret;
443
David Howells664cceb2005-09-28 17:03:15 +0100444 keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
445 if (IS_ERR(keyring_ref)) {
446 ret = PTR_ERR(keyring_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 goto error;
448 }
449
David Howells664cceb2005-09-28 17:03:15 +0100450 key_ref = lookup_user_key(NULL, id, 0, 0, 0);
451 if (IS_ERR(key_ref)) {
452 ret = PTR_ERR(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 goto error2;
454 }
455
David Howells664cceb2005-09-28 17:03:15 +0100456 ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
David Howells664cceb2005-09-28 17:03:15 +0100458 key_ref_put(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 error2:
David Howells664cceb2005-09-28 17:03:15 +0100460 key_ref_put(keyring_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 error:
462 return ret;
463
464} /* end keyctl_keyring_unlink() */
465
466/*****************************************************************************/
467/*
468 * describe a user key
469 * - the key must have view permission
470 * - if there's a buffer, we place up to buflen bytes of data into it
471 * - unless there's an error, we return the amount of description available,
472 * irrespective of how much we may have copied
473 * - the description is formatted thus:
474 * type;uid;gid;perm;description<NUL>
475 * - implements keyctl(KEYCTL_DESCRIBE)
476 */
477long keyctl_describe_key(key_serial_t keyid,
478 char __user *buffer,
479 size_t buflen)
480{
David Howells3e301482005-06-23 22:00:56 -0700481 struct key *key, *instkey;
David Howells664cceb2005-09-28 17:03:15 +0100482 key_ref_t key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 char *tmpbuf;
484 long ret;
485
David Howells664cceb2005-09-28 17:03:15 +0100486 key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
487 if (IS_ERR(key_ref)) {
David Howells3e301482005-06-23 22:00:56 -0700488 /* viewing a key under construction is permitted if we have the
489 * authorisation token handy */
David Howells664cceb2005-09-28 17:03:15 +0100490 if (PTR_ERR(key_ref) == -EACCES) {
David Howells3e301482005-06-23 22:00:56 -0700491 instkey = key_get_instantiation_authkey(keyid);
492 if (!IS_ERR(instkey)) {
493 key_put(instkey);
David Howells664cceb2005-09-28 17:03:15 +0100494 key_ref = lookup_user_key(NULL, keyid,
495 0, 1, 0);
496 if (!IS_ERR(key_ref))
David Howells3e301482005-06-23 22:00:56 -0700497 goto okay;
498 }
499 }
500
David Howells664cceb2005-09-28 17:03:15 +0100501 ret = PTR_ERR(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 goto error;
503 }
504
David Howells3e301482005-06-23 22:00:56 -0700505okay:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 /* calculate how much description we're going to return */
507 ret = -ENOMEM;
508 tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
509 if (!tmpbuf)
510 goto error2;
511
David Howells664cceb2005-09-28 17:03:15 +0100512 key = key_ref_to_ptr(key_ref);
513
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 ret = snprintf(tmpbuf, PAGE_SIZE - 1,
David Howells664cceb2005-09-28 17:03:15 +0100515 "%s;%d;%d;%08x;%s",
516 key_ref_to_ptr(key_ref)->type->name,
517 key_ref_to_ptr(key_ref)->uid,
518 key_ref_to_ptr(key_ref)->gid,
519 key_ref_to_ptr(key_ref)->perm,
520 key_ref_to_ptr(key_ref)->description ?
521 key_ref_to_ptr(key_ref)->description : ""
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 );
523
524 /* include a NUL char at the end of the data */
525 if (ret > PAGE_SIZE - 1)
526 ret = PAGE_SIZE - 1;
527 tmpbuf[ret] = 0;
528 ret++;
529
530 /* consider returning the data */
531 if (buffer && buflen > 0) {
532 if (buflen > ret)
533 buflen = ret;
534
535 if (copy_to_user(buffer, tmpbuf, buflen) != 0)
536 ret = -EFAULT;
537 }
538
539 kfree(tmpbuf);
540 error2:
David Howells664cceb2005-09-28 17:03:15 +0100541 key_ref_put(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 error:
543 return ret;
544
545} /* end keyctl_describe_key() */
546
547/*****************************************************************************/
548/*
549 * search the specified keyring for a matching key
550 * - the start keyring must be searchable
551 * - nested keyrings may also be searched if they are searchable
552 * - only keys with search permission may be found
553 * - if a key is found, it will be attached to the destination keyring if
554 * there's one specified
555 * - implements keyctl(KEYCTL_SEARCH)
556 */
557long keyctl_keyring_search(key_serial_t ringid,
558 const char __user *_type,
559 const char __user *_description,
560 key_serial_t destringid)
561{
562 struct key_type *ktype;
David Howells664cceb2005-09-28 17:03:15 +0100563 key_ref_t keyring_ref, key_ref, dest_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 char type[32], *description;
565 long dlen, ret;
566
567 /* pull the type and description into kernel space */
568 ret = strncpy_from_user(type, _type, sizeof(type) - 1);
569 if (ret < 0)
570 goto error;
571 type[31] = '\0';
572
573 ret = -EFAULT;
574 dlen = strnlen_user(_description, PAGE_SIZE - 1);
575 if (dlen <= 0)
576 goto error;
577
578 ret = -EINVAL;
579 if (dlen > PAGE_SIZE - 1)
580 goto error;
581
582 ret = -ENOMEM;
583 description = kmalloc(dlen + 1, GFP_KERNEL);
584 if (!description)
585 goto error;
586
587 ret = -EFAULT;
588 if (copy_from_user(description, _description, dlen + 1) != 0)
589 goto error2;
590
591 /* get the keyring at which to begin the search */
David Howells664cceb2005-09-28 17:03:15 +0100592 keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
593 if (IS_ERR(keyring_ref)) {
594 ret = PTR_ERR(keyring_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 goto error2;
596 }
597
598 /* get the destination keyring if specified */
David Howells664cceb2005-09-28 17:03:15 +0100599 dest_ref = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 if (destringid) {
David Howells664cceb2005-09-28 17:03:15 +0100601 dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
602 if (IS_ERR(dest_ref)) {
603 ret = PTR_ERR(dest_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 goto error3;
605 }
606 }
607
608 /* find the key type */
609 ktype = key_type_lookup(type);
610 if (IS_ERR(ktype)) {
611 ret = PTR_ERR(ktype);
612 goto error4;
613 }
614
615 /* do the search */
David Howells664cceb2005-09-28 17:03:15 +0100616 key_ref = keyring_search(keyring_ref, ktype, description);
617 if (IS_ERR(key_ref)) {
618 ret = PTR_ERR(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
620 /* treat lack or presence of a negative key the same */
621 if (ret == -EAGAIN)
622 ret = -ENOKEY;
623 goto error5;
624 }
625
626 /* link the resulting key to the destination keyring if we can */
David Howells664cceb2005-09-28 17:03:15 +0100627 if (dest_ref) {
David Howells29db9192005-10-30 15:02:44 -0800628 ret = key_permission(key_ref, KEY_LINK);
629 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 goto error6;
631
David Howells664cceb2005-09-28 17:03:15 +0100632 ret = key_link(key_ref_to_ptr(dest_ref), key_ref_to_ptr(key_ref));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 if (ret < 0)
634 goto error6;
635 }
636
David Howells664cceb2005-09-28 17:03:15 +0100637 ret = key_ref_to_ptr(key_ref)->serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
639 error6:
David Howells664cceb2005-09-28 17:03:15 +0100640 key_ref_put(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 error5:
642 key_type_put(ktype);
643 error4:
David Howells664cceb2005-09-28 17:03:15 +0100644 key_ref_put(dest_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 error3:
David Howells664cceb2005-09-28 17:03:15 +0100646 key_ref_put(keyring_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 error2:
648 kfree(description);
649 error:
650 return ret;
651
652} /* end keyctl_keyring_search() */
653
654/*****************************************************************************/
655/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 * read a user key's payload
657 * - the keyring must be readable or the key must be searchable from the
658 * process's keyrings
659 * - if there's a buffer, we place up to buflen bytes of data into it
660 * - unless there's an error, we return the amount of data in the key,
661 * irrespective of how much we may have copied
662 * - implements keyctl(KEYCTL_READ)
663 */
664long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
665{
David Howells664cceb2005-09-28 17:03:15 +0100666 struct key *key;
667 key_ref_t key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 long ret;
669
670 /* find the key first */
David Howells664cceb2005-09-28 17:03:15 +0100671 key_ref = lookup_user_key(NULL, keyid, 0, 0, 0);
672 if (IS_ERR(key_ref)) {
673 ret = -ENOKEY;
674 goto error;
675 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
David Howells664cceb2005-09-28 17:03:15 +0100677 key = key_ref_to_ptr(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
David Howells664cceb2005-09-28 17:03:15 +0100679 /* see if we can read it directly */
David Howells29db9192005-10-30 15:02:44 -0800680 ret = key_permission(key_ref, KEY_READ);
681 if (ret == 0)
David Howells664cceb2005-09-28 17:03:15 +0100682 goto can_read_key;
David Howells29db9192005-10-30 15:02:44 -0800683 if (ret != -EACCES)
684 goto error;
David Howells664cceb2005-09-28 17:03:15 +0100685
686 /* we can't; see if it's searchable from this process's keyrings
687 * - we automatically take account of the fact that it may be
688 * dangling off an instantiation key
689 */
690 if (!is_key_possessed(key_ref)) {
691 ret = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 goto error2;
693 }
694
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 /* the key is probably readable - now try to read it */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 can_read_key:
697 ret = key_validate(key);
698 if (ret == 0) {
699 ret = -EOPNOTSUPP;
700 if (key->type->read) {
701 /* read the data with the semaphore held (since we
702 * might sleep) */
703 down_read(&key->sem);
704 ret = key->type->read(key, buffer, buflen);
705 up_read(&key->sem);
706 }
707 }
708
709 error2:
710 key_put(key);
711 error:
712 return ret;
713
714} /* end keyctl_read_key() */
715
716/*****************************************************************************/
717/*
718 * change the ownership of a key
719 * - the keyring owned by the changer
720 * - if the uid or gid is -1, then that parameter is not changed
721 * - implements keyctl(KEYCTL_CHOWN)
722 */
723long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
724{
725 struct key *key;
David Howells664cceb2005-09-28 17:03:15 +0100726 key_ref_t key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 long ret;
728
729 ret = 0;
730 if (uid == (uid_t) -1 && gid == (gid_t) -1)
731 goto error;
732
David Howells29db9192005-10-30 15:02:44 -0800733 key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR);
David Howells664cceb2005-09-28 17:03:15 +0100734 if (IS_ERR(key_ref)) {
735 ret = PTR_ERR(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 goto error;
737 }
738
David Howells664cceb2005-09-28 17:03:15 +0100739 key = key_ref_to_ptr(key_ref);
740
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 /* make the changes with the locks held to prevent chown/chown races */
742 ret = -EACCES;
743 down_write(&key->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
745 if (!capable(CAP_SYS_ADMIN)) {
746 /* only the sysadmin can chown a key to some other UID */
747 if (uid != (uid_t) -1 && key->uid != uid)
748 goto no_access;
749
750 /* only the sysadmin can set the key's GID to a group other
751 * than one of those that the current process subscribes to */
752 if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid))
753 goto no_access;
754 }
755
756 /* change the UID (have to update the quotas) */
757 if (uid != (uid_t) -1 && uid != key->uid) {
758 /* don't support UID changing yet */
759 ret = -EOPNOTSUPP;
760 goto no_access;
761 }
762
763 /* change the GID */
764 if (gid != (gid_t) -1)
765 key->gid = gid;
766
767 ret = 0;
768
769 no_access:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 up_write(&key->sem);
771 key_put(key);
772 error:
773 return ret;
774
775} /* end keyctl_chown_key() */
776
777/*****************************************************************************/
778/*
779 * change the permission mask on a key
780 * - the keyring owned by the changer
781 * - implements keyctl(KEYCTL_SETPERM)
782 */
783long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
784{
785 struct key *key;
David Howells664cceb2005-09-28 17:03:15 +0100786 key_ref_t key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 long ret;
788
789 ret = -EINVAL;
David Howells664cceb2005-09-28 17:03:15 +0100790 if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 goto error;
792
David Howells29db9192005-10-30 15:02:44 -0800793 key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR);
David Howells664cceb2005-09-28 17:03:15 +0100794 if (IS_ERR(key_ref)) {
795 ret = PTR_ERR(key_ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 goto error;
797 }
798
David Howells664cceb2005-09-28 17:03:15 +0100799 key = key_ref_to_ptr(key_ref);
800
David Howells76d8aea2005-06-23 22:00:49 -0700801 /* make the changes with the locks held to prevent chown/chmod races */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 ret = -EACCES;
803 down_write(&key->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
David Howells76d8aea2005-06-23 22:00:49 -0700805 /* if we're not the sysadmin, we can only change a key that we own */
806 if (capable(CAP_SYS_ADMIN) || key->uid == current->fsuid) {
807 key->perm = perm;
808 ret = 0;
809 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 up_write(&key->sem);
812 key_put(key);
David Howells76d8aea2005-06-23 22:00:49 -0700813error:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 return ret;
815
816} /* end keyctl_setperm_key() */
817
818/*****************************************************************************/
819/*
820 * instantiate the key with the specified payload, and, if one is given, link
821 * the key into the keyring
822 */
823long keyctl_instantiate_key(key_serial_t id,
824 const void __user *_payload,
825 size_t plen,
826 key_serial_t ringid)
827{
David Howells3e301482005-06-23 22:00:56 -0700828 struct request_key_auth *rka;
David Howells664cceb2005-09-28 17:03:15 +0100829 struct key *instkey;
830 key_ref_t keyring_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 void *payload;
832 long ret;
833
834 ret = -EINVAL;
835 if (plen > 32767)
836 goto error;
837
David Howellsb5f545c2006-01-08 01:02:47 -0800838 /* the appropriate instantiation authorisation key must have been
839 * assumed before calling this */
840 ret = -EPERM;
841 instkey = current->request_key_auth;
842 if (!instkey)
843 goto error;
844
845 rka = instkey->payload.data;
846 if (rka->target_key->serial != id)
847 goto error;
848
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 /* pull the payload in if one was supplied */
850 payload = NULL;
851
852 if (_payload) {
853 ret = -ENOMEM;
854 payload = kmalloc(plen, GFP_KERNEL);
855 if (!payload)
856 goto error;
857
858 ret = -EFAULT;
859 if (copy_from_user(payload, _payload, plen) != 0)
860 goto error2;
861 }
862
David Howells3e301482005-06-23 22:00:56 -0700863 /* find the destination keyring amongst those belonging to the
864 * requesting task */
David Howells664cceb2005-09-28 17:03:15 +0100865 keyring_ref = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 if (ringid) {
David Howells664cceb2005-09-28 17:03:15 +0100867 keyring_ref = lookup_user_key(rka->context, ringid, 1, 0,
868 KEY_WRITE);
869 if (IS_ERR(keyring_ref)) {
870 ret = PTR_ERR(keyring_ref);
David Howellsb5f545c2006-01-08 01:02:47 -0800871 goto error2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 }
873 }
874
875 /* instantiate the key and link it into a keyring */
David Howells3e301482005-06-23 22:00:56 -0700876 ret = key_instantiate_and_link(rka->target_key, payload, plen,
David Howells664cceb2005-09-28 17:03:15 +0100877 key_ref_to_ptr(keyring_ref), instkey);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
David Howells664cceb2005-09-28 17:03:15 +0100879 key_ref_put(keyring_ref);
David Howellsb5f545c2006-01-08 01:02:47 -0800880
881 /* discard the assumed authority if it's just been disabled by
882 * instantiation of the key */
883 if (ret == 0) {
884 key_put(current->request_key_auth);
885 current->request_key_auth = NULL;
886 }
887
888error2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 kfree(payload);
David Howellsb5f545c2006-01-08 01:02:47 -0800890error:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 return ret;
892
893} /* end keyctl_instantiate_key() */
894
895/*****************************************************************************/
896/*
897 * negatively instantiate the key with the given timeout (in seconds), and, if
898 * one is given, link the key into the keyring
899 */
900long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
901{
David Howells3e301482005-06-23 22:00:56 -0700902 struct request_key_auth *rka;
David Howells664cceb2005-09-28 17:03:15 +0100903 struct key *instkey;
904 key_ref_t keyring_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 long ret;
906
David Howellsb5f545c2006-01-08 01:02:47 -0800907 /* the appropriate instantiation authorisation key must have been
908 * assumed before calling this */
909 ret = -EPERM;
910 instkey = current->request_key_auth;
911 if (!instkey)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
David Howells3e301482005-06-23 22:00:56 -0700914 rka = instkey->payload.data;
David Howellsb5f545c2006-01-08 01:02:47 -0800915 if (rka->target_key->serial != id)
916 goto error;
David Howells3e301482005-06-23 22:00:56 -0700917
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 /* find the destination keyring if present (which must also be
919 * writable) */
David Howells664cceb2005-09-28 17:03:15 +0100920 keyring_ref = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 if (ringid) {
David Howells664cceb2005-09-28 17:03:15 +0100922 keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
923 if (IS_ERR(keyring_ref)) {
924 ret = PTR_ERR(keyring_ref);
David Howellsb5f545c2006-01-08 01:02:47 -0800925 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 }
927 }
928
929 /* instantiate the key and link it into a keyring */
David Howells664cceb2005-09-28 17:03:15 +0100930 ret = key_negate_and_link(rka->target_key, timeout,
931 key_ref_to_ptr(keyring_ref), instkey);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
David Howells664cceb2005-09-28 17:03:15 +0100933 key_ref_put(keyring_ref);
David Howellsb5f545c2006-01-08 01:02:47 -0800934
935 /* discard the assumed authority if it's just been disabled by
936 * instantiation of the key */
937 if (ret == 0) {
938 key_put(current->request_key_auth);
939 current->request_key_auth = NULL;
940 }
941
942error:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 return ret;
944
945} /* end keyctl_negate_key() */
946
947/*****************************************************************************/
948/*
David Howells3e301482005-06-23 22:00:56 -0700949 * set the default keyring in which request_key() will cache keys
950 * - return the old setting
951 */
952long keyctl_set_reqkey_keyring(int reqkey_defl)
953{
954 int ret;
955
956 switch (reqkey_defl) {
957 case KEY_REQKEY_DEFL_THREAD_KEYRING:
958 ret = install_thread_keyring(current);
959 if (ret < 0)
960 return ret;
961 goto set;
962
963 case KEY_REQKEY_DEFL_PROCESS_KEYRING:
964 ret = install_process_keyring(current);
965 if (ret < 0)
966 return ret;
967
968 case KEY_REQKEY_DEFL_DEFAULT:
969 case KEY_REQKEY_DEFL_SESSION_KEYRING:
970 case KEY_REQKEY_DEFL_USER_KEYRING:
971 case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
972 set:
973 current->jit_keyring = reqkey_defl;
974
975 case KEY_REQKEY_DEFL_NO_CHANGE:
976 return current->jit_keyring;
977
978 case KEY_REQKEY_DEFL_GROUP_KEYRING:
979 default:
980 return -EINVAL;
981 }
982
983} /* end keyctl_set_reqkey_keyring() */
984
985/*****************************************************************************/
986/*
David Howells017679c2006-01-08 01:02:43 -0800987 * set or clear the timeout for a key
988 */
989long keyctl_set_timeout(key_serial_t id, unsigned timeout)
990{
991 struct timespec now;
992 struct key *key;
993 key_ref_t key_ref;
994 time_t expiry;
995 long ret;
996
997 key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR);
998 if (IS_ERR(key_ref)) {
999 ret = PTR_ERR(key_ref);
1000 goto error;
1001 }
1002
1003 key = key_ref_to_ptr(key_ref);
1004
1005 /* make the changes with the locks held to prevent races */
1006 down_write(&key->sem);
1007
1008 expiry = 0;
1009 if (timeout > 0) {
1010 now = current_kernel_time();
1011 expiry = now.tv_sec + timeout;
1012 }
1013
1014 key->expiry = expiry;
1015
1016 up_write(&key->sem);
1017 key_put(key);
1018
1019 ret = 0;
1020error:
1021 return ret;
1022
1023} /* end keyctl_set_timeout() */
1024
1025/*****************************************************************************/
1026/*
David Howellsb5f545c2006-01-08 01:02:47 -08001027 * assume the authority to instantiate the specified key
1028 */
1029long keyctl_assume_authority(key_serial_t id)
1030{
1031 struct key *authkey;
1032 long ret;
1033
1034 /* special key IDs aren't permitted */
1035 ret = -EINVAL;
1036 if (id < 0)
1037 goto error;
1038
1039 /* we divest ourselves of authority if given an ID of 0 */
1040 if (id == 0) {
1041 key_put(current->request_key_auth);
1042 current->request_key_auth = NULL;
1043 ret = 0;
1044 goto error;
1045 }
1046
1047 /* attempt to assume the authority temporarily granted to us whilst we
1048 * instantiate the specified key
1049 * - the authorisation key must be in the current task's keyrings
1050 * somewhere
1051 */
1052 authkey = key_get_instantiation_authkey(id);
1053 if (IS_ERR(authkey)) {
1054 ret = PTR_ERR(authkey);
1055 goto error;
1056 }
1057
1058 key_put(current->request_key_auth);
1059 current->request_key_auth = authkey;
1060 ret = authkey->serial;
1061
1062error:
1063 return ret;
1064
1065} /* end keyctl_assume_authority() */
1066
1067/*****************************************************************************/
1068/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 * the key control system call
1070 */
1071asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3,
1072 unsigned long arg4, unsigned long arg5)
1073{
1074 switch (option) {
1075 case KEYCTL_GET_KEYRING_ID:
1076 return keyctl_get_keyring_ID((key_serial_t) arg2,
1077 (int) arg3);
1078
1079 case KEYCTL_JOIN_SESSION_KEYRING:
1080 return keyctl_join_session_keyring((const char __user *) arg2);
1081
1082 case KEYCTL_UPDATE:
1083 return keyctl_update_key((key_serial_t) arg2,
1084 (const void __user *) arg3,
1085 (size_t) arg4);
1086
1087 case KEYCTL_REVOKE:
1088 return keyctl_revoke_key((key_serial_t) arg2);
1089
1090 case KEYCTL_DESCRIBE:
1091 return keyctl_describe_key((key_serial_t) arg2,
1092 (char __user *) arg3,
1093 (unsigned) arg4);
1094
1095 case KEYCTL_CLEAR:
1096 return keyctl_keyring_clear((key_serial_t) arg2);
1097
1098 case KEYCTL_LINK:
1099 return keyctl_keyring_link((key_serial_t) arg2,
1100 (key_serial_t) arg3);
1101
1102 case KEYCTL_UNLINK:
1103 return keyctl_keyring_unlink((key_serial_t) arg2,
1104 (key_serial_t) arg3);
1105
1106 case KEYCTL_SEARCH:
1107 return keyctl_keyring_search((key_serial_t) arg2,
1108 (const char __user *) arg3,
1109 (const char __user *) arg4,
1110 (key_serial_t) arg5);
1111
1112 case KEYCTL_READ:
1113 return keyctl_read_key((key_serial_t) arg2,
1114 (char __user *) arg3,
1115 (size_t) arg4);
1116
1117 case KEYCTL_CHOWN:
1118 return keyctl_chown_key((key_serial_t) arg2,
1119 (uid_t) arg3,
1120 (gid_t) arg4);
1121
1122 case KEYCTL_SETPERM:
1123 return keyctl_setperm_key((key_serial_t) arg2,
1124 (key_perm_t) arg3);
1125
1126 case KEYCTL_INSTANTIATE:
1127 return keyctl_instantiate_key((key_serial_t) arg2,
1128 (const void __user *) arg3,
1129 (size_t) arg4,
1130 (key_serial_t) arg5);
1131
1132 case KEYCTL_NEGATE:
1133 return keyctl_negate_key((key_serial_t) arg2,
1134 (unsigned) arg3,
1135 (key_serial_t) arg4);
1136
David Howells3e301482005-06-23 22:00:56 -07001137 case KEYCTL_SET_REQKEY_KEYRING:
1138 return keyctl_set_reqkey_keyring(arg2);
1139
David Howells017679c2006-01-08 01:02:43 -08001140 case KEYCTL_SET_TIMEOUT:
1141 return keyctl_set_timeout((key_serial_t) arg2,
1142 (unsigned) arg3);
1143
David Howellsb5f545c2006-01-08 01:02:47 -08001144 case KEYCTL_ASSUME_AUTHORITY:
1145 return keyctl_assume_authority((key_serial_t) arg2);
1146
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 default:
1148 return -EOPNOTSUPP;
1149 }
1150
1151} /* end sys_keyctl() */