Commit 5801649d authored by Fredrik Tolf's avatar Fredrik Tolf Committed by Linus Torvalds

[PATCH] keys: let keyctl_chown() change a key's owner

Let keyctl_chown() change a key's owner, including attempting to transfer the
quota burden to the new user.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 31204ed9
...@@ -673,6 +673,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) ...@@ -673,6 +673,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
*/ */
long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
{ {
struct key_user *newowner, *zapowner = NULL;
struct key *key; struct key *key;
key_ref_t key_ref; key_ref_t key_ref;
long ret; long ret;
...@@ -696,19 +697,50 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) ...@@ -696,19 +697,50 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
if (!capable(CAP_SYS_ADMIN)) { if (!capable(CAP_SYS_ADMIN)) {
/* only the sysadmin can chown a key to some other UID */ /* only the sysadmin can chown a key to some other UID */
if (uid != (uid_t) -1 && key->uid != uid) if (uid != (uid_t) -1 && key->uid != uid)
goto no_access; goto error_put;
/* only the sysadmin can set the key's GID to a group other /* only the sysadmin can set the key's GID to a group other
* than one of those that the current process subscribes to */ * than one of those that the current process subscribes to */
if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid)) if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid))
goto no_access; goto error_put;
} }
/* change the UID (have to update the quotas) */ /* change the UID */
if (uid != (uid_t) -1 && uid != key->uid) { if (uid != (uid_t) -1 && uid != key->uid) {
/* don't support UID changing yet */ ret = -ENOMEM;
ret = -EOPNOTSUPP; newowner = key_user_lookup(uid);
goto no_access; if (!newowner)
goto error_put;
/* transfer the quota burden to the new user */
if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
spin_lock(&newowner->lock);
if (newowner->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
newowner->qnbytes + key->quotalen >=
KEYQUOTA_MAX_BYTES)
goto quota_overrun;
newowner->qnkeys++;
newowner->qnbytes += key->quotalen;
spin_unlock(&newowner->lock);
spin_lock(&key->user->lock);
key->user->qnkeys--;
key->user->qnbytes -= key->quotalen;
spin_unlock(&key->user->lock);
}
atomic_dec(&key->user->nkeys);
atomic_inc(&newowner->nkeys);
if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
atomic_dec(&key->user->nikeys);
atomic_inc(&newowner->nikeys);
}
zapowner = key->user;
key->user = newowner;
key->uid = uid;
} }
/* change the GID */ /* change the GID */
...@@ -717,12 +749,20 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) ...@@ -717,12 +749,20 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
ret = 0; ret = 0;
no_access: error_put:
up_write(&key->sem); up_write(&key->sem);
key_put(key); key_put(key);
error: if (zapowner)
key_user_put(zapowner);
error:
return ret; return ret;
quota_overrun:
spin_unlock(&newowner->lock);
zapowner = newowner;
ret = -EDQUOT;
goto error_put;
} /* end keyctl_chown_key() */ } /* end keyctl_chown_key() */
/*****************************************************************************/ /*****************************************************************************/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment