aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2014-07-17 15:45:08 -0400
committerDavid Howells <dhowells@redhat.com>2014-07-17 15:45:08 -0400
commit0c7774abb41bd00d5836d9ba098825a40fa94133 (patch)
treed3c6cb9e81dd798b7383ed47a5fd5499b772a3ea
parentb6b8a371f5541c2b839caba84fede693f3fcc43d (diff)
KEYS: Allow special keys (eg. DNS results) to be invalidated by CAP_SYS_ADMIN
Special kernel keys, such as those used to hold DNS results for AFS, CIFS and NFS and those used to hold idmapper results for NFS, used to be 'invalidateable' with key_revoke(). However, since the default permissions for keys were reduced: Commit: 96b5c8fea6c0861621051290d705ec2e971963f1 KEYS: Reduce initial permissions on keys it has become impossible to do this. Add a key flag (KEY_FLAG_ROOT_CAN_INVAL) that will permit a key to be invalidated by root. This should not be used for system keyrings as the garbage collector will try and remove any invalidate key. For system keyrings, KEY_FLAG_ROOT_CAN_CLEAR can be used instead. After this, from userspace, keyctl_invalidate() and "keyctl invalidate" can be used by any possessor of CAP_SYS_ADMIN (typically root) to invalidate DNS and idmapper keys. Invalidated keys are immediately garbage collected and will be immediately rerequested if needed again. Signed-off-by: David Howells <dhowells@redhat.com> Tested-by: Steve Dickson <steved@redhat.com>
-rw-r--r--fs/nfs/idmap.c2
-rw-r--r--include/linux/key.h1
-rw-r--r--net/dns_resolver/dns_query.c1
-rw-r--r--security/keys/keyctl.c15
4 files changed, 18 insertions, 1 deletions
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index 567983d2c0eb..b7458d77f511 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -282,6 +282,8 @@ static struct key *nfs_idmap_request_key(const char *name, size_t namelen,
282 desc, "", 0, idmap); 282 desc, "", 0, idmap);
283 mutex_unlock(&idmap->idmap_mutex); 283 mutex_unlock(&idmap->idmap_mutex);
284 } 284 }
285 if (!IS_ERR(rkey))
286 set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags);
285 287
286 kfree(desc); 288 kfree(desc);
287 return rkey; 289 return rkey;
diff --git a/include/linux/key.h b/include/linux/key.h
index 017b0826642f..e37a4d807185 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -170,6 +170,7 @@ struct key {
170#define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ 170#define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */
171#define KEY_FLAG_TRUSTED 8 /* set if key is trusted */ 171#define KEY_FLAG_TRUSTED 8 /* set if key is trusted */
172#define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */ 172#define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */
173#define KEY_FLAG_ROOT_CAN_INVAL 11 /* set if key can be invalidated by root without permission */
173 174
174 /* the key type and key description string 175 /* the key type and key description string
175 * - the desc is used to match a key against search criteria 176 * - the desc is used to match a key against search criteria
diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c
index 9acec61f5433..9a32f55cf9b9 100644
--- a/net/dns_resolver/dns_query.c
+++ b/net/dns_resolver/dns_query.c
@@ -129,6 +129,7 @@ int dns_query(const char *type, const char *name, size_t namelen,
129 } 129 }
130 130
131 down_read(&rkey->sem); 131 down_read(&rkey->sem);
132 set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags);
132 rkey->perm |= KEY_USR_VIEW; 133 rkey->perm |= KEY_USR_VIEW;
133 134
134 ret = key_validate(rkey); 135 ret = key_validate(rkey);
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index cd5bd0cef25d..609f8d326ddc 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -404,12 +404,25 @@ long keyctl_invalidate_key(key_serial_t id)
404 key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH); 404 key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH);
405 if (IS_ERR(key_ref)) { 405 if (IS_ERR(key_ref)) {
406 ret = PTR_ERR(key_ref); 406 ret = PTR_ERR(key_ref);
407
408 /* Root is permitted to invalidate certain special keys */
409 if (capable(CAP_SYS_ADMIN)) {
410 key_ref = lookup_user_key(id, 0, 0);
411 if (IS_ERR(key_ref))
412 goto error;
413 if (test_bit(KEY_FLAG_ROOT_CAN_INVAL,
414 &key_ref_to_ptr(key_ref)->flags))
415 goto invalidate;
416 goto error_put;
417 }
418
407 goto error; 419 goto error;
408 } 420 }
409 421
422invalidate:
410 key_invalidate(key_ref_to_ptr(key_ref)); 423 key_invalidate(key_ref_to_ptr(key_ref));
411 ret = 0; 424 ret = 0;
412 425error_put:
413 key_ref_put(key_ref); 426 key_ref_put(key_ref);
414error: 427error:
415 kleave(" = %ld", ret); 428 kleave(" = %ld", ret);