]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - security/keys/keyctl.c
tc-testing: add ETS scheduler to tdc build configuration
[linux.git] / security / keys / keyctl.c
index 5aa605ef8d9d1572d29207e1bb61a6fc3740788f..9b898c9695583da389c4129544081c334f679e26 100644 (file)
 
 #define KEY_MAX_DESC_SIZE 4096
 
+static const unsigned char keyrings_capabilities[2] = {
+       [0] = (KEYCTL_CAPS0_CAPABILITIES |
+              (IS_ENABLED(CONFIG_PERSISTENT_KEYRINGS)  ? KEYCTL_CAPS0_PERSISTENT_KEYRINGS : 0) |
+              (IS_ENABLED(CONFIG_KEY_DH_OPERATIONS)    ? KEYCTL_CAPS0_DIFFIE_HELLMAN : 0) |
+              (IS_ENABLED(CONFIG_ASYMMETRIC_KEY_TYPE)  ? KEYCTL_CAPS0_PUBLIC_KEY : 0) |
+              (IS_ENABLED(CONFIG_BIG_KEYS)             ? KEYCTL_CAPS0_BIG_KEY : 0) |
+              KEYCTL_CAPS0_INVALIDATE |
+              KEYCTL_CAPS0_RESTRICT_KEYRING |
+              KEYCTL_CAPS0_MOVE
+              ),
+       [1] = (KEYCTL_CAPS1_NS_KEYRING_NAME |
+              KEYCTL_CAPS1_NS_KEY_TAG),
+};
+
 static int key_get_type_from_user(char *type,
                                  const char __user *_type,
                                  unsigned len)
@@ -206,7 +220,7 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
        }
 
        /* do the search */
-       key = request_key_and_link(ktype, description, callout_info,
+       key = request_key_and_link(ktype, description, NULL, callout_info,
                                   callout_len, NULL, key_ref_to_ptr(dest_ref),
                                   KEY_ALLOC_IN_QUOTA);
        if (IS_ERR(key)) {
@@ -568,6 +582,52 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
        return ret;
 }
 
+/*
+ * Move a link to a key from one keyring to another, displacing any matching
+ * key from the destination keyring.
+ *
+ * The key must grant the caller Link permission and both keyrings must grant
+ * the caller Write permission.  There must also be a link in the from keyring
+ * to the key.  If both keyrings are the same, nothing is done.
+ *
+ * If successful, 0 will be returned.
+ */
+long keyctl_keyring_move(key_serial_t id, key_serial_t from_ringid,
+                        key_serial_t to_ringid, unsigned int flags)
+{
+       key_ref_t key_ref, from_ref, to_ref;
+       long ret;
+
+       if (flags & ~KEYCTL_MOVE_EXCL)
+               return -EINVAL;
+
+       key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_NEED_LINK);
+       if (IS_ERR(key_ref))
+               return PTR_ERR(key_ref);
+
+       from_ref = lookup_user_key(from_ringid, 0, KEY_NEED_WRITE);
+       if (IS_ERR(from_ref)) {
+               ret = PTR_ERR(from_ref);
+               goto error2;
+       }
+
+       to_ref = lookup_user_key(to_ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
+       if (IS_ERR(to_ref)) {
+               ret = PTR_ERR(to_ref);
+               goto error3;
+       }
+
+       ret = key_move(key_ref_to_ptr(key_ref), key_ref_to_ptr(from_ref),
+                      key_ref_to_ptr(to_ref), flags);
+
+       key_ref_put(to_ref);
+error3:
+       key_ref_put(from_ref);
+error2:
+       key_ref_put(key_ref);
+       return ret;
+}
+
 /*
  * Return a description of a key to userspace.
  *
@@ -700,7 +760,7 @@ long keyctl_keyring_search(key_serial_t ringid,
        }
 
        /* do the search */
-       key_ref = keyring_search(keyring_ref, ktype, description);
+       key_ref = keyring_search(keyring_ref, ktype, description, true);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
 
@@ -1520,7 +1580,8 @@ long keyctl_session_to_parent(void)
 
        ret = -EPERM;
        oldwork = NULL;
-       parent = me->real_parent;
+       parent = rcu_dereference_protected(me->real_parent,
+                                          lockdep_is_held(&tasklist_lock));
 
        /* the parent mustn't be init and mustn't be a kernel thread */
        if (parent->pid <= 1 || !parent->mm)
@@ -1627,6 +1688,26 @@ long keyctl_restrict_keyring(key_serial_t id, const char __user *_type,
        return ret;
 }
 
+/*
+ * Get keyrings subsystem capabilities.
+ */
+long keyctl_capabilities(unsigned char __user *_buffer, size_t buflen)
+{
+       size_t size = buflen;
+
+       if (size > 0) {
+               if (size > sizeof(keyrings_capabilities))
+                       size = sizeof(keyrings_capabilities);
+               if (copy_to_user(_buffer, keyrings_capabilities, size) != 0)
+                       return -EFAULT;
+               if (size < buflen &&
+                   clear_user(_buffer + size, buflen - size) != 0)
+                       return -EFAULT;
+       }
+
+       return sizeof(keyrings_capabilities);
+}
+
 /*
  * The key control system call
  */
@@ -1767,6 +1848,15 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
                        (const void __user *)arg4,
                        (const void __user *)arg5);
 
+       case KEYCTL_MOVE:
+               return keyctl_keyring_move((key_serial_t)arg2,
+                                          (key_serial_t)arg3,
+                                          (key_serial_t)arg4,
+                                          (unsigned int)arg5);
+
+       case KEYCTL_CAPABILITIES:
+               return keyctl_capabilities((unsigned char __user *)arg2, (size_t)arg3);
+
        default:
                return -EOPNOTSUPP;
        }