Initial revision
[linux-2.6.git] / security / keys / keyctl.c
index ed71d86..0c62798 100644 (file)
 #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
@@ -61,22 +38,40 @@ asmlinkage long sys_add_key(const char __user *_type,
        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;
@@ -141,28 +136,59 @@ asmlinkage long sys_request_key(const char __user *_type,
        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 */
@@ -238,21 +264,36 @@ long keyctl_get_keyring_ID(key_serial_t id, int create)
 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;
 
@@ -525,18 +566,32 @@ long keyctl_keyring_search(key_serial_t ringid,
        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);