Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* keyctl.c: userspace keyctl operations |
2 | * | |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | |
4 | * 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> | |
19 | #include <linux/err.h> | |
20 | #include <asm/uaccess.h> | |
21 | #include "internal.h" | |
22 | ||
23 | /*****************************************************************************/ | |
24 | /* | |
25 | * extract the description of a new key from userspace and either add it as a | |
26 | * new key to the specified keyring or update a matching key in that keyring | |
27 | * - the keyring must be writable | |
28 | * - returns the new key's serial number | |
29 | * - implements add_key() | |
30 | */ | |
31 | asmlinkage long sys_add_key(const char __user *_type, | |
32 | const char __user *_description, | |
33 | const void __user *_payload, | |
34 | size_t plen, | |
35 | key_serial_t ringid) | |
36 | { | |
37 | struct key *keyring, *key; | |
38 | char type[32], *description; | |
39 | void *payload; | |
40 | long dlen, ret; | |
41 | ||
42 | ret = -EINVAL; | |
43 | if (plen > 32767) | |
44 | goto error; | |
45 | ||
46 | /* draw all the data into kernel space */ | |
47 | ret = strncpy_from_user(type, _type, sizeof(type) - 1); | |
48 | if (ret < 0) | |
49 | goto error; | |
50 | type[31] = '\0'; | |
51 | ||
52 | ret = -EFAULT; | |
53 | dlen = strnlen_user(_description, PAGE_SIZE - 1); | |
54 | if (dlen <= 0) | |
55 | goto error; | |
56 | ||
57 | ret = -EINVAL; | |
58 | if (dlen > PAGE_SIZE - 1) | |
59 | goto error; | |
60 | ||
61 | ret = -ENOMEM; | |
62 | description = kmalloc(dlen + 1, GFP_KERNEL); | |
63 | if (!description) | |
64 | goto error; | |
65 | ||
66 | ret = -EFAULT; | |
67 | if (copy_from_user(description, _description, dlen + 1) != 0) | |
68 | goto error2; | |
69 | ||
70 | /* pull the payload in if one was supplied */ | |
71 | payload = NULL; | |
72 | ||
73 | if (_payload) { | |
74 | ret = -ENOMEM; | |
75 | payload = kmalloc(plen, GFP_KERNEL); | |
76 | if (!payload) | |
77 | goto error2; | |
78 | ||
79 | ret = -EFAULT; | |
80 | if (copy_from_user(payload, _payload, plen) != 0) | |
81 | goto error3; | |
82 | } | |
83 | ||
84 | /* find the target keyring (which must be writable) */ | |
85 | keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE); | |
86 | if (IS_ERR(keyring)) { | |
87 | ret = PTR_ERR(keyring); | |
88 | goto error3; | |
89 | } | |
90 | ||
91 | /* create or update the requested key and add it to the target | |
92 | * keyring */ | |
93 | key = key_create_or_update(keyring, type, description, | |
94 | payload, plen, 0); | |
95 | if (!IS_ERR(key)) { | |
96 | ret = key->serial; | |
97 | key_put(key); | |
98 | } | |
99 | else { | |
100 | ret = PTR_ERR(key); | |
101 | } | |
102 | ||
103 | key_put(keyring); | |
104 | error3: | |
105 | kfree(payload); | |
106 | error2: | |
107 | kfree(description); | |
108 | error: | |
109 | return ret; | |
110 | ||
111 | } /* end sys_add_key() */ | |
112 | ||
113 | /*****************************************************************************/ | |
114 | /* | |
115 | * search the process keyrings for a matching key | |
116 | * - nested keyrings may also be searched if they have Search permission | |
117 | * - if a key is found, it will be attached to the destination keyring if | |
118 | * there's one specified | |
119 | * - /sbin/request-key will be invoked if _callout_info is non-NULL | |
120 | * - the _callout_info string will be passed to /sbin/request-key | |
121 | * - if the _callout_info string is empty, it will be rendered as "-" | |
122 | * - implements request_key() | |
123 | */ | |
124 | asmlinkage long sys_request_key(const char __user *_type, | |
125 | const char __user *_description, | |
126 | const char __user *_callout_info, | |
127 | key_serial_t destringid) | |
128 | { | |
129 | struct key_type *ktype; | |
130 | struct key *key, *dest; | |
131 | char type[32], *description, *callout_info; | |
132 | long dlen, ret; | |
133 | ||
134 | /* pull the type into kernel space */ | |
135 | ret = strncpy_from_user(type, _type, sizeof(type) - 1); | |
136 | if (ret < 0) | |
137 | goto error; | |
138 | type[31] = '\0'; | |
139 | ||
140 | /* pull the description into kernel space */ | |
141 | ret = -EFAULT; | |
142 | dlen = strnlen_user(_description, PAGE_SIZE - 1); | |
143 | if (dlen <= 0) | |
144 | goto error; | |
145 | ||
146 | ret = -EINVAL; | |
147 | if (dlen > PAGE_SIZE - 1) | |
148 | goto error; | |
149 | ||
150 | ret = -ENOMEM; | |
151 | description = kmalloc(dlen + 1, GFP_KERNEL); | |
152 | if (!description) | |
153 | goto error; | |
154 | ||
155 | ret = -EFAULT; | |
156 | if (copy_from_user(description, _description, dlen + 1) != 0) | |
157 | goto error2; | |
158 | ||
159 | /* pull the callout info into kernel space */ | |
160 | callout_info = NULL; | |
161 | if (_callout_info) { | |
162 | ret = -EFAULT; | |
163 | dlen = strnlen_user(_callout_info, PAGE_SIZE - 1); | |
164 | if (dlen <= 0) | |
165 | goto error2; | |
166 | ||
167 | ret = -EINVAL; | |
168 | if (dlen > PAGE_SIZE - 1) | |
169 | goto error2; | |
170 | ||
171 | ret = -ENOMEM; | |
172 | callout_info = kmalloc(dlen + 1, GFP_KERNEL); | |
173 | if (!callout_info) | |
174 | goto error2; | |
175 | ||
176 | ret = -EFAULT; | |
177 | if (copy_from_user(callout_info, _callout_info, dlen + 1) != 0) | |
178 | goto error3; | |
179 | } | |
180 | ||
181 | /* get the destination keyring if specified */ | |
182 | dest = NULL; | |
183 | if (destringid) { | |
184 | dest = lookup_user_key(destringid, 1, 0, KEY_WRITE); | |
185 | if (IS_ERR(dest)) { | |
186 | ret = PTR_ERR(dest); | |
187 | goto error3; | |
188 | } | |
189 | } | |
190 | ||
191 | /* find the key type */ | |
192 | ktype = key_type_lookup(type); | |
193 | if (IS_ERR(ktype)) { | |
194 | ret = PTR_ERR(ktype); | |
195 | goto error4; | |
196 | } | |
197 | ||
198 | /* do the search */ | |
199 | key = request_key(ktype, description, callout_info); | |
200 | if (IS_ERR(key)) { | |
201 | ret = PTR_ERR(key); | |
202 | goto error5; | |
203 | } | |
204 | ||
205 | /* link the resulting key to the destination keyring */ | |
206 | if (dest) { | |
207 | ret = key_link(dest, key); | |
208 | if (ret < 0) | |
209 | goto error6; | |
210 | } | |
211 | ||
212 | ret = key->serial; | |
213 | ||
214 | error6: | |
215 | key_put(key); | |
216 | error5: | |
217 | key_type_put(ktype); | |
218 | error4: | |
219 | key_put(dest); | |
220 | error3: | |
221 | kfree(callout_info); | |
222 | error2: | |
223 | kfree(description); | |
224 | error: | |
225 | return ret; | |
226 | ||
227 | } /* end sys_request_key() */ | |
228 | ||
229 | /*****************************************************************************/ | |
230 | /* | |
231 | * get the ID of the specified process keyring | |
232 | * - the keyring must have search permission to be found | |
233 | * - implements keyctl(KEYCTL_GET_KEYRING_ID) | |
234 | */ | |
235 | long keyctl_get_keyring_ID(key_serial_t id, int create) | |
236 | { | |
237 | struct key *key; | |
238 | long ret; | |
239 | ||
240 | key = lookup_user_key(id, create, 0, KEY_SEARCH); | |
241 | if (IS_ERR(key)) { | |
242 | ret = PTR_ERR(key); | |
243 | goto error; | |
244 | } | |
245 | ||
246 | ret = key->serial; | |
247 | key_put(key); | |
248 | error: | |
249 | return ret; | |
250 | ||
251 | } /* end keyctl_get_keyring_ID() */ | |
252 | ||
253 | /*****************************************************************************/ | |
254 | /* | |
255 | * join the session keyring | |
256 | * - implements keyctl(KEYCTL_JOIN_SESSION_KEYRING) | |
257 | */ | |
258 | long keyctl_join_session_keyring(const char __user *_name) | |
259 | { | |
260 | char *name; | |
261 | long nlen, ret; | |
262 | ||
263 | /* fetch the name from userspace */ | |
264 | name = NULL; | |
265 | if (_name) { | |
266 | ret = -EFAULT; | |
267 | nlen = strnlen_user(_name, PAGE_SIZE - 1); | |
268 | if (nlen <= 0) | |
269 | goto error; | |
270 | ||
271 | ret = -EINVAL; | |
272 | if (nlen > PAGE_SIZE - 1) | |
273 | goto error; | |
274 | ||
275 | ret = -ENOMEM; | |
276 | name = kmalloc(nlen + 1, GFP_KERNEL); | |
277 | if (!name) | |
278 | goto error; | |
279 | ||
280 | ret = -EFAULT; | |
281 | if (copy_from_user(name, _name, nlen + 1) != 0) | |
282 | goto error2; | |
283 | } | |
284 | ||
285 | /* join the session */ | |
286 | ret = join_session_keyring(name); | |
287 | ||
288 | error2: | |
289 | kfree(name); | |
290 | error: | |
291 | return ret; | |
292 | ||
293 | } /* end keyctl_join_session_keyring() */ | |
294 | ||
295 | /*****************************************************************************/ | |
296 | /* | |
297 | * update a key's data payload | |
298 | * - the key must be writable | |
299 | * - implements keyctl(KEYCTL_UPDATE) | |
300 | */ | |
301 | long keyctl_update_key(key_serial_t id, | |
302 | const void __user *_payload, | |
303 | size_t plen) | |
304 | { | |
305 | struct key *key; | |
306 | void *payload; | |
307 | long ret; | |
308 | ||
309 | ret = -EINVAL; | |
310 | if (plen > PAGE_SIZE) | |
311 | goto error; | |
312 | ||
313 | /* pull the payload in if one was supplied */ | |
314 | payload = NULL; | |
315 | if (_payload) { | |
316 | ret = -ENOMEM; | |
317 | payload = kmalloc(plen, GFP_KERNEL); | |
318 | if (!payload) | |
319 | goto error; | |
320 | ||
321 | ret = -EFAULT; | |
322 | if (copy_from_user(payload, _payload, plen) != 0) | |
323 | goto error2; | |
324 | } | |
325 | ||
326 | /* find the target key (which must be writable) */ | |
327 | key = lookup_user_key(id, 0, 0, KEY_WRITE); | |
328 | if (IS_ERR(key)) { | |
329 | ret = PTR_ERR(key); | |
330 | goto error2; | |
331 | } | |
332 | ||
333 | /* update the key */ | |
334 | ret = key_update(key, payload, plen); | |
335 | ||
336 | key_put(key); | |
337 | error2: | |
338 | kfree(payload); | |
339 | error: | |
340 | return ret; | |
341 | ||
342 | } /* end keyctl_update_key() */ | |
343 | ||
344 | /*****************************************************************************/ | |
345 | /* | |
346 | * revoke a key | |
347 | * - the key must be writable | |
348 | * - implements keyctl(KEYCTL_REVOKE) | |
349 | */ | |
350 | long keyctl_revoke_key(key_serial_t id) | |
351 | { | |
352 | struct key *key; | |
353 | long ret; | |
354 | ||
355 | key = lookup_user_key(id, 0, 0, KEY_WRITE); | |
356 | if (IS_ERR(key)) { | |
357 | ret = PTR_ERR(key); | |
358 | goto error; | |
359 | } | |
360 | ||
361 | key_revoke(key); | |
362 | ret = 0; | |
363 | ||
364 | key_put(key); | |
365 | error: | |
366 | return 0; | |
367 | ||
368 | } /* end keyctl_revoke_key() */ | |
369 | ||
370 | /*****************************************************************************/ | |
371 | /* | |
372 | * clear the specified process keyring | |
373 | * - the keyring must be writable | |
374 | * - implements keyctl(KEYCTL_CLEAR) | |
375 | */ | |
376 | long keyctl_keyring_clear(key_serial_t ringid) | |
377 | { | |
378 | struct key *keyring; | |
379 | long ret; | |
380 | ||
381 | keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE); | |
382 | if (IS_ERR(keyring)) { | |
383 | ret = PTR_ERR(keyring); | |
384 | goto error; | |
385 | } | |
386 | ||
387 | ret = keyring_clear(keyring); | |
388 | ||
389 | key_put(keyring); | |
390 | error: | |
391 | return ret; | |
392 | ||
393 | } /* end keyctl_keyring_clear() */ | |
394 | ||
395 | /*****************************************************************************/ | |
396 | /* | |
397 | * link a key into a keyring | |
398 | * - the keyring must be writable | |
399 | * - the key must be linkable | |
400 | * - implements keyctl(KEYCTL_LINK) | |
401 | */ | |
402 | long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) | |
403 | { | |
404 | struct key *keyring, *key; | |
405 | long ret; | |
406 | ||
407 | keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE); | |
408 | if (IS_ERR(keyring)) { | |
409 | ret = PTR_ERR(keyring); | |
410 | goto error; | |
411 | } | |
412 | ||
413 | key = lookup_user_key(id, 1, 0, KEY_LINK); | |
414 | if (IS_ERR(key)) { | |
415 | ret = PTR_ERR(key); | |
416 | goto error2; | |
417 | } | |
418 | ||
419 | ret = key_link(keyring, key); | |
420 | ||
421 | key_put(key); | |
422 | error2: | |
423 | key_put(keyring); | |
424 | error: | |
425 | return ret; | |
426 | ||
427 | } /* end keyctl_keyring_link() */ | |
428 | ||
429 | /*****************************************************************************/ | |
430 | /* | |
431 | * unlink the first attachment of a key from a keyring | |
432 | * - the keyring must be writable | |
433 | * - we don't need any permissions on the key | |
434 | * - implements keyctl(KEYCTL_UNLINK) | |
435 | */ | |
436 | long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) | |
437 | { | |
438 | struct key *keyring, *key; | |
439 | long ret; | |
440 | ||
441 | keyring = lookup_user_key(ringid, 0, 0, KEY_WRITE); | |
442 | if (IS_ERR(keyring)) { | |
443 | ret = PTR_ERR(keyring); | |
444 | goto error; | |
445 | } | |
446 | ||
447 | key = lookup_user_key(id, 0, 0, 0); | |
448 | if (IS_ERR(key)) { | |
449 | ret = PTR_ERR(key); | |
450 | goto error2; | |
451 | } | |
452 | ||
453 | ret = key_unlink(keyring, key); | |
454 | ||
455 | key_put(key); | |
456 | error2: | |
457 | key_put(keyring); | |
458 | error: | |
459 | return ret; | |
460 | ||
461 | } /* end keyctl_keyring_unlink() */ | |
462 | ||
463 | /*****************************************************************************/ | |
464 | /* | |
465 | * describe a user key | |
466 | * - the key must have view permission | |
467 | * - if there's a buffer, we place up to buflen bytes of data into it | |
468 | * - unless there's an error, we return the amount of description available, | |
469 | * irrespective of how much we may have copied | |
470 | * - the description is formatted thus: | |
471 | * type;uid;gid;perm;description<NUL> | |
472 | * - implements keyctl(KEYCTL_DESCRIBE) | |
473 | */ | |
474 | long keyctl_describe_key(key_serial_t keyid, | |
475 | char __user *buffer, | |
476 | size_t buflen) | |
477 | { | |
478 | struct key *key; | |
479 | char *tmpbuf; | |
480 | long ret; | |
481 | ||
482 | key = lookup_user_key(keyid, 0, 1, KEY_VIEW); | |
483 | if (IS_ERR(key)) { | |
484 | ret = PTR_ERR(key); | |
485 | goto error; | |
486 | } | |
487 | ||
488 | /* calculate how much description we're going to return */ | |
489 | ret = -ENOMEM; | |
490 | tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); | |
491 | if (!tmpbuf) | |
492 | goto error2; | |
493 | ||
494 | ret = snprintf(tmpbuf, PAGE_SIZE - 1, | |
495 | "%s;%d;%d;%06x;%s", | |
496 | key->type->name, | |
497 | key->uid, | |
498 | key->gid, | |
499 | key->perm, | |
500 | key->description ? key->description :"" | |
501 | ); | |
502 | ||
503 | /* include a NUL char at the end of the data */ | |
504 | if (ret > PAGE_SIZE - 1) | |
505 | ret = PAGE_SIZE - 1; | |
506 | tmpbuf[ret] = 0; | |
507 | ret++; | |
508 | ||
509 | /* consider returning the data */ | |
510 | if (buffer && buflen > 0) { | |
511 | if (buflen > ret) | |
512 | buflen = ret; | |
513 | ||
514 | if (copy_to_user(buffer, tmpbuf, buflen) != 0) | |
515 | ret = -EFAULT; | |
516 | } | |
517 | ||
518 | kfree(tmpbuf); | |
519 | error2: | |
520 | key_put(key); | |
521 | error: | |
522 | return ret; | |
523 | ||
524 | } /* end keyctl_describe_key() */ | |
525 | ||
526 | /*****************************************************************************/ | |
527 | /* | |
528 | * search the specified keyring for a matching key | |
529 | * - the start keyring must be searchable | |
530 | * - nested keyrings may also be searched if they are searchable | |
531 | * - only keys with search permission may be found | |
532 | * - if a key is found, it will be attached to the destination keyring if | |
533 | * there's one specified | |
534 | * - implements keyctl(KEYCTL_SEARCH) | |
535 | */ | |
536 | long keyctl_keyring_search(key_serial_t ringid, | |
537 | const char __user *_type, | |
538 | const char __user *_description, | |
539 | key_serial_t destringid) | |
540 | { | |
541 | struct key_type *ktype; | |
542 | struct key *keyring, *key, *dest; | |
543 | char type[32], *description; | |
544 | long dlen, ret; | |
545 | ||
546 | /* pull the type and description into kernel space */ | |
547 | ret = strncpy_from_user(type, _type, sizeof(type) - 1); | |
548 | if (ret < 0) | |
549 | goto error; | |
550 | type[31] = '\0'; | |
551 | ||
552 | ret = -EFAULT; | |
553 | dlen = strnlen_user(_description, PAGE_SIZE - 1); | |
554 | if (dlen <= 0) | |
555 | goto error; | |
556 | ||
557 | ret = -EINVAL; | |
558 | if (dlen > PAGE_SIZE - 1) | |
559 | goto error; | |
560 | ||
561 | ret = -ENOMEM; | |
562 | description = kmalloc(dlen + 1, GFP_KERNEL); | |
563 | if (!description) | |
564 | goto error; | |
565 | ||
566 | ret = -EFAULT; | |
567 | if (copy_from_user(description, _description, dlen + 1) != 0) | |
568 | goto error2; | |
569 | ||
570 | /* get the keyring at which to begin the search */ | |
571 | keyring = lookup_user_key(ringid, 0, 0, KEY_SEARCH); | |
572 | if (IS_ERR(keyring)) { | |
573 | ret = PTR_ERR(keyring); | |
574 | goto error2; | |
575 | } | |
576 | ||
577 | /* get the destination keyring if specified */ | |
578 | dest = NULL; | |
579 | if (destringid) { | |
580 | dest = lookup_user_key(destringid, 1, 0, KEY_WRITE); | |
581 | if (IS_ERR(dest)) { | |
582 | ret = PTR_ERR(dest); | |
583 | goto error3; | |
584 | } | |
585 | } | |
586 | ||
587 | /* find the key type */ | |
588 | ktype = key_type_lookup(type); | |
589 | if (IS_ERR(ktype)) { | |
590 | ret = PTR_ERR(ktype); | |
591 | goto error4; | |
592 | } | |
593 | ||
594 | /* do the search */ | |
595 | key = keyring_search(keyring, ktype, description); | |
596 | if (IS_ERR(key)) { | |
597 | ret = PTR_ERR(key); | |
598 | ||
599 | /* treat lack or presence of a negative key the same */ | |
600 | if (ret == -EAGAIN) | |
601 | ret = -ENOKEY; | |
602 | goto error5; | |
603 | } | |
604 | ||
605 | /* link the resulting key to the destination keyring if we can */ | |
606 | if (dest) { | |
607 | ret = -EACCES; | |
608 | if (!key_permission(key, KEY_LINK)) | |
609 | goto error6; | |
610 | ||
611 | ret = key_link(dest, key); | |
612 | if (ret < 0) | |
613 | goto error6; | |
614 | } | |
615 | ||
616 | ret = key->serial; | |
617 | ||
618 | error6: | |
619 | key_put(key); | |
620 | error5: | |
621 | key_type_put(ktype); | |
622 | error4: | |
623 | key_put(dest); | |
624 | error3: | |
625 | key_put(keyring); | |
626 | error2: | |
627 | kfree(description); | |
628 | error: | |
629 | return ret; | |
630 | ||
631 | } /* end keyctl_keyring_search() */ | |
632 | ||
633 | /*****************************************************************************/ | |
634 | /* | |
635 | * see if the key we're looking at is the target key | |
636 | */ | |
637 | static int keyctl_read_key_same(const struct key *key, const void *target) | |
638 | { | |
639 | return key == target; | |
640 | ||
641 | } /* end keyctl_read_key_same() */ | |
642 | ||
643 | /*****************************************************************************/ | |
644 | /* | |
645 | * read a user key's payload | |
646 | * - the keyring must be readable or the key must be searchable from the | |
647 | * process's keyrings | |
648 | * - if there's a buffer, we place up to buflen bytes of data into it | |
649 | * - unless there's an error, we return the amount of data in the key, | |
650 | * irrespective of how much we may have copied | |
651 | * - implements keyctl(KEYCTL_READ) | |
652 | */ | |
653 | long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) | |
654 | { | |
655 | struct key *key, *skey; | |
656 | long ret; | |
657 | ||
658 | /* find the key first */ | |
659 | key = lookup_user_key(keyid, 0, 0, 0); | |
660 | if (!IS_ERR(key)) { | |
661 | /* see if we can read it directly */ | |
662 | if (key_permission(key, KEY_READ)) | |
663 | goto can_read_key; | |
664 | ||
665 | /* can't; see if it's searchable from this process's | |
666 | * keyrings */ | |
667 | ret = -ENOKEY; | |
668 | if (key_permission(key, KEY_SEARCH)) { | |
669 | /* okay - we do have search permission on the key | |
670 | * itself, but do we have the key? */ | |
671 | skey = search_process_keyrings_aux(key->type, key, | |
672 | keyctl_read_key_same); | |
673 | if (!IS_ERR(skey)) | |
674 | goto can_read_key2; | |
675 | } | |
676 | ||
677 | goto error2; | |
678 | } | |
679 | ||
680 | ret = -ENOKEY; | |
681 | goto error; | |
682 | ||
683 | /* the key is probably readable - now try to read it */ | |
684 | can_read_key2: | |
685 | key_put(skey); | |
686 | can_read_key: | |
687 | ret = key_validate(key); | |
688 | if (ret == 0) { | |
689 | ret = -EOPNOTSUPP; | |
690 | if (key->type->read) { | |
691 | /* read the data with the semaphore held (since we | |
692 | * might sleep) */ | |
693 | down_read(&key->sem); | |
694 | ret = key->type->read(key, buffer, buflen); | |
695 | up_read(&key->sem); | |
696 | } | |
697 | } | |
698 | ||
699 | error2: | |
700 | key_put(key); | |
701 | error: | |
702 | return ret; | |
703 | ||
704 | } /* end keyctl_read_key() */ | |
705 | ||
706 | /*****************************************************************************/ | |
707 | /* | |
708 | * change the ownership of a key | |
709 | * - the keyring owned by the changer | |
710 | * - if the uid or gid is -1, then that parameter is not changed | |
711 | * - implements keyctl(KEYCTL_CHOWN) | |
712 | */ | |
713 | long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |
714 | { | |
715 | struct key *key; | |
716 | long ret; | |
717 | ||
718 | ret = 0; | |
719 | if (uid == (uid_t) -1 && gid == (gid_t) -1) | |
720 | goto error; | |
721 | ||
722 | key = lookup_user_key(id, 1, 1, 0); | |
723 | if (IS_ERR(key)) { | |
724 | ret = PTR_ERR(key); | |
725 | goto error; | |
726 | } | |
727 | ||
728 | /* make the changes with the locks held to prevent chown/chown races */ | |
729 | ret = -EACCES; | |
730 | down_write(&key->sem); | |
731 | write_lock(&key->lock); | |
732 | ||
733 | if (!capable(CAP_SYS_ADMIN)) { | |
734 | /* only the sysadmin can chown a key to some other UID */ | |
735 | if (uid != (uid_t) -1 && key->uid != uid) | |
736 | goto no_access; | |
737 | ||
738 | /* only the sysadmin can set the key's GID to a group other | |
739 | * than one of those that the current process subscribes to */ | |
740 | if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid)) | |
741 | goto no_access; | |
742 | } | |
743 | ||
744 | /* change the UID (have to update the quotas) */ | |
745 | if (uid != (uid_t) -1 && uid != key->uid) { | |
746 | /* don't support UID changing yet */ | |
747 | ret = -EOPNOTSUPP; | |
748 | goto no_access; | |
749 | } | |
750 | ||
751 | /* change the GID */ | |
752 | if (gid != (gid_t) -1) | |
753 | key->gid = gid; | |
754 | ||
755 | ret = 0; | |
756 | ||
757 | no_access: | |
758 | write_unlock(&key->lock); | |
759 | up_write(&key->sem); | |
760 | key_put(key); | |
761 | error: | |
762 | return ret; | |
763 | ||
764 | } /* end keyctl_chown_key() */ | |
765 | ||
766 | /*****************************************************************************/ | |
767 | /* | |
768 | * change the permission mask on a key | |
769 | * - the keyring owned by the changer | |
770 | * - implements keyctl(KEYCTL_SETPERM) | |
771 | */ | |
772 | long keyctl_setperm_key(key_serial_t id, key_perm_t perm) | |
773 | { | |
774 | struct key *key; | |
775 | long ret; | |
776 | ||
777 | ret = -EINVAL; | |
778 | if (perm & ~(KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) | |
779 | goto error; | |
780 | ||
781 | key = lookup_user_key(id, 1, 1, 0); | |
782 | if (IS_ERR(key)) { | |
783 | ret = PTR_ERR(key); | |
784 | goto error; | |
785 | } | |
786 | ||
787 | /* make the changes with the locks held to prevent chown/chmod | |
788 | * races */ | |
789 | ret = -EACCES; | |
790 | down_write(&key->sem); | |
791 | write_lock(&key->lock); | |
792 | ||
793 | /* if we're not the sysadmin, we can only chmod a key that we | |
794 | * own */ | |
795 | if (!capable(CAP_SYS_ADMIN) && key->uid != current->fsuid) | |
796 | goto no_access; | |
797 | ||
798 | /* changing the permissions mask */ | |
799 | key->perm = perm; | |
800 | ret = 0; | |
801 | ||
802 | no_access: | |
803 | write_unlock(&key->lock); | |
804 | up_write(&key->sem); | |
805 | key_put(key); | |
806 | error: | |
807 | return ret; | |
808 | ||
809 | } /* end keyctl_setperm_key() */ | |
810 | ||
811 | /*****************************************************************************/ | |
812 | /* | |
813 | * instantiate the key with the specified payload, and, if one is given, link | |
814 | * the key into the keyring | |
815 | */ | |
816 | long keyctl_instantiate_key(key_serial_t id, | |
817 | const void __user *_payload, | |
818 | size_t plen, | |
819 | key_serial_t ringid) | |
820 | { | |
821 | struct key *key, *keyring; | |
822 | void *payload; | |
823 | long ret; | |
824 | ||
825 | ret = -EINVAL; | |
826 | if (plen > 32767) | |
827 | goto error; | |
828 | ||
829 | /* pull the payload in if one was supplied */ | |
830 | payload = NULL; | |
831 | ||
832 | if (_payload) { | |
833 | ret = -ENOMEM; | |
834 | payload = kmalloc(plen, GFP_KERNEL); | |
835 | if (!payload) | |
836 | goto error; | |
837 | ||
838 | ret = -EFAULT; | |
839 | if (copy_from_user(payload, _payload, plen) != 0) | |
840 | goto error2; | |
841 | } | |
842 | ||
843 | /* find the target key (which must be writable) */ | |
844 | key = lookup_user_key(id, 0, 1, KEY_WRITE); | |
845 | if (IS_ERR(key)) { | |
846 | ret = PTR_ERR(key); | |
847 | goto error2; | |
848 | } | |
849 | ||
850 | /* find the destination keyring if present (which must also be | |
851 | * writable) */ | |
852 | keyring = NULL; | |
853 | if (ringid) { | |
854 | keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE); | |
855 | if (IS_ERR(keyring)) { | |
856 | ret = PTR_ERR(keyring); | |
857 | goto error3; | |
858 | } | |
859 | } | |
860 | ||
861 | /* instantiate the key and link it into a keyring */ | |
862 | ret = key_instantiate_and_link(key, payload, plen, keyring); | |
863 | ||
864 | key_put(keyring); | |
865 | error3: | |
866 | key_put(key); | |
867 | error2: | |
868 | kfree(payload); | |
869 | error: | |
870 | return ret; | |
871 | ||
872 | } /* end keyctl_instantiate_key() */ | |
873 | ||
874 | /*****************************************************************************/ | |
875 | /* | |
876 | * negatively instantiate the key with the given timeout (in seconds), and, if | |
877 | * one is given, link the key into the keyring | |
878 | */ | |
879 | long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) | |
880 | { | |
881 | struct key *key, *keyring; | |
882 | long ret; | |
883 | ||
884 | /* find the target key (which must be writable) */ | |
885 | key = lookup_user_key(id, 0, 1, KEY_WRITE); | |
886 | if (IS_ERR(key)) { | |
887 | ret = PTR_ERR(key); | |
888 | goto error; | |
889 | } | |
890 | ||
891 | /* find the destination keyring if present (which must also be | |
892 | * writable) */ | |
893 | keyring = NULL; | |
894 | if (ringid) { | |
895 | keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE); | |
896 | if (IS_ERR(keyring)) { | |
897 | ret = PTR_ERR(keyring); | |
898 | goto error2; | |
899 | } | |
900 | } | |
901 | ||
902 | /* instantiate the key and link it into a keyring */ | |
903 | ret = key_negate_and_link(key, timeout, keyring); | |
904 | ||
905 | key_put(keyring); | |
906 | error2: | |
907 | key_put(key); | |
908 | error: | |
909 | return ret; | |
910 | ||
911 | } /* end keyctl_negate_key() */ | |
912 | ||
913 | /*****************************************************************************/ | |
914 | /* | |
915 | * the key control system call | |
916 | */ | |
917 | asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, | |
918 | unsigned long arg4, unsigned long arg5) | |
919 | { | |
920 | switch (option) { | |
921 | case KEYCTL_GET_KEYRING_ID: | |
922 | return keyctl_get_keyring_ID((key_serial_t) arg2, | |
923 | (int) arg3); | |
924 | ||
925 | case KEYCTL_JOIN_SESSION_KEYRING: | |
926 | return keyctl_join_session_keyring((const char __user *) arg2); | |
927 | ||
928 | case KEYCTL_UPDATE: | |
929 | return keyctl_update_key((key_serial_t) arg2, | |
930 | (const void __user *) arg3, | |
931 | (size_t) arg4); | |
932 | ||
933 | case KEYCTL_REVOKE: | |
934 | return keyctl_revoke_key((key_serial_t) arg2); | |
935 | ||
936 | case KEYCTL_DESCRIBE: | |
937 | return keyctl_describe_key((key_serial_t) arg2, | |
938 | (char __user *) arg3, | |
939 | (unsigned) arg4); | |
940 | ||
941 | case KEYCTL_CLEAR: | |
942 | return keyctl_keyring_clear((key_serial_t) arg2); | |
943 | ||
944 | case KEYCTL_LINK: | |
945 | return keyctl_keyring_link((key_serial_t) arg2, | |
946 | (key_serial_t) arg3); | |
947 | ||
948 | case KEYCTL_UNLINK: | |
949 | return keyctl_keyring_unlink((key_serial_t) arg2, | |
950 | (key_serial_t) arg3); | |
951 | ||
952 | case KEYCTL_SEARCH: | |
953 | return keyctl_keyring_search((key_serial_t) arg2, | |
954 | (const char __user *) arg3, | |
955 | (const char __user *) arg4, | |
956 | (key_serial_t) arg5); | |
957 | ||
958 | case KEYCTL_READ: | |
959 | return keyctl_read_key((key_serial_t) arg2, | |
960 | (char __user *) arg3, | |
961 | (size_t) arg4); | |
962 | ||
963 | case KEYCTL_CHOWN: | |
964 | return keyctl_chown_key((key_serial_t) arg2, | |
965 | (uid_t) arg3, | |
966 | (gid_t) arg4); | |
967 | ||
968 | case KEYCTL_SETPERM: | |
969 | return keyctl_setperm_key((key_serial_t) arg2, | |
970 | (key_perm_t) arg3); | |
971 | ||
972 | case KEYCTL_INSTANTIATE: | |
973 | return keyctl_instantiate_key((key_serial_t) arg2, | |
974 | (const void __user *) arg3, | |
975 | (size_t) arg4, | |
976 | (key_serial_t) arg5); | |
977 | ||
978 | case KEYCTL_NEGATE: | |
979 | return keyctl_negate_key((key_serial_t) arg2, | |
980 | (unsigned) arg3, | |
981 | (key_serial_t) arg4); | |
982 | ||
983 | default: | |
984 | return -EOPNOTSUPP; | |
985 | } | |
986 | ||
987 | } /* end sys_keyctl() */ |