KEYS: Allow special keyrings to be cleared
authorDavid Howells <dhowells@redhat.com>
Wed, 18 Jan 2012 15:31:45 +0000 (15:31 +0000)
committerJames Morris <jmorris@namei.org>
Thu, 19 Jan 2012 03:38:51 +0000 (14:38 +1100)
The kernel contains some special internal keyrings, for instance the DNS
resolver keyring :

2a93faf1 I-----     1 perm 1f030000     0     0 keyring   .dns_resolver: empty

It would occasionally be useful to allow the contents of such keyrings to be
flushed by root (cache invalidation).

Allow a flag to be set on a keyring to mark that someone possessing the
sysadmin capability can clear the keyring, even without normal write access to
the keyring.

Set this flag on the special keyrings created by the DNS resolver, the NFS
identity mapper and the CIFS identity mapper.

Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Jeff Layton <jlayton@redhat.com>
Acked-by: Steve Dickson <steved@redhat.com>
Signed-off-by: James Morris <jmorris@namei.org>
Documentation/networking/dns_resolver.txt
Documentation/security/keys.txt
fs/cifs/cifsacl.c
fs/nfs/idmap.c
include/linux/key.h
net/dns_resolver/dns_key.c
security/keys/keyctl.c

index 7f531ad83285ced1d2cc24d513d611e0c8156c47..d86adcdae4202a9b502073ef03fa058f46136306 100644 (file)
@@ -102,6 +102,10 @@ implemented in the module can be called after doing:
      If _expiry is non-NULL, the expiry time (TTL) of the result will be
      returned also.
 
+The kernel maintains an internal keyring in which it caches looked up keys.
+This can be cleared by any process that has the CAP_SYS_ADMIN capability by
+the use of KEYCTL_KEYRING_CLEAR on the keyring ID.
+
 
 ===============================
 READING DNS KEYS FROM USERSPACE
index 4d75931d2d79e7febde59664b005798827df6d26..713ec232c5623ec1efa2542c127ccc09169b9c8e 100644 (file)
@@ -554,6 +554,10 @@ The keyctl syscall functions are:
      process must have write permission on the keyring, and it must be a
      keyring (or else error ENOTDIR will result).
 
+     This function can also be used to clear special kernel keyrings if they
+     are appropriately marked if the user has CAP_SYS_ADMIN capability.  The
+     DNS resolver cache keyring is an example of this.
+
 
  (*) Link a key into a keyring:
 
index 72ddf23ef6f7d77145dbe765732633ff8e588076..854749d21bb1a6a28496e88b0061fbe98a2693b2 100644 (file)
@@ -556,6 +556,7 @@ init_cifs_idmap(void)
 
        /* instruct request_key() to use this special keyring as a cache for
         * the results it looks up */
+       set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
        cred->thread_keyring = keyring;
        cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
        root_cred = cred;
index 2c05f1991e1e1c3664c8ffb9f0159687b53b8449..a1bbf7780dfcec3e1a1dd0c608d3e88842db8820 100644 (file)
@@ -198,6 +198,7 @@ int nfs_idmap_init(void)
        if (ret < 0)
                goto failed_put_key;
 
+       set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
        cred->thread_keyring = keyring;
        cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
        id_resolver_cache = cred;
index 183a6af7715d341bb5ffa9c8ebb3428d44f93cc8..3ac412855d835feb05552cd09ddf37be3c7837f5 100644 (file)
@@ -155,6 +155,7 @@ struct key {
 #define KEY_FLAG_IN_QUOTA      3       /* set if key consumes quota */
 #define KEY_FLAG_USER_CONSTRUCT        4       /* set if key is being constructed in userspace */
 #define KEY_FLAG_NEGATIVE      5       /* set if key is negative */
+#define KEY_FLAG_ROOT_CAN_CLEAR        6       /* set if key can be cleared by root without permission */
 
        /* the description string
         * - this is used to match a key against search criteria
index fa000d26dc6097220fe8bf53ed7cfc822afc31a0..c73bba326d709c17af88329d593465c04e2246cc 100644 (file)
@@ -281,6 +281,7 @@ static int __init init_dns_resolver(void)
 
        /* instruct request_key() to use this special keyring as a cache for
         * the results it looks up */
+       set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
        cred->thread_keyring = keyring;
        cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
        dns_resolver_cache = cred;
index 0b3f5d72af1cecbd06b33c2151ec570a4cfaa2ee..6523599e9ac0e08d7911c1fb007cc1971d1334a6 100644 (file)
@@ -388,11 +388,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;