diff options
Diffstat (limited to 'security/keys/keyctl.c')
-rw-r--r-- | security/keys/keyctl.c | 70 |
1 files changed, 44 insertions, 26 deletions
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 3364fbf46807..5d34b4e827d6 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -46,6 +46,9 @@ static int key_get_type_from_user(char *type, | |||
46 | * Extract the description of a new key from userspace and either add it as a | 46 | * Extract the description of a new key from userspace and either add it as a |
47 | * new key to the specified keyring or update a matching key in that keyring. | 47 | * new key to the specified keyring or update a matching key in that keyring. |
48 | * | 48 | * |
49 | * If the description is NULL or an empty string, the key type is asked to | ||
50 | * generate one from the payload. | ||
51 | * | ||
49 | * The keyring must be writable so that we can attach the key to it. | 52 | * The keyring must be writable so that we can attach the key to it. |
50 | * | 53 | * |
51 | * If successful, the new key's serial number is returned, otherwise an error | 54 | * If successful, the new key's serial number is returned, otherwise an error |
@@ -72,10 +75,17 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, | |||
72 | if (ret < 0) | 75 | if (ret < 0) |
73 | goto error; | 76 | goto error; |
74 | 77 | ||
75 | description = strndup_user(_description, PAGE_SIZE); | 78 | description = NULL; |
76 | if (IS_ERR(description)) { | 79 | if (_description) { |
77 | ret = PTR_ERR(description); | 80 | description = strndup_user(_description, PAGE_SIZE); |
78 | goto error; | 81 | if (IS_ERR(description)) { |
82 | ret = PTR_ERR(description); | ||
83 | goto error; | ||
84 | } | ||
85 | if (!*description) { | ||
86 | kfree(description); | ||
87 | description = NULL; | ||
88 | } | ||
79 | } | 89 | } |
80 | 90 | ||
81 | /* pull the payload in if one was supplied */ | 91 | /* pull the payload in if one was supplied */ |
@@ -569,8 +579,8 @@ okay: | |||
569 | ret = snprintf(tmpbuf, PAGE_SIZE - 1, | 579 | ret = snprintf(tmpbuf, PAGE_SIZE - 1, |
570 | "%s;%d;%d;%08x;%s", | 580 | "%s;%d;%d;%08x;%s", |
571 | key->type->name, | 581 | key->type->name, |
572 | key->uid, | 582 | from_kuid_munged(current_user_ns(), key->uid), |
573 | key->gid, | 583 | from_kgid_munged(current_user_ns(), key->gid), |
574 | key->perm, | 584 | key->perm, |
575 | key->description ?: ""); | 585 | key->description ?: ""); |
576 | 586 | ||
@@ -766,15 +776,25 @@ error: | |||
766 | * | 776 | * |
767 | * If successful, 0 will be returned. | 777 | * If successful, 0 will be returned. |
768 | */ | 778 | */ |
769 | long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | 779 | long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group) |
770 | { | 780 | { |
771 | struct key_user *newowner, *zapowner = NULL; | 781 | struct key_user *newowner, *zapowner = NULL; |
772 | struct key *key; | 782 | struct key *key; |
773 | key_ref_t key_ref; | 783 | key_ref_t key_ref; |
774 | long ret; | 784 | long ret; |
785 | kuid_t uid; | ||
786 | kgid_t gid; | ||
787 | |||
788 | uid = make_kuid(current_user_ns(), user); | ||
789 | gid = make_kgid(current_user_ns(), group); | ||
790 | ret = -EINVAL; | ||
791 | if ((user != (uid_t) -1) && !uid_valid(uid)) | ||
792 | goto error; | ||
793 | if ((group != (gid_t) -1) && !gid_valid(gid)) | ||
794 | goto error; | ||
775 | 795 | ||
776 | ret = 0; | 796 | ret = 0; |
777 | if (uid == (uid_t) -1 && gid == (gid_t) -1) | 797 | if (user == (uid_t) -1 && group == (gid_t) -1) |
778 | goto error; | 798 | goto error; |
779 | 799 | ||
780 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, | 800 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
@@ -792,27 +812,27 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |||
792 | 812 | ||
793 | if (!capable(CAP_SYS_ADMIN)) { | 813 | if (!capable(CAP_SYS_ADMIN)) { |
794 | /* only the sysadmin can chown a key to some other UID */ | 814 | /* only the sysadmin can chown a key to some other UID */ |
795 | if (uid != (uid_t) -1 && key->uid != uid) | 815 | if (user != (uid_t) -1 && !uid_eq(key->uid, uid)) |
796 | goto error_put; | 816 | goto error_put; |
797 | 817 | ||
798 | /* only the sysadmin can set the key's GID to a group other | 818 | /* only the sysadmin can set the key's GID to a group other |
799 | * than one of those that the current process subscribes to */ | 819 | * than one of those that the current process subscribes to */ |
800 | if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid)) | 820 | if (group != (gid_t) -1 && !gid_eq(gid, key->gid) && !in_group_p(gid)) |
801 | goto error_put; | 821 | goto error_put; |
802 | } | 822 | } |
803 | 823 | ||
804 | /* change the UID */ | 824 | /* change the UID */ |
805 | if (uid != (uid_t) -1 && uid != key->uid) { | 825 | if (user != (uid_t) -1 && !uid_eq(uid, key->uid)) { |
806 | ret = -ENOMEM; | 826 | ret = -ENOMEM; |
807 | newowner = key_user_lookup(uid, current_user_ns()); | 827 | newowner = key_user_lookup(uid); |
808 | if (!newowner) | 828 | if (!newowner) |
809 | goto error_put; | 829 | goto error_put; |
810 | 830 | ||
811 | /* transfer the quota burden to the new user */ | 831 | /* transfer the quota burden to the new user */ |
812 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | 832 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { |
813 | unsigned maxkeys = (uid == 0) ? | 833 | unsigned maxkeys = uid_eq(uid, GLOBAL_ROOT_UID) ? |
814 | key_quota_root_maxkeys : key_quota_maxkeys; | 834 | key_quota_root_maxkeys : key_quota_maxkeys; |
815 | unsigned maxbytes = (uid == 0) ? | 835 | unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ? |
816 | key_quota_root_maxbytes : key_quota_maxbytes; | 836 | key_quota_root_maxbytes : key_quota_maxbytes; |
817 | 837 | ||
818 | spin_lock(&newowner->lock); | 838 | spin_lock(&newowner->lock); |
@@ -846,7 +866,7 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |||
846 | } | 866 | } |
847 | 867 | ||
848 | /* change the GID */ | 868 | /* change the GID */ |
849 | if (gid != (gid_t) -1) | 869 | if (group != (gid_t) -1) |
850 | key->gid = gid; | 870 | key->gid = gid; |
851 | 871 | ||
852 | ret = 0; | 872 | ret = 0; |
@@ -897,7 +917,7 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm) | |||
897 | down_write(&key->sem); | 917 | down_write(&key->sem); |
898 | 918 | ||
899 | /* if we're not the sysadmin, we can only change a key that we own */ | 919 | /* if we're not the sysadmin, we can only change a key that we own */ |
900 | if (capable(CAP_SYS_ADMIN) || key->uid == current_fsuid()) { | 920 | if (capable(CAP_SYS_ADMIN) || uid_eq(key->uid, current_fsuid())) { |
901 | key->perm = perm; | 921 | key->perm = perm; |
902 | ret = 0; | 922 | ret = 0; |
903 | } | 923 | } |
@@ -1486,7 +1506,6 @@ long keyctl_session_to_parent(void) | |||
1486 | oldwork = NULL; | 1506 | oldwork = NULL; |
1487 | parent = me->real_parent; | 1507 | parent = me->real_parent; |
1488 | 1508 | ||
1489 | task_lock(parent); | ||
1490 | /* the parent mustn't be init and mustn't be a kernel thread */ | 1509 | /* the parent mustn't be init and mustn't be a kernel thread */ |
1491 | if (parent->pid <= 1 || !parent->mm) | 1510 | if (parent->pid <= 1 || !parent->mm) |
1492 | goto unlock; | 1511 | goto unlock; |
@@ -1507,18 +1526,18 @@ long keyctl_session_to_parent(void) | |||
1507 | 1526 | ||
1508 | /* the parent must have the same effective ownership and mustn't be | 1527 | /* the parent must have the same effective ownership and mustn't be |
1509 | * SUID/SGID */ | 1528 | * SUID/SGID */ |
1510 | if (pcred->uid != mycred->euid || | 1529 | if (!uid_eq(pcred->uid, mycred->euid) || |
1511 | pcred->euid != mycred->euid || | 1530 | !uid_eq(pcred->euid, mycred->euid) || |
1512 | pcred->suid != mycred->euid || | 1531 | !uid_eq(pcred->suid, mycred->euid) || |
1513 | pcred->gid != mycred->egid || | 1532 | !gid_eq(pcred->gid, mycred->egid) || |
1514 | pcred->egid != mycred->egid || | 1533 | !gid_eq(pcred->egid, mycred->egid) || |
1515 | pcred->sgid != mycred->egid) | 1534 | !gid_eq(pcred->sgid, mycred->egid)) |
1516 | goto unlock; | 1535 | goto unlock; |
1517 | 1536 | ||
1518 | /* the keyrings must have the same UID */ | 1537 | /* the keyrings must have the same UID */ |
1519 | if ((pcred->tgcred->session_keyring && | 1538 | if ((pcred->tgcred->session_keyring && |
1520 | pcred->tgcred->session_keyring->uid != mycred->euid) || | 1539 | !uid_eq(pcred->tgcred->session_keyring->uid, mycred->euid)) || |
1521 | mycred->tgcred->session_keyring->uid != mycred->euid) | 1540 | !uid_eq(mycred->tgcred->session_keyring->uid, mycred->euid)) |
1522 | goto unlock; | 1541 | goto unlock; |
1523 | 1542 | ||
1524 | /* cancel an already pending keyring replacement */ | 1543 | /* cancel an already pending keyring replacement */ |
@@ -1530,7 +1549,6 @@ long keyctl_session_to_parent(void) | |||
1530 | if (!ret) | 1549 | if (!ret) |
1531 | newwork = NULL; | 1550 | newwork = NULL; |
1532 | unlock: | 1551 | unlock: |
1533 | task_unlock(parent); | ||
1534 | write_unlock_irq(&tasklist_lock); | 1552 | write_unlock_irq(&tasklist_lock); |
1535 | rcu_read_unlock(); | 1553 | rcu_read_unlock(); |
1536 | if (oldwork) | 1554 | if (oldwork) |