]> Pileus Git - ~andy/linux/blobdiff - security/keys/keyctl.c
Merge tag 'nfs-for-3.4-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[~andy/linux] / security / keys / keyctl.c
index 0b3f5d72af1cecbd06b33c2151ec570a4cfaa2ee..fb767c6cd99f6a92da8fa989999a18988bce1a19 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/syscalls.h>
+#include <linux/key.h>
 #include <linux/keyctl.h>
 #include <linux/fs.h>
 #include <linux/capability.h>
@@ -388,11 +389,24 @@ long keyctl_keyring_clear(key_serial_t ringid)
        keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
        if (IS_ERR(keyring_ref)) {
                ret = PTR_ERR(keyring_ref);
+
+               /* Root is permitted to invalidate certain special keyrings */
+               if (capable(CAP_SYS_ADMIN)) {
+                       keyring_ref = lookup_user_key(ringid, 0, 0);
+                       if (IS_ERR(keyring_ref))
+                               goto error;
+                       if (test_bit(KEY_FLAG_ROOT_CAN_CLEAR,
+                                    &key_ref_to_ptr(keyring_ref)->flags))
+                               goto clear;
+                       goto error_put;
+               }
+
                goto error;
        }
 
+clear:
        ret = keyring_clear(key_ref_to_ptr(keyring_ref));
-
+error_put:
        key_ref_put(keyring_ref);
 error:
        return ret;
@@ -1244,10 +1258,8 @@ error:
  */
 long keyctl_set_timeout(key_serial_t id, unsigned timeout)
 {
-       struct timespec now;
        struct key *key, *instkey;
        key_ref_t key_ref;
-       time_t expiry;
        long ret;
 
        key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
@@ -1273,20 +1285,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
 
 okay:
        key = key_ref_to_ptr(key_ref);
-
-       /* make the changes with the locks held to prevent races */
-       down_write(&key->sem);
-
-       expiry = 0;
-       if (timeout > 0) {
-               now = current_kernel_time();
-               expiry = now.tv_sec + timeout;
-       }
-
-       key->expiry = expiry;
-       key_schedule_gc(key->expiry + key_gc_delay);
-
-       up_write(&key->sem);
+       key_set_timeout(key, timeout);
        key_put(key);
 
        ret = 0;