#include <linux/keyctl.h>
#include <linux/fs.h>
#include <linux/capability.h>
-#include <linux/string.h>
#include <linux/err.h>
#include <asm/uaccess.h>
#include "internal.h"
-static int key_get_type_from_user(char *type,
- const char __user *_type,
- unsigned len)
-{
- int ret;
-
- ret = strncpy_from_user(type, _type, len);
-
- if (ret < 0)
- return -EFAULT;
-
- if (ret == 0 || ret >= len)
- return -EINVAL;
-
- if (type[0] == '.')
- return -EPERM;
-
- type[len - 1] = '\0';
-
- return 0;
-}
-
/*****************************************************************************/
/*
* extract the description of a new key from userspace and either add it as a
key_ref_t keyring_ref, key_ref;
char type[32], *description;
void *payload;
- long ret;
+ long dlen, ret;
ret = -EINVAL;
if (plen > 32767)
goto error;
/* draw all the data into kernel space */
- ret = key_get_type_from_user(type, _type, sizeof(type));
+ ret = strncpy_from_user(type, _type, sizeof(type) - 1);
if (ret < 0)
goto error;
+ type[31] = '\0';
- description = strndup_user(_description, PAGE_SIZE);
- if (IS_ERR(description)) {
- ret = PTR_ERR(description);
+ ret = -EPERM;
+ if (type[0] == '.')
+ goto error;
+
+ ret = -EFAULT;
+ dlen = strnlen_user(_description, PAGE_SIZE - 1);
+ if (dlen <= 0)
+ goto error;
+
+ ret = -EINVAL;
+ if (dlen > PAGE_SIZE - 1)
goto error;
- }
+
+ ret = -ENOMEM;
+ description = kmalloc(dlen + 1, GFP_KERNEL);
+ if (!description)
+ goto error;
+ description[dlen] = '\0';
+
+ ret = -EFAULT;
+ if (copy_from_user(description, _description, dlen) != 0)
+ goto error2;
/* pull the payload in if one was supplied */
payload = NULL;
/* create or update the requested key and add it to the target
* keyring */
key_ref = key_create_or_update(keyring_ref, type, description,
- payload, plen, KEY_ALLOC_IN_QUOTA);
+ payload, plen, 0);
if (!IS_ERR(key_ref)) {
ret = key_ref_to_ptr(key_ref)->serial;
key_ref_put(key_ref);
struct key *key;
key_ref_t dest_ref;
char type[32], *description, *callout_info;
- long ret;
+ long dlen, ret;
/* pull the type into kernel space */
- ret = key_get_type_from_user(type, _type, sizeof(type));
+ ret = strncpy_from_user(type, _type, sizeof(type) - 1);
if (ret < 0)
goto error;
+ type[31] = '\0';
+
+ ret = -EPERM;
+ if (type[0] == '.')
+ goto error;
/* pull the description into kernel space */
- description = strndup_user(_description, PAGE_SIZE);
- if (IS_ERR(description)) {
- ret = PTR_ERR(description);
+ ret = -EFAULT;
+ dlen = strnlen_user(_description, PAGE_SIZE - 1);
+ if (dlen <= 0)
goto error;
- }
+
+ ret = -EINVAL;
+ if (dlen > PAGE_SIZE - 1)
+ goto error;
+
+ ret = -ENOMEM;
+ description = kmalloc(dlen + 1, GFP_KERNEL);
+ if (!description)
+ goto error;
+ description[dlen] = '\0';
+
+ ret = -EFAULT;
+ if (copy_from_user(description, _description, dlen) != 0)
+ goto error2;
/* pull the callout info into kernel space */
callout_info = NULL;
if (_callout_info) {
- callout_info = strndup_user(_callout_info, PAGE_SIZE);
- if (IS_ERR(callout_info)) {
- ret = PTR_ERR(callout_info);
+ ret = -EFAULT;
+ dlen = strnlen_user(_callout_info, PAGE_SIZE - 1);
+ if (dlen <= 0)
goto error2;
- }
+
+ ret = -EINVAL;
+ if (dlen > PAGE_SIZE - 1)
+ goto error2;
+
+ ret = -ENOMEM;
+ callout_info = kmalloc(dlen + 1, GFP_KERNEL);
+ if (!callout_info)
+ goto error2;
+ callout_info[dlen] = '\0';
+
+ ret = -EFAULT;
+ if (copy_from_user(callout_info, _callout_info, dlen) != 0)
+ goto error3;
}
/* get the destination keyring if specified */
}
/* do the search */
- key = request_key_and_link(ktype, description, callout_info, NULL,
- key_ref_to_ptr(dest_ref),
- KEY_ALLOC_IN_QUOTA);
+ key = request_key_and_link(ktype, description, callout_info,
+ key_ref_to_ptr(dest_ref));
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error5;
long keyctl_join_session_keyring(const char __user *_name)
{
char *name;
- long ret;
+ long nlen, ret;
/* fetch the name from userspace */
name = NULL;
if (_name) {
- name = strndup_user(_name, PAGE_SIZE);
- if (IS_ERR(name)) {
- ret = PTR_ERR(name);
+ ret = -EFAULT;
+ nlen = strnlen_user(_name, PAGE_SIZE - 1);
+ if (nlen <= 0)
goto error;
- }
+
+ ret = -EINVAL;
+ if (nlen > PAGE_SIZE - 1)
+ goto error;
+
+ ret = -ENOMEM;
+ name = kmalloc(nlen + 1, GFP_KERNEL);
+ if (!name)
+ goto error;
+ name[nlen] = '\0';
+
+ ret = -EFAULT;
+ if (copy_from_user(name, _name, nlen) != 0)
+ goto error2;
}
/* join the session */
ret = join_session_keyring(name);
+ error2:
+ kfree(name);
error:
return ret;
struct key_type *ktype;
key_ref_t keyring_ref, key_ref, dest_ref;
char type[32], *description;
- long ret;
+ long dlen, ret;
/* pull the type and description into kernel space */
- ret = key_get_type_from_user(type, _type, sizeof(type));
+ ret = strncpy_from_user(type, _type, sizeof(type) - 1);
if (ret < 0)
goto error;
+ type[31] = '\0';
- description = strndup_user(_description, PAGE_SIZE);
- if (IS_ERR(description)) {
- ret = PTR_ERR(description);
+ ret = -EFAULT;
+ dlen = strnlen_user(_description, PAGE_SIZE - 1);
+ if (dlen <= 0)
goto error;
- }
+
+ ret = -EINVAL;
+ if (dlen > PAGE_SIZE - 1)
+ goto error;
+
+ ret = -ENOMEM;
+ description = kmalloc(dlen + 1, GFP_KERNEL);
+ if (!description)
+ goto error;
+ description[dlen] = '\0';
+
+ ret = -EFAULT;
+ if (copy_from_user(description, _description, dlen) != 0)
+ goto error2;
/* get the keyring at which to begin the search */
keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
*/
long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
{
- struct key_user *newowner, *zapowner = NULL;
struct key *key;
key_ref_t key_ref;
long ret;
if (!capable(CAP_SYS_ADMIN)) {
/* only the sysadmin can chown a key to some other UID */
if (uid != (uid_t) -1 && key->uid != uid)
- goto error_put;
+ goto no_access;
/* only the sysadmin can set the key's GID to a group other
* than one of those that the current process subscribes to */
if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid))
- goto error_put;
+ goto no_access;
}
- /* change the UID */
+ /* change the UID (have to update the quotas) */
if (uid != (uid_t) -1 && uid != key->uid) {
- ret = -ENOMEM;
- newowner = key_user_lookup(uid);
- 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;
+ /* don't support UID changing yet */
+ ret = -EOPNOTSUPP;
+ goto no_access;
}
/* change the GID */
ret = 0;
-error_put:
+ no_access:
up_write(&key->sem);
key_put(key);
- if (zapowner)
- key_user_put(zapowner);
-error:
+ error:
return ret;
-quota_overrun:
- spin_unlock(&newowner->lock);
- zapowner = newowner;
- ret = -EDQUOT;
- goto error_put;
-
} /* end keyctl_chown_key() */
/*****************************************************************************/