diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-03 13:56:12 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-03 13:56:12 -0500 |
| commit | 23c836ce5c1e1e0bb942f58a3cbc2f7fc05a08b5 (patch) | |
| tree | 818d1be11860a8fb43dee99a00de68817d0d11db | |
| parent | 1dd909affbc45412270fd196d1181404d2e416b1 (diff) | |
| parent | 188324808572faf096a5fd8c1986874bc904dafe (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull keyring/nfs fixes from James Morris:
"From David Howells:
The first one fixes the handling of maximum buffer size for key
descriptions, fixing the size at 4095 + NUL char rather than whatever
PAGE_SIZE happens to be and permits you to read back the full
description without it getting clipped because some extra information
got prepended.
The second and third fix a bug in NFS idmapper handling whereby a key
representing a mapping between an id and a name expires and causing
EKEYEXPIRED to be seen internally in NFS (which prevents the mapping
from happening) rather than re-looking up the mapping"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
KEYS: request_key() should reget expired keys rather than give EKEYEXPIRED
KEYS: Simplify KEYRING_SEARCH_{NO,DO}_STATE_CHECK flags
KEYS: Fix the size of the key description passed to/from userspace
| -rw-r--r-- | security/keys/internal.h | 1 | ||||
| -rw-r--r-- | security/keys/keyctl.c | 56 | ||||
| -rw-r--r-- | security/keys/keyring.c | 10 | ||||
| -rw-r--r-- | security/keys/request_key.c | 2 | ||||
| -rw-r--r-- | security/keys/request_key_auth.c | 1 |
5 files changed, 36 insertions, 34 deletions
diff --git a/security/keys/internal.h b/security/keys/internal.h index b8960c4959a5..200e37867336 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
| @@ -117,6 +117,7 @@ struct keyring_search_context { | |||
| 117 | #define KEYRING_SEARCH_NO_UPDATE_TIME 0x0004 /* Don't update times */ | 117 | #define KEYRING_SEARCH_NO_UPDATE_TIME 0x0004 /* Don't update times */ |
| 118 | #define KEYRING_SEARCH_NO_CHECK_PERM 0x0008 /* Don't check permissions */ | 118 | #define KEYRING_SEARCH_NO_CHECK_PERM 0x0008 /* Don't check permissions */ |
| 119 | #define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0010 /* Give an error on excessive depth */ | 119 | #define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0010 /* Give an error on excessive depth */ |
| 120 | #define KEYRING_SEARCH_SKIP_EXPIRED 0x0020 /* Ignore expired keys (intention to replace) */ | ||
| 120 | 121 | ||
| 121 | int (*iterator)(const void *object, void *iterator_data); | 122 | int (*iterator)(const void *object, void *iterator_data); |
| 122 | 123 | ||
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index eff88a5f5d40..4743d71e4aa6 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
| @@ -26,6 +26,8 @@ | |||
| 26 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
| 27 | #include "internal.h" | 27 | #include "internal.h" |
| 28 | 28 | ||
| 29 | #define KEY_MAX_DESC_SIZE 4096 | ||
| 30 | |||
| 29 | static int key_get_type_from_user(char *type, | 31 | static int key_get_type_from_user(char *type, |
| 30 | const char __user *_type, | 32 | const char __user *_type, |
| 31 | unsigned len) | 33 | unsigned len) |
| @@ -78,7 +80,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, | |||
| 78 | 80 | ||
| 79 | description = NULL; | 81 | description = NULL; |
| 80 | if (_description) { | 82 | if (_description) { |
| 81 | description = strndup_user(_description, PAGE_SIZE); | 83 | description = strndup_user(_description, KEY_MAX_DESC_SIZE); |
| 82 | if (IS_ERR(description)) { | 84 | if (IS_ERR(description)) { |
| 83 | ret = PTR_ERR(description); | 85 | ret = PTR_ERR(description); |
| 84 | goto error; | 86 | goto error; |
| @@ -177,7 +179,7 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, | |||
| 177 | goto error; | 179 | goto error; |
| 178 | 180 | ||
| 179 | /* pull the description into kernel space */ | 181 | /* pull the description into kernel space */ |
| 180 | description = strndup_user(_description, PAGE_SIZE); | 182 | description = strndup_user(_description, KEY_MAX_DESC_SIZE); |
| 181 | if (IS_ERR(description)) { | 183 | if (IS_ERR(description)) { |
| 182 | ret = PTR_ERR(description); | 184 | ret = PTR_ERR(description); |
| 183 | goto error; | 185 | goto error; |
| @@ -287,7 +289,7 @@ long keyctl_join_session_keyring(const char __user *_name) | |||
| 287 | /* fetch the name from userspace */ | 289 | /* fetch the name from userspace */ |
| 288 | name = NULL; | 290 | name = NULL; |
| 289 | if (_name) { | 291 | if (_name) { |
| 290 | name = strndup_user(_name, PAGE_SIZE); | 292 | name = strndup_user(_name, KEY_MAX_DESC_SIZE); |
| 291 | if (IS_ERR(name)) { | 293 | if (IS_ERR(name)) { |
| 292 | ret = PTR_ERR(name); | 294 | ret = PTR_ERR(name); |
| 293 | goto error; | 295 | goto error; |
| @@ -562,8 +564,9 @@ long keyctl_describe_key(key_serial_t keyid, | |||
| 562 | { | 564 | { |
| 563 | struct key *key, *instkey; | 565 | struct key *key, *instkey; |
| 564 | key_ref_t key_ref; | 566 | key_ref_t key_ref; |
| 565 | char *tmpbuf; | 567 | char *infobuf; |
| 566 | long ret; | 568 | long ret; |
| 569 | int desclen, infolen; | ||
| 567 | 570 | ||
| 568 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW); | 571 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW); |
| 569 | if (IS_ERR(key_ref)) { | 572 | if (IS_ERR(key_ref)) { |
| @@ -586,38 +589,31 @@ long keyctl_describe_key(key_serial_t keyid, | |||
| 586 | } | 589 | } |
| 587 | 590 | ||
| 588 | okay: | 591 | okay: |
| 589 | /* calculate how much description we're going to return */ | ||
| 590 | ret = -ENOMEM; | ||
| 591 | tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
| 592 | if (!tmpbuf) | ||
| 593 | goto error2; | ||
| 594 | |||
| 595 | key = key_ref_to_ptr(key_ref); | 592 | key = key_ref_to_ptr(key_ref); |
| 593 | desclen = strlen(key->description); | ||
| 596 | 594 | ||
| 597 | ret = snprintf(tmpbuf, PAGE_SIZE - 1, | 595 | /* calculate how much information we're going to return */ |
| 598 | "%s;%d;%d;%08x;%s", | 596 | ret = -ENOMEM; |
| 599 | key->type->name, | 597 | infobuf = kasprintf(GFP_KERNEL, |
| 600 | from_kuid_munged(current_user_ns(), key->uid), | 598 | "%s;%d;%d;%08x;", |
| 601 | from_kgid_munged(current_user_ns(), key->gid), | 599 | key->type->name, |
| 602 | key->perm, | 600 | from_kuid_munged(current_user_ns(), key->uid), |
| 603 | key->description ?: ""); | 601 | from_kgid_munged(current_user_ns(), key->gid), |
| 604 | 602 | key->perm); | |
| 605 | /* include a NUL char at the end of the data */ | 603 | if (!infobuf) |
| 606 | if (ret > PAGE_SIZE - 1) | 604 | goto error2; |
| 607 | ret = PAGE_SIZE - 1; | 605 | infolen = strlen(infobuf); |
| 608 | tmpbuf[ret] = 0; | 606 | ret = infolen + desclen + 1; |
| 609 | ret++; | ||
| 610 | 607 | ||
| 611 | /* consider returning the data */ | 608 | /* consider returning the data */ |
| 612 | if (buffer && buflen > 0) { | 609 | if (buffer && buflen >= ret) { |
| 613 | if (buflen > ret) | 610 | if (copy_to_user(buffer, infobuf, infolen) != 0 || |
| 614 | buflen = ret; | 611 | copy_to_user(buffer + infolen, key->description, |
| 615 | 612 | desclen + 1) != 0) | |
| 616 | if (copy_to_user(buffer, tmpbuf, buflen) != 0) | ||
| 617 | ret = -EFAULT; | 613 | ret = -EFAULT; |
| 618 | } | 614 | } |
| 619 | 615 | ||
| 620 | kfree(tmpbuf); | 616 | kfree(infobuf); |
| 621 | error2: | 617 | error2: |
| 622 | key_ref_put(key_ref); | 618 | key_ref_put(key_ref); |
| 623 | error: | 619 | error: |
| @@ -649,7 +645,7 @@ long keyctl_keyring_search(key_serial_t ringid, | |||
| 649 | if (ret < 0) | 645 | if (ret < 0) |
| 650 | goto error; | 646 | goto error; |
| 651 | 647 | ||
| 652 | description = strndup_user(_description, PAGE_SIZE); | 648 | description = strndup_user(_description, KEY_MAX_DESC_SIZE); |
| 653 | if (IS_ERR(description)) { | 649 | if (IS_ERR(description)) { |
| 654 | ret = PTR_ERR(description); | 650 | ret = PTR_ERR(description); |
| 655 | goto error; | 651 | goto error; |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 8177010174f7..e72548b5897e 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
| @@ -546,7 +546,8 @@ static int keyring_search_iterator(const void *object, void *iterator_data) | |||
| 546 | } | 546 | } |
| 547 | 547 | ||
| 548 | if (key->expiry && ctx->now.tv_sec >= key->expiry) { | 548 | if (key->expiry && ctx->now.tv_sec >= key->expiry) { |
| 549 | ctx->result = ERR_PTR(-EKEYEXPIRED); | 549 | if (!(ctx->flags & KEYRING_SEARCH_SKIP_EXPIRED)) |
| 550 | ctx->result = ERR_PTR(-EKEYEXPIRED); | ||
| 550 | kleave(" = %d [expire]", ctx->skipped_ret); | 551 | kleave(" = %d [expire]", ctx->skipped_ret); |
| 551 | goto skipped; | 552 | goto skipped; |
| 552 | } | 553 | } |
| @@ -628,6 +629,10 @@ static bool search_nested_keyrings(struct key *keyring, | |||
| 628 | ctx->index_key.type->name, | 629 | ctx->index_key.type->name, |
| 629 | ctx->index_key.description); | 630 | ctx->index_key.description); |
| 630 | 631 | ||
| 632 | #define STATE_CHECKS (KEYRING_SEARCH_NO_STATE_CHECK | KEYRING_SEARCH_DO_STATE_CHECK) | ||
| 633 | BUG_ON((ctx->flags & STATE_CHECKS) == 0 || | ||
| 634 | (ctx->flags & STATE_CHECKS) == STATE_CHECKS); | ||
| 635 | |||
| 631 | if (ctx->index_key.description) | 636 | if (ctx->index_key.description) |
| 632 | ctx->index_key.desc_len = strlen(ctx->index_key.description); | 637 | ctx->index_key.desc_len = strlen(ctx->index_key.description); |
| 633 | 638 | ||
| @@ -637,7 +642,6 @@ static bool search_nested_keyrings(struct key *keyring, | |||
| 637 | if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_ITERATE || | 642 | if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_ITERATE || |
| 638 | keyring_compare_object(keyring, &ctx->index_key)) { | 643 | keyring_compare_object(keyring, &ctx->index_key)) { |
| 639 | ctx->skipped_ret = 2; | 644 | ctx->skipped_ret = 2; |
| 640 | ctx->flags |= KEYRING_SEARCH_DO_STATE_CHECK; | ||
| 641 | switch (ctx->iterator(keyring_key_to_ptr(keyring), ctx)) { | 645 | switch (ctx->iterator(keyring_key_to_ptr(keyring), ctx)) { |
| 642 | case 1: | 646 | case 1: |
| 643 | goto found; | 647 | goto found; |
| @@ -649,8 +653,6 @@ static bool search_nested_keyrings(struct key *keyring, | |||
| 649 | } | 653 | } |
| 650 | 654 | ||
| 651 | ctx->skipped_ret = 0; | 655 | ctx->skipped_ret = 0; |
| 652 | if (ctx->flags & KEYRING_SEARCH_NO_STATE_CHECK) | ||
| 653 | ctx->flags &= ~KEYRING_SEARCH_DO_STATE_CHECK; | ||
| 654 | 656 | ||
| 655 | /* Start processing a new keyring */ | 657 | /* Start processing a new keyring */ |
| 656 | descend_to_keyring: | 658 | descend_to_keyring: |
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index bb4337c7ae1b..0c7aea4dea54 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
| @@ -516,6 +516,8 @@ struct key *request_key_and_link(struct key_type *type, | |||
| 516 | .match_data.cmp = key_default_cmp, | 516 | .match_data.cmp = key_default_cmp, |
| 517 | .match_data.raw_data = description, | 517 | .match_data.raw_data = description, |
| 518 | .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | 518 | .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
| 519 | .flags = (KEYRING_SEARCH_DO_STATE_CHECK | | ||
| 520 | KEYRING_SEARCH_SKIP_EXPIRED), | ||
| 519 | }; | 521 | }; |
| 520 | struct key *key; | 522 | struct key *key; |
| 521 | key_ref_t key_ref; | 523 | key_ref_t key_ref; |
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 6639e2cb8853..5d672f7580dd 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c | |||
| @@ -249,6 +249,7 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id) | |||
| 249 | .match_data.cmp = key_default_cmp, | 249 | .match_data.cmp = key_default_cmp, |
| 250 | .match_data.raw_data = description, | 250 | .match_data.raw_data = description, |
| 251 | .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | 251 | .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
| 252 | .flags = KEYRING_SEARCH_DO_STATE_CHECK, | ||
| 252 | }; | 253 | }; |
| 253 | struct key *authkey; | 254 | struct key *authkey; |
| 254 | key_ref_t authkey_ref; | 255 | key_ref_t authkey_ref; |
