diff options
Diffstat (limited to 'kernel/security/keys/permission.c')
-rw-r--r-- | kernel/security/keys/permission.c | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/kernel/security/keys/permission.c b/kernel/security/keys/permission.c new file mode 100644 index 000000000..732cc0bef --- /dev/null +++ b/kernel/security/keys/permission.c @@ -0,0 +1,110 @@ +/* Key permission checking + * + * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/security.h> +#include "internal.h" + +/** + * key_task_permission - Check a key can be used + * @key_ref: The key to check. + * @cred: The credentials to use. + * @perm: The permissions to check for. + * + * Check to see whether permission is granted to use a key in the desired way, + * but permit the security modules to override. + * + * The caller must hold either a ref on cred or must hold the RCU readlock. + * + * Returns 0 if successful, -EACCES if access is denied based on the + * permissions bits or the LSM check. + */ +int key_task_permission(const key_ref_t key_ref, const struct cred *cred, + unsigned perm) +{ + struct key *key; + key_perm_t kperm; + int ret; + + key = key_ref_to_ptr(key_ref); + + /* use the second 8-bits of permissions for keys the caller owns */ + if (uid_eq(key->uid, cred->fsuid)) { + kperm = key->perm >> 16; + goto use_these_perms; + } + + /* use the third 8-bits of permissions for keys the caller has a group + * membership in common with */ + if (gid_valid(key->gid) && key->perm & KEY_GRP_ALL) { + if (gid_eq(key->gid, cred->fsgid)) { + kperm = key->perm >> 8; + goto use_these_perms; + } + + ret = groups_search(cred->group_info, key->gid); + if (ret) { + kperm = key->perm >> 8; + goto use_these_perms; + } + } + + /* otherwise use the least-significant 8-bits */ + kperm = key->perm; + +use_these_perms: + + /* use the top 8-bits of permissions for keys the caller possesses + * - possessor permissions are additive with other permissions + */ + if (is_key_possessed(key_ref)) + kperm |= key->perm >> 24; + + kperm = kperm & perm & KEY_NEED_ALL; + + if (kperm != perm) + return -EACCES; + + /* let LSM be the final arbiter */ + return security_key_permission(key_ref, cred, perm); +} +EXPORT_SYMBOL(key_task_permission); + +/** + * key_validate - Validate a key. + * @key: The key to be validated. + * + * Check that a key is valid, returning 0 if the key is okay, -ENOKEY if the + * key is invalidated, -EKEYREVOKED if the key's type has been removed or if + * the key has been revoked or -EKEYEXPIRED if the key has expired. + */ +int key_validate(const struct key *key) +{ + unsigned long flags = key->flags; + + if (flags & (1 << KEY_FLAG_INVALIDATED)) + return -ENOKEY; + + /* check it's still accessible */ + if (flags & ((1 << KEY_FLAG_REVOKED) | + (1 << KEY_FLAG_DEAD))) + return -EKEYREVOKED; + + /* check it hasn't expired */ + if (key->expiry) { + struct timespec now = current_kernel_time(); + if (now.tv_sec >= key->expiry) + return -EKEYEXPIRED; + } + + return 0; +} +EXPORT_SYMBOL(key_validate); |