xref: /openbmc/linux/security/keys/permission.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2973c9f4fSDavid Howells /* Key permission checking
3468ed2b0SDavid Howells  *
4468ed2b0SDavid Howells  * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
5468ed2b0SDavid Howells  * Written by David Howells (dhowells@redhat.com)
6468ed2b0SDavid Howells  */
7468ed2b0SDavid Howells 
8876979c9SPaul Gortmaker #include <linux/export.h>
929db9190SDavid Howells #include <linux/security.h>
10468ed2b0SDavid Howells #include "internal.h"
11468ed2b0SDavid Howells 
12d84f4f99SDavid Howells /**
13d84f4f99SDavid Howells  * key_task_permission - Check a key can be used
14973c9f4fSDavid Howells  * @key_ref: The key to check.
15973c9f4fSDavid Howells  * @cred: The credentials to use.
16*8c0637e9SDavid Howells  * @need_perm: The permission required.
17d84f4f99SDavid Howells  *
18d84f4f99SDavid Howells  * Check to see whether permission is granted to use a key in the desired way,
19d84f4f99SDavid Howells  * but permit the security modules to override.
20d84f4f99SDavid Howells  *
21973c9f4fSDavid Howells  * The caller must hold either a ref on cred or must hold the RCU readlock.
22973c9f4fSDavid Howells  *
23973c9f4fSDavid Howells  * Returns 0 if successful, -EACCES if access is denied based on the
24973c9f4fSDavid Howells  * permissions bits or the LSM check.
25468ed2b0SDavid Howells  */
key_task_permission(const key_ref_t key_ref,const struct cred * cred,enum key_need_perm need_perm)26d84f4f99SDavid Howells int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
27*8c0637e9SDavid Howells 			enum key_need_perm need_perm)
28468ed2b0SDavid Howells {
29028db3e2SLinus Torvalds 	struct key *key;
30*8c0637e9SDavid Howells 	key_perm_t kperm, mask;
31028db3e2SLinus Torvalds 	int ret;
32468ed2b0SDavid Howells 
33*8c0637e9SDavid Howells 	switch (need_perm) {
34*8c0637e9SDavid Howells 	default:
35*8c0637e9SDavid Howells 		WARN_ON(1);
36*8c0637e9SDavid Howells 		return -EACCES;
37*8c0637e9SDavid Howells 	case KEY_NEED_UNLINK:
38*8c0637e9SDavid Howells 	case KEY_SYSADMIN_OVERRIDE:
39*8c0637e9SDavid Howells 	case KEY_AUTHTOKEN_OVERRIDE:
40*8c0637e9SDavid Howells 	case KEY_DEFER_PERM_CHECK:
41*8c0637e9SDavid Howells 		goto lsm;
42*8c0637e9SDavid Howells 
43*8c0637e9SDavid Howells 	case KEY_NEED_VIEW:	mask = KEY_OTH_VIEW;	break;
44*8c0637e9SDavid Howells 	case KEY_NEED_READ:	mask = KEY_OTH_READ;	break;
45*8c0637e9SDavid Howells 	case KEY_NEED_WRITE:	mask = KEY_OTH_WRITE;	break;
46*8c0637e9SDavid Howells 	case KEY_NEED_SEARCH:	mask = KEY_OTH_SEARCH;	break;
47*8c0637e9SDavid Howells 	case KEY_NEED_LINK:	mask = KEY_OTH_LINK;	break;
48*8c0637e9SDavid Howells 	case KEY_NEED_SETATTR:	mask = KEY_OTH_SETATTR;	break;
49*8c0637e9SDavid Howells 	}
50*8c0637e9SDavid Howells 
51468ed2b0SDavid Howells 	key = key_ref_to_ptr(key_ref);
52468ed2b0SDavid Howells 
53028db3e2SLinus Torvalds 	/* use the second 8-bits of permissions for keys the caller owns */
54028db3e2SLinus Torvalds 	if (uid_eq(key->uid, cred->fsuid)) {
55028db3e2SLinus Torvalds 		kperm = key->perm >> 16;
56028db3e2SLinus Torvalds 		goto use_these_perms;
57028db3e2SLinus Torvalds 	}
58468ed2b0SDavid Howells 
59028db3e2SLinus Torvalds 	/* use the third 8-bits of permissions for keys the caller has a group
60028db3e2SLinus Torvalds 	 * membership in common with */
61028db3e2SLinus Torvalds 	if (gid_valid(key->gid) && key->perm & KEY_GRP_ALL) {
62028db3e2SLinus Torvalds 		if (gid_eq(key->gid, cred->fsgid)) {
63028db3e2SLinus Torvalds 			kperm = key->perm >> 8;
64028db3e2SLinus Torvalds 			goto use_these_perms;
65028db3e2SLinus Torvalds 		}
66468ed2b0SDavid Howells 
67028db3e2SLinus Torvalds 		ret = groups_search(cred->group_info, key->gid);
68028db3e2SLinus Torvalds 		if (ret) {
69028db3e2SLinus Torvalds 			kperm = key->perm >> 8;
70028db3e2SLinus Torvalds 			goto use_these_perms;
71028db3e2SLinus Torvalds 		}
72028db3e2SLinus Torvalds 	}
73468ed2b0SDavid Howells 
74028db3e2SLinus Torvalds 	/* otherwise use the least-significant 8-bits */
75028db3e2SLinus Torvalds 	kperm = key->perm;
76028db3e2SLinus Torvalds 
77028db3e2SLinus Torvalds use_these_perms:
78028db3e2SLinus Torvalds 
79028db3e2SLinus Torvalds 	/* use the top 8-bits of permissions for keys the caller possesses
80028db3e2SLinus Torvalds 	 * - possessor permissions are additive with other permissions
81028db3e2SLinus Torvalds 	 */
827ab501dbSDavid Howells 	if (is_key_possessed(key_ref))
83028db3e2SLinus Torvalds 		kperm |= key->perm >> 24;
847ab501dbSDavid Howells 
85*8c0637e9SDavid Howells 	if ((kperm & mask) != mask)
8629db9190SDavid Howells 		return -EACCES;
87028db3e2SLinus Torvalds 
88028db3e2SLinus Torvalds 	/* let LSM be the final arbiter */
89*8c0637e9SDavid Howells lsm:
90*8c0637e9SDavid Howells 	return security_key_permission(key_ref, cred, need_perm);
91a8b17ed0SDavid Howells }
92468ed2b0SDavid Howells EXPORT_SYMBOL(key_task_permission);
93b5f545c8SDavid Howells 
94973c9f4fSDavid Howells /**
95973c9f4fSDavid Howells  * key_validate - Validate a key.
96973c9f4fSDavid Howells  * @key: The key to be validated.
97973c9f4fSDavid Howells  *
98fd75815fSDavid Howells  * Check that a key is valid, returning 0 if the key is okay, -ENOKEY if the
99fd75815fSDavid Howells  * key is invalidated, -EKEYREVOKED if the key's type has been removed or if
100fd75815fSDavid Howells  * the key has been revoked or -EKEYEXPIRED if the key has expired.
101b5f545c8SDavid Howells  */
key_validate(const struct key * key)102b404aef7SDavid Howells int key_validate(const struct key *key)
103b5f545c8SDavid Howells {
1041823d475SEric Biggers 	unsigned long flags = READ_ONCE(key->flags);
105074d5898SBaolin Wang 	time64_t expiry = READ_ONCE(key->expiry);
106b5f545c8SDavid Howells 
107fd75815fSDavid Howells 	if (flags & (1 << KEY_FLAG_INVALIDATED))
108b404aef7SDavid Howells 		return -ENOKEY;
109fd75815fSDavid Howells 
110b5f545c8SDavid Howells 	/* check it's still accessible */
111fd75815fSDavid Howells 	if (flags & ((1 << KEY_FLAG_REVOKED) |
112fd75815fSDavid Howells 		     (1 << KEY_FLAG_DEAD)))
113b404aef7SDavid Howells 		return -EKEYREVOKED;
114b5f545c8SDavid Howells 
115b5f545c8SDavid Howells 	/* check it hasn't expired */
1161823d475SEric Biggers 	if (expiry) {
117074d5898SBaolin Wang 		if (ktime_get_real_seconds() >= expiry)
118b404aef7SDavid Howells 			return -EKEYEXPIRED;
119b5f545c8SDavid Howells 	}
120b5f545c8SDavid Howells 
121b404aef7SDavid Howells 	return 0;
122a8b17ed0SDavid Howells }
123b5f545c8SDavid Howells EXPORT_SYMBOL(key_validate);
124