diff options
-rw-r--r-- | security/keys/keyctl.c | 56 |
1 files changed, 26 insertions, 30 deletions
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; |