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 /security | |
| 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>
Diffstat (limited to 'security')
| -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 */ |
