@@ -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;
@@ -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 10 /* 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
@@ -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);
@@ -404,12 +404,25 @@ long keyctl_invalidate_key(key_serial_t id)
key_ref = lookup_user_key(id, 0, KEY_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);