blob: fd8a5dc6910ae2bc6baa0e129461c9096f744bad [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
David Howells973c9f42011-01-20 16:38:33 +00002/* Key permission checking
David Howells468ed2b2005-10-07 15:07:38 +01003 *
4 * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
David Howells468ed2b2005-10-07 15:07:38 +01006 */
7
Paul Gortmaker876979c2018-12-09 15:36:29 -05008#include <linux/export.h>
David Howells29db9192005-10-30 15:02:44 -08009#include <linux/security.h>
David Howells2e122562019-06-27 23:03:07 +010010#include <linux/user_namespace.h>
11#include <linux/uaccess.h>
David Howells468ed2b2005-10-07 15:07:38 +010012#include "internal.h"
13
David Howells2e122562019-06-27 23:03:07 +010014struct key_acl default_key_acl = {
15 .usage = REFCOUNT_INIT(1),
16 .nr_ace = 2,
17 .possessor_viewable = true,
18 .aces = {
19 KEY_POSSESSOR_ACE(KEY_ACE__PERMS & ~KEY_ACE_JOIN),
20 KEY_OWNER_ACE(KEY_ACE_VIEW),
21 }
22};
23EXPORT_SYMBOL(default_key_acl);
24
25struct key_acl joinable_keyring_acl = {
26 .usage = REFCOUNT_INIT(1),
27 .nr_ace = 2,
28 .possessor_viewable = true,
29 .aces = {
30 KEY_POSSESSOR_ACE(KEY_ACE__PERMS & ~KEY_ACE_JOIN),
31 KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_LINK | KEY_ACE_JOIN),
32 }
33};
34EXPORT_SYMBOL(joinable_keyring_acl);
35
36struct key_acl internal_key_acl = {
37 .usage = REFCOUNT_INIT(1),
38 .nr_ace = 2,
39 .aces = {
40 KEY_POSSESSOR_ACE(KEY_ACE_SEARCH),
41 KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_SEARCH),
42 }
43};
44EXPORT_SYMBOL(internal_key_acl);
45
46struct key_acl internal_keyring_acl = {
47 .usage = REFCOUNT_INIT(1),
48 .nr_ace = 2,
49 .aces = {
50 KEY_POSSESSOR_ACE(KEY_ACE_SEARCH),
51 KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_SEARCH),
52 }
53};
54EXPORT_SYMBOL(internal_keyring_acl);
55
56struct key_acl internal_writable_keyring_acl = {
57 .usage = REFCOUNT_INIT(1),
58 .nr_ace = 2,
59 .aces = {
60 KEY_POSSESSOR_ACE(KEY_ACE_SEARCH | KEY_ACE_WRITE),
61 KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_WRITE | KEY_ACE_SEARCH),
62 }
63};
64EXPORT_SYMBOL(internal_writable_keyring_acl);
65
David Howellsd84f4f92008-11-14 10:39:23 +110066/**
67 * key_task_permission - Check a key can be used
David Howells973c9f42011-01-20 16:38:33 +000068 * @key_ref: The key to check.
69 * @cred: The credentials to use.
David Howells2e122562019-06-27 23:03:07 +010070 * @desired_perm: The permission to check for.
David Howellsd84f4f92008-11-14 10:39:23 +110071 *
72 * Check to see whether permission is granted to use a key in the desired way,
73 * but permit the security modules to override.
74 *
David Howells973c9f42011-01-20 16:38:33 +000075 * The caller must hold either a ref on cred or must hold the RCU readlock.
76 *
77 * Returns 0 if successful, -EACCES if access is denied based on the
78 * permissions bits or the LSM check.
David Howells468ed2b2005-10-07 15:07:38 +010079 */
David Howellsd84f4f92008-11-14 10:39:23 +110080int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
David Howells2e122562019-06-27 23:03:07 +010081 unsigned int desired_perm)
David Howells468ed2b2005-10-07 15:07:38 +010082{
David Howells2e122562019-06-27 23:03:07 +010083 const struct key_acl *acl;
84 const struct key *key;
85 unsigned int allow = 0;
86 int i;
87
88 BUILD_BUG_ON(KEY_NEED_VIEW != KEY_ACE_VIEW ||
89 KEY_NEED_READ != KEY_ACE_READ ||
90 KEY_NEED_WRITE != KEY_ACE_WRITE ||
91 KEY_NEED_SEARCH != KEY_ACE_SEARCH ||
92 KEY_NEED_LINK != KEY_ACE_LINK ||
93 KEY_NEED_SETSEC != KEY_ACE_SET_SECURITY ||
94 KEY_NEED_INVAL != KEY_ACE_INVAL ||
95 KEY_NEED_REVOKE != KEY_ACE_REVOKE ||
96 KEY_NEED_JOIN != KEY_ACE_JOIN ||
97 KEY_NEED_CLEAR != KEY_ACE_CLEAR);
David Howells468ed2b2005-10-07 15:07:38 +010098
99 key = key_ref_to_ptr(key_ref);
100
David Howells2e122562019-06-27 23:03:07 +0100101 rcu_read_lock();
David Howells468ed2b2005-10-07 15:07:38 +0100102
David Howells2e122562019-06-27 23:03:07 +0100103 acl = rcu_dereference(key->acl);
104 if (!acl || acl->nr_ace == 0)
105 goto no_access_rcu;
David Howells468ed2b2005-10-07 15:07:38 +0100106
David Howells2e122562019-06-27 23:03:07 +0100107 for (i = 0; i < acl->nr_ace; i++) {
108 const struct key_ace *ace = &acl->aces[i];
109
110 switch (ace->type) {
111 case KEY_ACE_SUBJ_STANDARD:
112 switch (ace->subject_id) {
113 case KEY_ACE_POSSESSOR:
114 if (is_key_possessed(key_ref))
115 allow |= ace->perm;
116 break;
117 case KEY_ACE_OWNER:
118 if (uid_eq(key->uid, cred->fsuid))
119 allow |= ace->perm;
120 break;
121 case KEY_ACE_GROUP:
122 if (gid_valid(key->gid)) {
123 if (gid_eq(key->gid, cred->fsgid))
124 allow |= ace->perm;
125 else if (groups_search(cred->group_info, key->gid))
126 allow |= ace->perm;
127 }
128 break;
129 case KEY_ACE_EVERYONE:
130 allow |= ace->perm;
131 break;
132 }
133 break;
David Howells468ed2b2005-10-07 15:07:38 +0100134 }
135 }
136
David Howells2e122562019-06-27 23:03:07 +0100137 rcu_read_unlock();
David Howells468ed2b2005-10-07 15:07:38 +0100138
David Howells2e122562019-06-27 23:03:07 +0100139 if (!(allow & desired_perm))
140 goto no_access;
David Howellsc69e8d92008-11-14 10:39:19 +1100141
David Howells2e122562019-06-27 23:03:07 +0100142 return security_key_permission(key_ref, cred, desired_perm);
David Howells7ab501d2005-10-07 16:41:24 +0100143
David Howells2e122562019-06-27 23:03:07 +0100144no_access_rcu:
145 rcu_read_unlock();
146no_access:
147 return -EACCES;
David Howellsa8b17ed2011-01-20 16:38:27 +0000148}
David Howells468ed2b2005-10-07 15:07:38 +0100149EXPORT_SYMBOL(key_task_permission);
David Howellsb5f545c2006-01-08 01:02:47 -0800150
David Howells973c9f42011-01-20 16:38:33 +0000151/**
152 * key_validate - Validate a key.
153 * @key: The key to be validated.
154 *
David Howellsfd758152012-05-11 10:56:56 +0100155 * Check that a key is valid, returning 0 if the key is okay, -ENOKEY if the
156 * key is invalidated, -EKEYREVOKED if the key's type has been removed or if
157 * the key has been revoked or -EKEYEXPIRED if the key has expired.
David Howellsb5f545c2006-01-08 01:02:47 -0800158 */
David Howellsb404aef2012-05-15 14:11:11 +0100159int key_validate(const struct key *key)
David Howellsb5f545c2006-01-08 01:02:47 -0800160{
Eric Biggers1823d472017-09-27 12:50:44 -0700161 unsigned long flags = READ_ONCE(key->flags);
Baolin Wang074d5892017-11-15 16:38:45 +0000162 time64_t expiry = READ_ONCE(key->expiry);
David Howellsb5f545c2006-01-08 01:02:47 -0800163
David Howellsb404aef2012-05-15 14:11:11 +0100164 if (flags & (1 << KEY_FLAG_INVALIDATED))
165 return -ENOKEY;
David Howellsfd758152012-05-11 10:56:56 +0100166
David Howellsb404aef2012-05-15 14:11:11 +0100167 /* check it's still accessible */
168 if (flags & ((1 << KEY_FLAG_REVOKED) |
169 (1 << KEY_FLAG_DEAD)))
170 return -EKEYREVOKED;
David Howellsb5f545c2006-01-08 01:02:47 -0800171
David Howellsb404aef2012-05-15 14:11:11 +0100172 /* check it hasn't expired */
Eric Biggers1823d472017-09-27 12:50:44 -0700173 if (expiry) {
Baolin Wang074d5892017-11-15 16:38:45 +0000174 if (ktime_get_real_seconds() >= expiry)
David Howellsb404aef2012-05-15 14:11:11 +0100175 return -EKEYEXPIRED;
David Howellsb5f545c2006-01-08 01:02:47 -0800176 }
177
David Howellsb404aef2012-05-15 14:11:11 +0100178 return 0;
David Howellsa8b17ed2011-01-20 16:38:27 +0000179}
David Howellsb5f545c2006-01-08 01:02:47 -0800180EXPORT_SYMBOL(key_validate);
David Howells2e122562019-06-27 23:03:07 +0100181
182/*
183 * Roughly render an ACL to an old-style permissions mask. We cannot
184 * accurately render what the ACL, particularly if it has ACEs that represent
185 * subjects outside of { poss, user, group, other }.
186 */
187unsigned int key_acl_to_perm(const struct key_acl *acl)
188{
189 unsigned int perm = 0, tperm;
190 int i;
191
192 BUILD_BUG_ON(KEY_OTH_VIEW != KEY_ACE_VIEW ||
193 KEY_OTH_READ != KEY_ACE_READ ||
194 KEY_OTH_WRITE != KEY_ACE_WRITE ||
195 KEY_OTH_SEARCH != KEY_ACE_SEARCH ||
196 KEY_OTH_LINK != KEY_ACE_LINK ||
197 KEY_OTH_SETATTR != KEY_ACE_SET_SECURITY);
198
199 if (!acl || acl->nr_ace == 0)
200 return 0;
201
202 for (i = 0; i < acl->nr_ace; i++) {
203 const struct key_ace *ace = &acl->aces[i];
204
205 switch (ace->type) {
206 case KEY_ACE_SUBJ_STANDARD:
207 tperm = ace->perm & KEY_OTH_ALL;
208
209 /* Invalidation and joining were allowed by SEARCH */
210 if (ace->perm & (KEY_ACE_INVAL | KEY_ACE_JOIN))
211 tperm |= KEY_OTH_SEARCH;
212
213 /* Revocation was allowed by either SETATTR or WRITE */
214 if ((ace->perm & KEY_ACE_REVOKE) && !(tperm & KEY_OTH_SETATTR))
215 tperm |= KEY_OTH_WRITE;
216
217 /* Clearing was allowed by WRITE */
218 if (ace->perm & KEY_ACE_CLEAR)
219 tperm |= KEY_OTH_WRITE;
220
221 switch (ace->subject_id) {
222 case KEY_ACE_POSSESSOR:
223 perm |= tperm << 24;
224 break;
225 case KEY_ACE_OWNER:
226 perm |= tperm << 16;
227 break;
228 case KEY_ACE_GROUP:
229 perm |= tperm << 8;
230 break;
231 case KEY_ACE_EVERYONE:
232 perm |= tperm << 0;
233 break;
234 }
235 }
236 }
237
238 return perm;
239}
240
241/*
242 * Destroy a key's ACL.
243 */
244void key_put_acl(struct key_acl *acl)
245{
246 if (acl && refcount_dec_and_test(&acl->usage))
247 kfree_rcu(acl, rcu);
248}
249
250/*
251 * Try to set the ACL. This either attaches or discards the proposed ACL.
252 */
253long key_set_acl(struct key *key, struct key_acl *acl)
254{
255 int i;
256
257 /* If we're not the sysadmin, we can only change a key that we own. */
258 if (!capable(CAP_SYS_ADMIN) && !uid_eq(key->uid, current_fsuid())) {
259 key_put_acl(acl);
260 return -EACCES;
261 }
262
263 for (i = 0; i < acl->nr_ace; i++) {
264 const struct key_ace *ace = &acl->aces[i];
265 if (ace->type == KEY_ACE_SUBJ_STANDARD &&
266 ace->subject_id == KEY_ACE_POSSESSOR) {
267 if (ace->perm & KEY_ACE_VIEW)
268 acl->possessor_viewable = true;
269 break;
270 }
271 }
272
273 rcu_swap_protected(key->acl, acl, lockdep_is_held(&key->sem));
274 key_put_acl(acl);
275 return 0;
276}
David Howells7a1ade82019-06-27 23:03:07 +0100277
278/*
279 * Allocate a new ACL with an extra ACE slot.
280 */
281static struct key_acl *key_alloc_acl(const struct key_acl *old_acl, int nr, int skip)
282{
283 struct key_acl *acl;
284 int nr_ace, i, j = 0;
285
286 nr_ace = old_acl->nr_ace + nr;
287 if (nr_ace > 16)
288 return ERR_PTR(-EINVAL);
289
290 acl = kzalloc(struct_size(acl, aces, nr_ace), GFP_KERNEL);
291 if (!acl)
292 return ERR_PTR(-ENOMEM);
293
294 refcount_set(&acl->usage, 1);
295 acl->nr_ace = nr_ace;
296 for (i = 0; i < old_acl->nr_ace; i++) {
297 if (i == skip)
298 continue;
299 acl->aces[j] = old_acl->aces[i];
300 j++;
301 }
302 return acl;
303}
304
305/*
306 * Generate the revised ACL.
307 */
308static long key_change_acl(struct key *key, struct key_ace *new_ace)
309{
310 struct key_acl *acl, *old;
311 int i;
312
313 old = rcu_dereference_protected(key->acl, lockdep_is_held(&key->sem));
314
315 for (i = 0; i < old->nr_ace; i++)
316 if (old->aces[i].type == new_ace->type &&
317 old->aces[i].subject_id == new_ace->subject_id)
318 goto found_match;
319
320 if (new_ace->perm == 0)
321 return 0; /* No permissions to remove. Add deny record? */
322
323 acl = key_alloc_acl(old, 1, -1);
324 if (IS_ERR(acl))
325 return PTR_ERR(acl);
326 acl->aces[i] = *new_ace;
327 goto change;
328
329found_match:
330 if (new_ace->perm == 0)
331 goto delete_ace;
332 if (new_ace->perm == old->aces[i].perm)
333 return 0;
334 acl = key_alloc_acl(old, 0, -1);
335 if (IS_ERR(acl))
336 return PTR_ERR(acl);
337 acl->aces[i].perm = new_ace->perm;
338 goto change;
339
340delete_ace:
341 acl = key_alloc_acl(old, -1, i);
342 if (IS_ERR(acl))
343 return PTR_ERR(acl);
344 goto change;
345
346change:
347 return key_set_acl(key, acl);
348}
349
350/*
351 * Add, alter or remove (if perm == 0) an ACE in a key's ACL.
352 */
353long keyctl_grant_permission(key_serial_t keyid,
354 enum key_ace_subject_type type,
355 unsigned int subject,
356 unsigned int perm)
357{
358 struct key_ace new_ace;
359 struct key *key;
360 key_ref_t key_ref;
361 long ret;
362
363 new_ace.type = type;
364 new_ace.perm = perm;
365
366 switch (type) {
367 case KEY_ACE_SUBJ_STANDARD:
368 if (subject >= nr__key_ace_standard_subject)
369 return -ENOENT;
370 new_ace.subject_id = subject;
371 break;
372
373 default:
374 return -ENOENT;
375 }
376
377 key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_SETSEC);
378 if (IS_ERR(key_ref)) {
379 ret = PTR_ERR(key_ref);
380 goto error;
381 }
382
383 key = key_ref_to_ptr(key_ref);
384
385 down_write(&key->sem);
386
387 /* If we're not the sysadmin, we can only change a key that we own */
388 ret = -EACCES;
389 if (capable(CAP_SYS_ADMIN) || uid_eq(key->uid, current_fsuid()))
390 ret = key_change_acl(key, &new_ace);
391 up_write(&key->sem);
392 key_put(key);
393error:
394 return ret;
395}