diff options
Diffstat (limited to 'security')
| -rw-r--r-- | security/keys/keyctl.c | 56 |
1 files changed, 48 insertions, 8 deletions
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index d74458522e98..329411cf8768 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
| @@ -673,6 +673,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) | |||
| 673 | */ | 673 | */ |
| 674 | long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | 674 | long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) |
| 675 | { | 675 | { |
| 676 | struct key_user *newowner, *zapowner = NULL; | ||
| 676 | struct key *key; | 677 | struct key *key; |
| 677 | key_ref_t key_ref; | 678 | key_ref_t key_ref; |
| 678 | long ret; | 679 | long ret; |
| @@ -696,19 +697,50 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |||
| 696 | if (!capable(CAP_SYS_ADMIN)) { | 697 | if (!capable(CAP_SYS_ADMIN)) { |
| 697 | /* only the sysadmin can chown a key to some other UID */ | 698 | /* only the sysadmin can chown a key to some other UID */ |
| 698 | if (uid != (uid_t) -1 && key->uid != uid) | 699 | if (uid != (uid_t) -1 && key->uid != uid) |
| 699 | goto no_access; | 700 | goto error_put; |
| 700 | 701 | ||
| 701 | /* only the sysadmin can set the key's GID to a group other | 702 | /* only the sysadmin can set the key's GID to a group other |
| 702 | * than one of those that the current process subscribes to */ | 703 | * than one of those that the current process subscribes to */ |
| 703 | if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid)) | 704 | if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid)) |
| 704 | goto no_access; | 705 | goto error_put; |
| 705 | } | 706 | } |
| 706 | 707 | ||
| 707 | /* change the UID (have to update the quotas) */ | 708 | /* change the UID */ |
| 708 | if (uid != (uid_t) -1 && uid != key->uid) { | 709 | if (uid != (uid_t) -1 && uid != key->uid) { |
| 709 | /* don't support UID changing yet */ | 710 | ret = -ENOMEM; |
| 710 | ret = -EOPNOTSUPP; | 711 | newowner = key_user_lookup(uid); |
| 711 | goto no_access; | 712 | if (!newowner) |
| 713 | goto error_put; | ||
| 714 | |||
| 715 | /* transfer the quota burden to the new user */ | ||
| 716 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | ||
| 717 | spin_lock(&newowner->lock); | ||
| 718 | if (newowner->qnkeys + 1 >= KEYQUOTA_MAX_KEYS || | ||
| 719 | newowner->qnbytes + key->quotalen >= | ||
| 720 | KEYQUOTA_MAX_BYTES) | ||
| 721 | goto quota_overrun; | ||
| 722 | |||
| 723 | newowner->qnkeys++; | ||
| 724 | newowner->qnbytes += key->quotalen; | ||
| 725 | spin_unlock(&newowner->lock); | ||
| 726 | |||
| 727 | spin_lock(&key->user->lock); | ||
| 728 | key->user->qnkeys--; | ||
| 729 | key->user->qnbytes -= key->quotalen; | ||
| 730 | spin_unlock(&key->user->lock); | ||
| 731 | } | ||
| 732 | |||
| 733 | atomic_dec(&key->user->nkeys); | ||
| 734 | atomic_inc(&newowner->nkeys); | ||
| 735 | |||
| 736 | if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { | ||
| 737 | atomic_dec(&key->user->nikeys); | ||
| 738 | atomic_inc(&newowner->nikeys); | ||
| 739 | } | ||
| 740 | |||
| 741 | zapowner = key->user; | ||
| 742 | key->user = newowner; | ||
| 743 | key->uid = uid; | ||
| 712 | } | 744 | } |
| 713 | 745 | ||
| 714 | /* change the GID */ | 746 | /* change the GID */ |
| @@ -717,12 +749,20 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |||
| 717 | 749 | ||
| 718 | ret = 0; | 750 | ret = 0; |
| 719 | 751 | ||
| 720 | no_access: | 752 | error_put: |
| 721 | up_write(&key->sem); | 753 | up_write(&key->sem); |
| 722 | key_put(key); | 754 | key_put(key); |
| 723 | error: | 755 | if (zapowner) |
| 756 | key_user_put(zapowner); | ||
| 757 | error: | ||
| 724 | return ret; | 758 | return ret; |
| 725 | 759 | ||
| 760 | quota_overrun: | ||
| 761 | spin_unlock(&newowner->lock); | ||
| 762 | zapowner = newowner; | ||
| 763 | ret = -EDQUOT; | ||
| 764 | goto error_put; | ||
| 765 | |||
| 726 | } /* end keyctl_chown_key() */ | 766 | } /* end keyctl_chown_key() */ |
| 727 | 767 | ||
| 728 | /*****************************************************************************/ | 768 | /*****************************************************************************/ |
