Commit 700920eb5ba4de5417b446c9a8bb008df2b973e0

Authored by David Howells
Committed by James Morris
1 parent 53999bf34d

KEYS: Allow special keyrings to be cleared

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>

Showing 7 changed files with 26 additions and 1 deletions Side-by-side Diff

Documentation/networking/dns_resolver.txt
... ... @@ -102,6 +102,10 @@
102 102 If _expiry is non-NULL, the expiry time (TTL) of the result will be
103 103 returned also.
104 104  
  105 +The kernel maintains an internal keyring in which it caches looked up keys.
  106 +This can be cleared by any process that has the CAP_SYS_ADMIN capability by
  107 +the use of KEYCTL_KEYRING_CLEAR on the keyring ID.
  108 +
105 109  
106 110 ===============================
107 111 READING DNS KEYS FROM USERSPACE
Documentation/security/keys.txt
... ... @@ -554,6 +554,10 @@
554 554 process must have write permission on the keyring, and it must be a
555 555 keyring (or else error ENOTDIR will result).
556 556  
  557 + This function can also be used to clear special kernel keyrings if they
  558 + are appropriately marked if the user has CAP_SYS_ADMIN capability. The
  559 + DNS resolver cache keyring is an example of this.
  560 +
557 561  
558 562 (*) Link a key into a keyring:
559 563  
... ... @@ -556,6 +556,7 @@
556 556  
557 557 /* instruct request_key() to use this special keyring as a cache for
558 558 * the results it looks up */
  559 + set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
559 560 cred->thread_keyring = keyring;
560 561 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
561 562 root_cred = cred;
... ... @@ -198,6 +198,7 @@
198 198 if (ret < 0)
199 199 goto failed_put_key;
200 200  
  201 + set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
201 202 cred->thread_keyring = keyring;
202 203 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
203 204 id_resolver_cache = cred;
... ... @@ -155,6 +155,7 @@
155 155 #define KEY_FLAG_IN_QUOTA 3 /* set if key consumes quota */
156 156 #define KEY_FLAG_USER_CONSTRUCT 4 /* set if key is being constructed in userspace */
157 157 #define KEY_FLAG_NEGATIVE 5 /* set if key is negative */
  158 +#define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */
158 159  
159 160 /* the description string
160 161 * - this is used to match a key against search criteria
net/dns_resolver/dns_key.c
... ... @@ -281,6 +281,7 @@
281 281  
282 282 /* instruct request_key() to use this special keyring as a cache for
283 283 * the results it looks up */
  284 + set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
284 285 cred->thread_keyring = keyring;
285 286 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
286 287 dns_resolver_cache = cred;
security/keys/keyctl.c
... ... @@ -388,11 +388,24 @@
388 388 keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
389 389 if (IS_ERR(keyring_ref)) {
390 390 ret = PTR_ERR(keyring_ref);
  391 +
  392 + /* Root is permitted to invalidate certain special keyrings */
  393 + if (capable(CAP_SYS_ADMIN)) {
  394 + keyring_ref = lookup_user_key(ringid, 0, 0);
  395 + if (IS_ERR(keyring_ref))
  396 + goto error;
  397 + if (test_bit(KEY_FLAG_ROOT_CAN_CLEAR,
  398 + &key_ref_to_ptr(keyring_ref)->flags))
  399 + goto clear;
  400 + goto error_put;
  401 + }
  402 +
391 403 goto error;
392 404 }
393 405  
  406 +clear:
394 407 ret = keyring_clear(key_ref_to_ptr(keyring_ref));
395   -
  408 +error_put:
396 409 key_ref_put(keyring_ref);
397 410 error:
398 411 return ret;