diff options
author | David Howells <dhowells@redhat.com> | 2009-09-02 04:13:45 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2009-09-02 07:29:04 -0400 |
commit | 5593122eec26b061cc0b6fbff32118f1aadf4a27 (patch) | |
tree | f148b182ada54b722962607567bd5b1ace06640a | |
parent | e0e817392b9acf2c98d3be80c233dddb1b52003d (diff) |
KEYS: Deal with dead-type keys appropriately [try #6]
Allow keys for which the key type has been removed to be unlinked. Currently
dead-type keys can only be disposed of by completely clearing the keyrings
that point to them.
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Serge Hallyn <serue@us.ibm.com>
Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r-- | security/keys/internal.h | 5 | ||||
-rw-r--r-- | security/keys/key.c | 6 | ||||
-rw-r--r-- | security/keys/keyctl.c | 50 | ||||
-rw-r--r-- | security/keys/process_keys.c | 18 |
4 files changed, 48 insertions, 31 deletions
diff --git a/security/keys/internal.h b/security/keys/internal.h index 9fb679c66b8a..a7252e7b2e05 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -124,8 +124,11 @@ extern struct key *request_key_and_link(struct key_type *type, | |||
124 | struct key *dest_keyring, | 124 | struct key *dest_keyring, |
125 | unsigned long flags); | 125 | unsigned long flags); |
126 | 126 | ||
127 | extern key_ref_t lookup_user_key(key_serial_t id, int create, int partial, | 127 | extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, |
128 | key_perm_t perm); | 128 | key_perm_t perm); |
129 | #define KEY_LOOKUP_CREATE 0x01 | ||
130 | #define KEY_LOOKUP_PARTIAL 0x02 | ||
131 | #define KEY_LOOKUP_FOR_UNLINK 0x04 | ||
129 | 132 | ||
130 | extern long join_session_keyring(const char *name); | 133 | extern long join_session_keyring(const char *name); |
131 | 134 | ||
diff --git a/security/keys/key.c b/security/keys/key.c index 4a1297d1ada4..3762d5b1ce64 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -642,10 +642,8 @@ struct key *key_lookup(key_serial_t id) | |||
642 | goto error; | 642 | goto error; |
643 | 643 | ||
644 | found: | 644 | found: |
645 | /* pretend it doesn't exist if it's dead */ | 645 | /* pretend it doesn't exist if it is awaiting deletion */ |
646 | if (atomic_read(&key->usage) == 0 || | 646 | if (atomic_read(&key->usage) == 0) |
647 | test_bit(KEY_FLAG_DEAD, &key->flags) || | ||
648 | key->type == &key_type_dead) | ||
649 | goto not_found; | 647 | goto not_found; |
650 | 648 | ||
651 | /* this races with key_put(), but that doesn't matter since key_put() | 649 | /* this races with key_put(), but that doesn't matter since key_put() |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 7f09fb897d2b..b85ace218395 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -103,7 +103,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, | |||
103 | } | 103 | } |
104 | 104 | ||
105 | /* find the target keyring (which must be writable) */ | 105 | /* find the target keyring (which must be writable) */ |
106 | keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 106 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); |
107 | if (IS_ERR(keyring_ref)) { | 107 | if (IS_ERR(keyring_ref)) { |
108 | ret = PTR_ERR(keyring_ref); | 108 | ret = PTR_ERR(keyring_ref); |
109 | goto error3; | 109 | goto error3; |
@@ -185,7 +185,8 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, | |||
185 | /* get the destination keyring if specified */ | 185 | /* get the destination keyring if specified */ |
186 | dest_ref = NULL; | 186 | dest_ref = NULL; |
187 | if (destringid) { | 187 | if (destringid) { |
188 | dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE); | 188 | dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, |
189 | KEY_WRITE); | ||
189 | if (IS_ERR(dest_ref)) { | 190 | if (IS_ERR(dest_ref)) { |
190 | ret = PTR_ERR(dest_ref); | 191 | ret = PTR_ERR(dest_ref); |
191 | goto error3; | 192 | goto error3; |
@@ -233,9 +234,11 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, | |||
233 | long keyctl_get_keyring_ID(key_serial_t id, int create) | 234 | long keyctl_get_keyring_ID(key_serial_t id, int create) |
234 | { | 235 | { |
235 | key_ref_t key_ref; | 236 | key_ref_t key_ref; |
237 | unsigned long lflags; | ||
236 | long ret; | 238 | long ret; |
237 | 239 | ||
238 | key_ref = lookup_user_key(id, create, 0, KEY_SEARCH); | 240 | lflags = create ? KEY_LOOKUP_CREATE : 0; |
241 | key_ref = lookup_user_key(id, lflags, KEY_SEARCH); | ||
239 | if (IS_ERR(key_ref)) { | 242 | if (IS_ERR(key_ref)) { |
240 | ret = PTR_ERR(key_ref); | 243 | ret = PTR_ERR(key_ref); |
241 | goto error; | 244 | goto error; |
@@ -309,7 +312,7 @@ long keyctl_update_key(key_serial_t id, | |||
309 | } | 312 | } |
310 | 313 | ||
311 | /* find the target key (which must be writable) */ | 314 | /* find the target key (which must be writable) */ |
312 | key_ref = lookup_user_key(id, 0, 0, KEY_WRITE); | 315 | key_ref = lookup_user_key(id, 0, KEY_WRITE); |
313 | if (IS_ERR(key_ref)) { | 316 | if (IS_ERR(key_ref)) { |
314 | ret = PTR_ERR(key_ref); | 317 | ret = PTR_ERR(key_ref); |
315 | goto error2; | 318 | goto error2; |
@@ -337,7 +340,7 @@ long keyctl_revoke_key(key_serial_t id) | |||
337 | key_ref_t key_ref; | 340 | key_ref_t key_ref; |
338 | long ret; | 341 | long ret; |
339 | 342 | ||
340 | key_ref = lookup_user_key(id, 0, 0, KEY_WRITE); | 343 | key_ref = lookup_user_key(id, 0, KEY_WRITE); |
341 | if (IS_ERR(key_ref)) { | 344 | if (IS_ERR(key_ref)) { |
342 | ret = PTR_ERR(key_ref); | 345 | ret = PTR_ERR(key_ref); |
343 | goto error; | 346 | goto error; |
@@ -363,7 +366,7 @@ long keyctl_keyring_clear(key_serial_t ringid) | |||
363 | key_ref_t keyring_ref; | 366 | key_ref_t keyring_ref; |
364 | long ret; | 367 | long ret; |
365 | 368 | ||
366 | keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 369 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); |
367 | if (IS_ERR(keyring_ref)) { | 370 | if (IS_ERR(keyring_ref)) { |
368 | ret = PTR_ERR(keyring_ref); | 371 | ret = PTR_ERR(keyring_ref); |
369 | goto error; | 372 | goto error; |
@@ -389,13 +392,13 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) | |||
389 | key_ref_t keyring_ref, key_ref; | 392 | key_ref_t keyring_ref, key_ref; |
390 | long ret; | 393 | long ret; |
391 | 394 | ||
392 | keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 395 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); |
393 | if (IS_ERR(keyring_ref)) { | 396 | if (IS_ERR(keyring_ref)) { |
394 | ret = PTR_ERR(keyring_ref); | 397 | ret = PTR_ERR(keyring_ref); |
395 | goto error; | 398 | goto error; |
396 | } | 399 | } |
397 | 400 | ||
398 | key_ref = lookup_user_key(id, 1, 0, KEY_LINK); | 401 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_LINK); |
399 | if (IS_ERR(key_ref)) { | 402 | if (IS_ERR(key_ref)) { |
400 | ret = PTR_ERR(key_ref); | 403 | ret = PTR_ERR(key_ref); |
401 | goto error2; | 404 | goto error2; |
@@ -423,13 +426,13 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) | |||
423 | key_ref_t keyring_ref, key_ref; | 426 | key_ref_t keyring_ref, key_ref; |
424 | long ret; | 427 | long ret; |
425 | 428 | ||
426 | keyring_ref = lookup_user_key(ringid, 0, 0, KEY_WRITE); | 429 | keyring_ref = lookup_user_key(ringid, 0, KEY_WRITE); |
427 | if (IS_ERR(keyring_ref)) { | 430 | if (IS_ERR(keyring_ref)) { |
428 | ret = PTR_ERR(keyring_ref); | 431 | ret = PTR_ERR(keyring_ref); |
429 | goto error; | 432 | goto error; |
430 | } | 433 | } |
431 | 434 | ||
432 | key_ref = lookup_user_key(id, 0, 0, 0); | 435 | key_ref = lookup_user_key(id, KEY_LOOKUP_FOR_UNLINK, 0); |
433 | if (IS_ERR(key_ref)) { | 436 | if (IS_ERR(key_ref)) { |
434 | ret = PTR_ERR(key_ref); | 437 | ret = PTR_ERR(key_ref); |
435 | goto error2; | 438 | goto error2; |
@@ -465,7 +468,7 @@ long keyctl_describe_key(key_serial_t keyid, | |||
465 | char *tmpbuf; | 468 | char *tmpbuf; |
466 | long ret; | 469 | long ret; |
467 | 470 | ||
468 | key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW); | 471 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); |
469 | if (IS_ERR(key_ref)) { | 472 | if (IS_ERR(key_ref)) { |
470 | /* viewing a key under construction is permitted if we have the | 473 | /* viewing a key under construction is permitted if we have the |
471 | * authorisation token handy */ | 474 | * authorisation token handy */ |
@@ -474,7 +477,8 @@ long keyctl_describe_key(key_serial_t keyid, | |||
474 | if (!IS_ERR(instkey)) { | 477 | if (!IS_ERR(instkey)) { |
475 | key_put(instkey); | 478 | key_put(instkey); |
476 | key_ref = lookup_user_key(keyid, | 479 | key_ref = lookup_user_key(keyid, |
477 | 0, 1, 0); | 480 | KEY_LOOKUP_PARTIAL, |
481 | 0); | ||
478 | if (!IS_ERR(key_ref)) | 482 | if (!IS_ERR(key_ref)) |
479 | goto okay; | 483 | goto okay; |
480 | } | 484 | } |
@@ -558,7 +562,7 @@ long keyctl_keyring_search(key_serial_t ringid, | |||
558 | } | 562 | } |
559 | 563 | ||
560 | /* get the keyring at which to begin the search */ | 564 | /* get the keyring at which to begin the search */ |
561 | keyring_ref = lookup_user_key(ringid, 0, 0, KEY_SEARCH); | 565 | keyring_ref = lookup_user_key(ringid, 0, KEY_SEARCH); |
562 | if (IS_ERR(keyring_ref)) { | 566 | if (IS_ERR(keyring_ref)) { |
563 | ret = PTR_ERR(keyring_ref); | 567 | ret = PTR_ERR(keyring_ref); |
564 | goto error2; | 568 | goto error2; |
@@ -567,7 +571,8 @@ long keyctl_keyring_search(key_serial_t ringid, | |||
567 | /* get the destination keyring if specified */ | 571 | /* get the destination keyring if specified */ |
568 | dest_ref = NULL; | 572 | dest_ref = NULL; |
569 | if (destringid) { | 573 | if (destringid) { |
570 | dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE); | 574 | dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, |
575 | KEY_WRITE); | ||
571 | if (IS_ERR(dest_ref)) { | 576 | if (IS_ERR(dest_ref)) { |
572 | ret = PTR_ERR(dest_ref); | 577 | ret = PTR_ERR(dest_ref); |
573 | goto error3; | 578 | goto error3; |
@@ -637,7 +642,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) | |||
637 | long ret; | 642 | long ret; |
638 | 643 | ||
639 | /* find the key first */ | 644 | /* find the key first */ |
640 | key_ref = lookup_user_key(keyid, 0, 0, 0); | 645 | key_ref = lookup_user_key(keyid, 0, 0); |
641 | if (IS_ERR(key_ref)) { | 646 | if (IS_ERR(key_ref)) { |
642 | ret = -ENOKEY; | 647 | ret = -ENOKEY; |
643 | goto error; | 648 | goto error; |
@@ -700,7 +705,8 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |||
700 | if (uid == (uid_t) -1 && gid == (gid_t) -1) | 705 | if (uid == (uid_t) -1 && gid == (gid_t) -1) |
701 | goto error; | 706 | goto error; |
702 | 707 | ||
703 | key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR); | 708 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
709 | KEY_SETATTR); | ||
704 | if (IS_ERR(key_ref)) { | 710 | if (IS_ERR(key_ref)) { |
705 | ret = PTR_ERR(key_ref); | 711 | ret = PTR_ERR(key_ref); |
706 | goto error; | 712 | goto error; |
@@ -805,7 +811,8 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm) | |||
805 | if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) | 811 | if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) |
806 | goto error; | 812 | goto error; |
807 | 813 | ||
808 | key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR); | 814 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
815 | KEY_SETATTR); | ||
809 | if (IS_ERR(key_ref)) { | 816 | if (IS_ERR(key_ref)) { |
810 | ret = PTR_ERR(key_ref); | 817 | ret = PTR_ERR(key_ref); |
811 | goto error; | 818 | goto error; |
@@ -847,7 +854,7 @@ static long get_instantiation_keyring(key_serial_t ringid, | |||
847 | 854 | ||
848 | /* if a specific keyring is nominated by ID, then use that */ | 855 | /* if a specific keyring is nominated by ID, then use that */ |
849 | if (ringid > 0) { | 856 | if (ringid > 0) { |
850 | dkref = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 857 | dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); |
851 | if (IS_ERR(dkref)) | 858 | if (IS_ERR(dkref)) |
852 | return PTR_ERR(dkref); | 859 | return PTR_ERR(dkref); |
853 | *_dest_keyring = key_ref_to_ptr(dkref); | 860 | *_dest_keyring = key_ref_to_ptr(dkref); |
@@ -1083,7 +1090,8 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout) | |||
1083 | time_t expiry; | 1090 | time_t expiry; |
1084 | long ret; | 1091 | long ret; |
1085 | 1092 | ||
1086 | key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR); | 1093 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
1094 | KEY_SETATTR); | ||
1087 | if (IS_ERR(key_ref)) { | 1095 | if (IS_ERR(key_ref)) { |
1088 | ret = PTR_ERR(key_ref); | 1096 | ret = PTR_ERR(key_ref); |
1089 | goto error; | 1097 | goto error; |
@@ -1170,7 +1178,7 @@ long keyctl_get_security(key_serial_t keyid, | |||
1170 | char *context; | 1178 | char *context; |
1171 | long ret; | 1179 | long ret; |
1172 | 1180 | ||
1173 | key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW); | 1181 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); |
1174 | if (IS_ERR(key_ref)) { | 1182 | if (IS_ERR(key_ref)) { |
1175 | if (PTR_ERR(key_ref) != -EACCES) | 1183 | if (PTR_ERR(key_ref) != -EACCES) |
1176 | return PTR_ERR(key_ref); | 1184 | return PTR_ERR(key_ref); |
@@ -1182,7 +1190,7 @@ long keyctl_get_security(key_serial_t keyid, | |||
1182 | return PTR_ERR(key_ref); | 1190 | return PTR_ERR(key_ref); |
1183 | key_put(instkey); | 1191 | key_put(instkey); |
1184 | 1192 | ||
1185 | key_ref = lookup_user_key(keyid, 0, 1, 0); | 1193 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, 0); |
1186 | if (IS_ERR(key_ref)) | 1194 | if (IS_ERR(key_ref)) |
1187 | return PTR_ERR(key_ref); | 1195 | return PTR_ERR(key_ref); |
1188 | } | 1196 | } |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index ed929af466d3..4739cfbb41b7 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -487,7 +487,7 @@ static int lookup_user_key_possessed(const struct key *key, const void *target) | |||
487 | * - don't create special keyrings unless so requested | 487 | * - don't create special keyrings unless so requested |
488 | * - partially constructed keys aren't found unless requested | 488 | * - partially constructed keys aren't found unless requested |
489 | */ | 489 | */ |
490 | key_ref_t lookup_user_key(key_serial_t id, int create, int partial, | 490 | key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, |
491 | key_perm_t perm) | 491 | key_perm_t perm) |
492 | { | 492 | { |
493 | struct request_key_auth *rka; | 493 | struct request_key_auth *rka; |
@@ -503,7 +503,7 @@ try_again: | |||
503 | switch (id) { | 503 | switch (id) { |
504 | case KEY_SPEC_THREAD_KEYRING: | 504 | case KEY_SPEC_THREAD_KEYRING: |
505 | if (!cred->thread_keyring) { | 505 | if (!cred->thread_keyring) { |
506 | if (!create) | 506 | if (!(lflags & KEY_LOOKUP_CREATE)) |
507 | goto error; | 507 | goto error; |
508 | 508 | ||
509 | ret = install_thread_keyring(); | 509 | ret = install_thread_keyring(); |
@@ -521,7 +521,7 @@ try_again: | |||
521 | 521 | ||
522 | case KEY_SPEC_PROCESS_KEYRING: | 522 | case KEY_SPEC_PROCESS_KEYRING: |
523 | if (!cred->tgcred->process_keyring) { | 523 | if (!cred->tgcred->process_keyring) { |
524 | if (!create) | 524 | if (!(lflags & KEY_LOOKUP_CREATE)) |
525 | goto error; | 525 | goto error; |
526 | 526 | ||
527 | ret = install_process_keyring(); | 527 | ret = install_process_keyring(); |
@@ -642,7 +642,14 @@ try_again: | |||
642 | break; | 642 | break; |
643 | } | 643 | } |
644 | 644 | ||
645 | if (!partial) { | 645 | /* unlink does not use the nominated key in any way, so can skip all |
646 | * the permission checks as it is only concerned with the keyring */ | ||
647 | if (lflags & KEY_LOOKUP_FOR_UNLINK) { | ||
648 | ret = 0; | ||
649 | goto error; | ||
650 | } | ||
651 | |||
652 | if (!(lflags & KEY_LOOKUP_PARTIAL)) { | ||
646 | ret = wait_for_key_construction(key, true); | 653 | ret = wait_for_key_construction(key, true); |
647 | switch (ret) { | 654 | switch (ret) { |
648 | case -ERESTARTSYS: | 655 | case -ERESTARTSYS: |
@@ -660,7 +667,8 @@ try_again: | |||
660 | } | 667 | } |
661 | 668 | ||
662 | ret = -EIO; | 669 | ret = -EIO; |
663 | if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | 670 | if (!(lflags & KEY_LOOKUP_PARTIAL) && |
671 | !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | ||
664 | goto invalid_key; | 672 | goto invalid_key; |
665 | 673 | ||
666 | /* check the permissions */ | 674 | /* check the permissions */ |