Dave Jones f3fbdcb
diff -up linux-3.1.x86_64/Documentation/networking/dns_resolver.txt.orig linux-3.1.x86_64/Documentation/networking/dns_resolver.txt
Dave Jones f3fbdcb
--- linux-3.1.x86_64/Documentation/networking/dns_resolver.txt.orig	2011-10-24 03:10:05.000000000 -0400
Dave Jones f3fbdcb
+++ linux-3.1.x86_64/Documentation/networking/dns_resolver.txt	2011-12-13 15:09:35.705766078 -0500
Dave Jones f3fbdcb
@@ -102,6 +102,10 @@ implemented in the module can be called
Dave Jones f3fbdcb
      If _expiry is non-NULL, the expiry time (TTL) of the result will be
Dave Jones f3fbdcb
      returned also.
Dave Jones f3fbdcb
 
Dave Jones f3fbdcb
+The kernel maintains an internal keyring in which it caches looked up keys.
Dave Jones f3fbdcb
+This can be cleared by any process that has the CAP_SYS_ADMIN capability by
Dave Jones f3fbdcb
+the use of KEYCTL_KEYRING_CLEAR on the keyring ID.
Dave Jones f3fbdcb
+
Dave Jones f3fbdcb
 
Dave Jones f3fbdcb
 ===============================
Dave Jones f3fbdcb
 READING DNS KEYS FROM USERSPACE
Dave Jones f3fbdcb
diff -up linux-3.1.x86_64/Documentation/security/keys.txt.orig linux-3.1.x86_64/Documentation/security/keys.txt
Dave Jones f3fbdcb
--- linux-3.1.x86_64/Documentation/security/keys.txt.orig	2011-10-24 03:10:05.000000000 -0400
Dave Jones f3fbdcb
+++ linux-3.1.x86_64/Documentation/security/keys.txt	2011-12-13 15:09:35.706766099 -0500
Dave Jones f3fbdcb
@@ -554,6 +554,10 @@ The keyctl syscall functions are:
Dave Jones f3fbdcb
      process must have write permission on the keyring, and it must be a
Dave Jones f3fbdcb
      keyring (or else error ENOTDIR will result).
Dave Jones f3fbdcb
 
Dave Jones f3fbdcb
+     This function can also be used to clear special kernel keyrings if they
Dave Jones f3fbdcb
+     are appropriately marked if the user has CAP_SYS_ADMIN capability.  The
Dave Jones f3fbdcb
+     DNS resolver cache keyring is an example of this.
Dave Jones f3fbdcb
+
Dave Jones f3fbdcb
 
Dave Jones f3fbdcb
  (*) Link a key into a keyring:
Dave Jones f3fbdcb
 
Dave Jones f3fbdcb
diff -up linux-3.1.x86_64/fs/cifs/cifsacl.c.orig linux-3.1.x86_64/fs/cifs/cifsacl.c
Dave Jones f3fbdcb
--- linux-3.1.x86_64/fs/cifs/cifsacl.c.orig	2011-12-13 12:54:12.221145867 -0500
Dave Jones f3fbdcb
+++ linux-3.1.x86_64/fs/cifs/cifsacl.c	2011-12-13 15:09:35.707766122 -0500
Dave Jones f3fbdcb
@@ -556,6 +556,7 @@ init_cifs_idmap(void)
Dave Jones f3fbdcb
 
Dave Jones f3fbdcb
 	/* instruct request_key() to use this special keyring as a cache for
Dave Jones f3fbdcb
 	 * the results it looks up */
Dave Jones f3fbdcb
+	set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Dave Jones f3fbdcb
 	cred->thread_keyring = keyring;
Dave Jones f3fbdcb
 	cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
Dave Jones f3fbdcb
 	root_cred = cred;
Dave Jones f3fbdcb
diff -up linux-3.1.x86_64/fs/nfs/idmap.c.orig linux-3.1.x86_64/fs/nfs/idmap.c
Dave Jones f3fbdcb
--- linux-3.1.x86_64/fs/nfs/idmap.c.orig	2011-12-13 12:54:14.657203507 -0500
Dave Jones f3fbdcb
+++ linux-3.1.x86_64/fs/nfs/idmap.c	2011-12-13 15:10:14.731681691 -0500
Dave Jones f3fbdcb
@@ -115,6 +115,7 @@ int nfs_idmap_init(void)
Dave Jones f3fbdcb
 	if (ret < 0)
Dave Jones f3fbdcb
 		goto failed_put_key;
Dave Jones f3fbdcb
 
Dave Jones f3fbdcb
+	set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Dave Jones f3fbdcb
 	cred->thread_keyring = keyring;
Dave Jones f3fbdcb
 	cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
Dave Jones f3fbdcb
 	id_resolver_cache = cred;
Dave Jones f3fbdcb
@@ -185,7 +186,7 @@ static ssize_t nfs_idmap_request_key(con
Dave Jones f3fbdcb
 	}
Dave Jones f3fbdcb
 
Dave Jones f3fbdcb
 	rcu_read_lock();
Dave Jones f3fbdcb
-	rkey->perm |= KEY_USR_VIEW;
Dave Jones f3fbdcb
+	rkey->perm |= KEY_USR_VIEW|KEY_USR_WRITE;
Dave Jones f3fbdcb
 
Dave Jones f3fbdcb
 	ret = key_validate(rkey);
Dave Jones f3fbdcb
 	if (ret < 0)
Dave Jones f3fbdcb
diff -up linux-3.1.x86_64/include/linux/key.h.orig linux-3.1.x86_64/include/linux/key.h
Dave Jones f3fbdcb
--- linux-3.1.x86_64/include/linux/key.h.orig	2011-10-24 03:10:05.000000000 -0400
Dave Jones f3fbdcb
+++ linux-3.1.x86_64/include/linux/key.h	2011-12-13 15:09:35.748767078 -0500
Dave Jones f3fbdcb
@@ -155,6 +155,7 @@ struct key {
Dave Jones f3fbdcb
 #define KEY_FLAG_IN_QUOTA	3	/* set if key consumes quota */
Dave Jones f3fbdcb
 #define KEY_FLAG_USER_CONSTRUCT	4	/* set if key is being constructed in userspace */
Dave Jones f3fbdcb
 #define KEY_FLAG_NEGATIVE	5	/* set if key is negative */
Dave Jones f3fbdcb
+#define KEY_FLAG_ROOT_CAN_CLEAR	6	/* set if key can be cleared by root without permission */
Dave Jones f3fbdcb
 
Dave Jones f3fbdcb
 	/* the description string
Dave Jones f3fbdcb
 	 * - this is used to match a key against search criteria
Dave Jones f3fbdcb
diff -up linux-3.1.x86_64/net/dns_resolver/dns_key.c.orig linux-3.1.x86_64/net/dns_resolver/dns_key.c
Dave Jones f3fbdcb
--- linux-3.1.x86_64/net/dns_resolver/dns_key.c.orig	2011-10-24 03:10:05.000000000 -0400
Dave Jones f3fbdcb
+++ linux-3.1.x86_64/net/dns_resolver/dns_key.c	2011-12-13 15:09:35.748767078 -0500
Dave Jones f3fbdcb
@@ -281,6 +281,7 @@ static int __init init_dns_resolver(void
Dave Jones f3fbdcb
 
Dave Jones f3fbdcb
 	/* instruct request_key() to use this special keyring as a cache for
Dave Jones f3fbdcb
 	 * the results it looks up */
Dave Jones f3fbdcb
+	set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Dave Jones f3fbdcb
 	cred->thread_keyring = keyring;
Dave Jones f3fbdcb
 	cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
Dave Jones f3fbdcb
 	dns_resolver_cache = cred;
Dave Jones f3fbdcb
diff -up linux-3.1.x86_64/security/keys/keyctl.c.orig linux-3.1.x86_64/security/keys/keyctl.c
Dave Jones f3fbdcb
--- linux-3.1.x86_64/security/keys/keyctl.c.orig	2011-12-13 12:54:30.322571289 -0500
Dave Jones f3fbdcb
+++ linux-3.1.x86_64/security/keys/keyctl.c	2011-12-13 15:09:35.756767271 -0500
Dave Jones f3fbdcb
@@ -388,11 +388,24 @@ long keyctl_keyring_clear(key_serial_t r
Dave Jones f3fbdcb
 	keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
Dave Jones f3fbdcb
 	if (IS_ERR(keyring_ref)) {
Dave Jones f3fbdcb
 		ret = PTR_ERR(keyring_ref);
Dave Jones f3fbdcb
+
Dave Jones f3fbdcb
+		/* Root is permitted to invalidate certain special keyrings */
Dave Jones f3fbdcb
+		if (capable(CAP_SYS_ADMIN)) {
Dave Jones f3fbdcb
+			keyring_ref = lookup_user_key(ringid, 0, 0);
Dave Jones f3fbdcb
+			if (IS_ERR(keyring_ref))
Dave Jones f3fbdcb
+				goto error;
Dave Jones f3fbdcb
+			if (test_bit(KEY_FLAG_ROOT_CAN_CLEAR,
Dave Jones f3fbdcb
+				     &key_ref_to_ptr(keyring_ref)->flags))
Dave Jones f3fbdcb
+				goto clear;
Dave Jones f3fbdcb
+			goto error_put;
Dave Jones f3fbdcb
+		}
Dave Jones f3fbdcb
+
Dave Jones f3fbdcb
 		goto error;
Dave Jones f3fbdcb
 	}
Dave Jones f3fbdcb
 
Dave Jones f3fbdcb
+clear:
Dave Jones f3fbdcb
 	ret = keyring_clear(key_ref_to_ptr(keyring_ref));
Dave Jones f3fbdcb
-
Dave Jones f3fbdcb
+error_put:
Dave Jones f3fbdcb
 	key_ref_put(keyring_ref);
Dave Jones f3fbdcb
 error:
Dave Jones f3fbdcb
 	return ret;