]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - security/keys/keyctl.c
keys: add keyctl function to get a security label
[linux-2.6-omap-h63xx.git] / security / keys / keyctl.c
index d9ca15c109ccfaa167cafc8c39dec87f2a3e305d..56e963b700b92cfe494294617a5b2e56895dd7c3 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/capability.h>
 #include <linux/string.h>
 #include <linux/err.h>
+#include <linux/vmalloc.h>
+#include <linux/security.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
@@ -62,9 +64,10 @@ asmlinkage long sys_add_key(const char __user *_type,
        char type[32], *description;
        void *payload;
        long ret;
+       bool vm;
 
        ret = -EINVAL;
-       if (plen > 32767)
+       if (plen > 1024 * 1024 - 1)
                goto error;
 
        /* draw all the data into kernel space */
@@ -81,11 +84,18 @@ asmlinkage long sys_add_key(const char __user *_type,
        /* pull the payload in if one was supplied */
        payload = NULL;
 
+       vm = false;
        if (_payload) {
                ret = -ENOMEM;
                payload = kmalloc(plen, GFP_KERNEL);
-               if (!payload)
-                       goto error2;
+               if (!payload) {
+                       if (plen <= PAGE_SIZE)
+                               goto error2;
+                       vm = true;
+                       payload = vmalloc(plen);
+                       if (!payload)
+                               goto error2;
+               }
 
                ret = -EFAULT;
                if (copy_from_user(payload, _payload, plen) != 0)
@@ -113,7 +123,10 @@ asmlinkage long sys_add_key(const char __user *_type,
 
        key_ref_put(keyring_ref);
  error3:
-       kfree(payload);
+       if (!vm)
+               kfree(payload);
+       else
+               vfree(payload);
  error2:
        kfree(description);
  error:
@@ -140,6 +153,7 @@ asmlinkage long sys_request_key(const char __user *_type,
        struct key_type *ktype;
        struct key *key;
        key_ref_t dest_ref;
+       size_t callout_len;
        char type[32], *description, *callout_info;
        long ret;
 
@@ -157,12 +171,14 @@ asmlinkage long sys_request_key(const char __user *_type,
 
        /* pull the callout info into kernel space */
        callout_info = NULL;
+       callout_len = 0;
        if (_callout_info) {
                callout_info = strndup_user(_callout_info, PAGE_SIZE);
                if (IS_ERR(callout_info)) {
                        ret = PTR_ERR(callout_info);
                        goto error2;
                }
+               callout_len = strlen(callout_info);
        }
 
        /* get the destination keyring if specified */
@@ -183,8 +199,8 @@ asmlinkage long sys_request_key(const char __user *_type,
        }
 
        /* do the search */
-       key = request_key_and_link(ktype, description, callout_info, NULL,
-                                  key_ref_to_ptr(dest_ref),
+       key = request_key_and_link(ktype, description, callout_info,
+                                  callout_len, NULL, key_ref_to_ptr(dest_ref),
                                   KEY_ALLOC_IN_QUOTA);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
@@ -821,9 +837,10 @@ long keyctl_instantiate_key(key_serial_t id,
        key_ref_t keyring_ref;
        void *payload;
        long ret;
+       bool vm = false;
 
        ret = -EINVAL;
-       if (plen > 32767)
+       if (plen > 1024 * 1024 - 1)
                goto error;
 
        /* the appropriate instantiation authorisation key must have been
@@ -843,8 +860,14 @@ long keyctl_instantiate_key(key_serial_t id,
        if (_payload) {
                ret = -ENOMEM;
                payload = kmalloc(plen, GFP_KERNEL);
-               if (!payload)
-                       goto error;
+               if (!payload) {
+                       if (plen <= PAGE_SIZE)
+                               goto error;
+                       vm = true;
+                       payload = vmalloc(plen);
+                       if (!payload)
+                               goto error;
+               }
 
                ret = -EFAULT;
                if (copy_from_user(payload, _payload, plen) != 0)
@@ -877,7 +900,10 @@ long keyctl_instantiate_key(key_serial_t id,
        }
 
 error2:
-       kfree(payload);
+       if (!vm)
+               kfree(payload);
+       else
+               vfree(payload);
 error:
        return ret;
 
@@ -1055,6 +1081,66 @@ error:
 
 } /* end keyctl_assume_authority() */
 
+/*
+ * get the security label of a key
+ * - the key must grant us view permission
+ * - if there's a buffer, we place up to buflen bytes of data into it
+ * - unless there's an error, we return the amount of information available,
+ *   irrespective of how much we may have copied (including the terminal NUL)
+ * - implements keyctl(KEYCTL_GET_SECURITY)
+ */
+long keyctl_get_security(key_serial_t keyid,
+                        char __user *buffer,
+                        size_t buflen)
+{
+       struct key *key, *instkey;
+       key_ref_t key_ref;
+       char *context;
+       long ret;
+
+       key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
+       if (IS_ERR(key_ref)) {
+               if (PTR_ERR(key_ref) != -EACCES)
+                       return PTR_ERR(key_ref);
+
+               /* viewing a key under construction is also permitted if we
+                * have the authorisation token handy */
+               instkey = key_get_instantiation_authkey(keyid);
+               if (IS_ERR(instkey))
+                       return PTR_ERR(key_ref);
+               key_put(instkey);
+
+               key_ref = lookup_user_key(NULL, keyid, 0, 1, 0);
+               if (IS_ERR(key_ref))
+                       return PTR_ERR(key_ref);
+       }
+
+       key = key_ref_to_ptr(key_ref);
+       ret = security_key_getsecurity(key, &context);
+       if (ret == 0) {
+               /* if no information was returned, give userspace an empty
+                * string */
+               ret = 1;
+               if (buffer && buflen > 0 &&
+                   copy_to_user(buffer, "", 1) != 0)
+                       ret = -EFAULT;
+       } else if (ret > 0) {
+               /* return as much data as there's room for */
+               if (buffer && buflen > 0) {
+                       if (buflen > ret)
+                               buflen = ret;
+
+                       if (copy_to_user(buffer, context, buflen) != 0)
+                               ret = -EFAULT;
+               }
+
+               kfree(context);
+       }
+
+       key_ref_put(key_ref);
+       return ret;
+}
+
 /*****************************************************************************/
 /*
  * the key control system call
@@ -1135,6 +1221,11 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3,
        case KEYCTL_ASSUME_AUTHORITY:
                return keyctl_assume_authority((key_serial_t) arg2);
 
+       case KEYCTL_GET_SECURITY:
+               return keyctl_get_security((key_serial_t) arg2,
+                                          (char *) arg3,
+                                          (size_t) arg4);
+
        default:
                return -EOPNOTSUPP;
        }