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, desc, "", 0, idmap); mutex_unlock(&idmap->idmap_mutex); } + if (!IS_ERR(rkey)) + set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags); kfree(desc); 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 { #define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ #define KEY_FLAG_TRUSTED 8 /* set if key is trusted */ #define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */ +#define KEY_FLAG_ROOT_CAN_INVAL 11 /* set if key can be invalidated by root without permission */ /* the key type and key description string * - 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, } down_read(&rkey->sem); + set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags); rkey->perm |= KEY_USR_VIEW; 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) key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); + + /* Root is permitted to invalidate certain special keys */ + if (capable(CAP_SYS_ADMIN)) { + key_ref = lookup_user_key(id, 0, 0); + if (IS_ERR(key_ref)) + goto error; + if (test_bit(KEY_FLAG_ROOT_CAN_INVAL, + &key_ref_to_ptr(key_ref)->flags)) + goto invalidate; + goto error_put; + } + goto error; } +invalidate: key_invalidate(key_ref_to_ptr(key_ref)); ret = 0; - +error_put: key_ref_put(key_ref); error: kleave(" = %ld", ret);