xref: /linux/fs/afs/security.c (revision db6b35cffe59c619ea3772b21d7c7c8a7b885dc1)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* AFS security handling
3  *
4  * Copyright (C) 2007, 2017 Red Hat, Inc. All Rights Reserved.
5  * Written by David Howells (dhowells@redhat.com)
6  */
7 
8 #include <linux/init.h>
9 #include <linux/slab.h>
10 #include <linux/fs.h>
11 #include <linux/ctype.h>
12 #include <linux/sched.h>
13 #include <linux/hashtable.h>
14 #include <keys/rxrpc-type.h>
15 #include "internal.h"
16 
17 static DEFINE_HASHTABLE(afs_permits_cache, 10);
18 static DEFINE_SPINLOCK(afs_permits_lock);
19 static DEFINE_MUTEX(afs_key_lock);
20 
21 /*
22  * Allocate a key to use as a placeholder for anonymous user security.
23  */
24 static int afs_alloc_anon_key(struct afs_cell *cell)
25 {
26 	struct key *key;
27 
28 	mutex_lock(&afs_key_lock);
29 	key = cell->anonymous_key;
30 	if (!key) {
31 		key = rxrpc_get_null_key(cell->key_desc);
32 		if (!IS_ERR(key))
33 			cell->anonymous_key = key;
34 	}
35 	mutex_unlock(&afs_key_lock);
36 
37 	if (IS_ERR(key))
38 		return PTR_ERR(key);
39 
40 	_debug("anon key %p{%x}",
41 	       cell->anonymous_key, key_serial(cell->anonymous_key));
42 	return 0;
43 }
44 
45 /*
46  * get a key
47  */
48 struct key *afs_request_key(struct afs_cell *cell)
49 {
50 	struct key *key;
51 	int ret;
52 
53 	_enter("{%s}", cell->key_desc);
54 
55 	_debug("key %s", cell->key_desc);
56 	key = request_key_net(&key_type_rxrpc, cell->key_desc,
57 			      cell->net->net, NULL);
58 	if (IS_ERR(key)) {
59 		if (PTR_ERR(key) != -ENOKEY) {
60 			_leave(" = %ld", PTR_ERR(key));
61 			return key;
62 		}
63 
64 		if (!cell->anonymous_key) {
65 			ret = afs_alloc_anon_key(cell);
66 			if (ret < 0)
67 				return ERR_PTR(ret);
68 		}
69 
70 		/* act as anonymous user */
71 		_leave(" = {%x} [anon]", key_serial(cell->anonymous_key));
72 		return key_get(cell->anonymous_key);
73 	} else {
74 		/* act as authorised user */
75 		_leave(" = {%x} [auth]", key_serial(key));
76 		return key;
77 	}
78 }
79 
80 /*
81  * Get a key when pathwalk is in rcuwalk mode.
82  */
83 struct key *afs_request_key_rcu(struct afs_cell *cell)
84 {
85 	struct key *key;
86 
87 	_enter("{%s}", cell->key_desc);
88 
89 	_debug("key %s", cell->key_desc);
90 	key = request_key_net_rcu(&key_type_rxrpc, cell->key_desc,
91 				  cell->net->net);
92 	if (IS_ERR(key)) {
93 		if (PTR_ERR(key) != -ENOKEY) {
94 			_leave(" = %ld", PTR_ERR(key));
95 			return key;
96 		}
97 
98 		/* act as anonymous user */
99 		if (!cell->anonymous_key)
100 			return NULL; /* Need to allocate */
101 		_leave(" = {%x} [anon]", key_serial(cell->anonymous_key));
102 		return key_get(cell->anonymous_key);
103 	} else {
104 		/* act as authorised user */
105 		_leave(" = {%x} [auth]", key_serial(key));
106 		return key;
107 	}
108 }
109 
110 /*
111  * Dispose of a list of permits.
112  */
113 static void afs_permits_rcu(struct rcu_head *rcu)
114 {
115 	struct afs_permits *permits =
116 		container_of(rcu, struct afs_permits, rcu);
117 	int i;
118 
119 	for (i = 0; i < permits->nr_permits; i++)
120 		key_put(permits->permits[i].key);
121 	kfree(permits);
122 }
123 
124 /*
125  * Discard a permission cache.
126  */
127 void afs_put_permits(struct afs_permits *permits)
128 {
129 	if (permits && refcount_dec_and_test(&permits->usage)) {
130 		spin_lock(&afs_permits_lock);
131 		hash_del_rcu(&permits->hash_node);
132 		spin_unlock(&afs_permits_lock);
133 		call_rcu(&permits->rcu, afs_permits_rcu);
134 	}
135 }
136 
137 /*
138  * Clear a permit cache on callback break.
139  */
140 void afs_clear_permits(struct afs_vnode *vnode)
141 {
142 	struct afs_permits *permits;
143 
144 	spin_lock(&vnode->lock);
145 	permits = rcu_dereference_protected(vnode->permit_cache,
146 					    lockdep_is_held(&vnode->lock));
147 	RCU_INIT_POINTER(vnode->permit_cache, NULL);
148 	spin_unlock(&vnode->lock);
149 
150 	afs_put_permits(permits);
151 }
152 
153 /*
154  * Hash a list of permits.  Use simple addition to make it easy to add an extra
155  * one at an as-yet indeterminate position in the list.
156  */
157 static void afs_hash_permits(struct afs_permits *permits)
158 {
159 	unsigned long h = permits->nr_permits;
160 	int i;
161 
162 	for (i = 0; i < permits->nr_permits; i++) {
163 		h += (unsigned long)permits->permits[i].key / sizeof(void *);
164 		h += permits->permits[i].access;
165 	}
166 
167 	permits->h = h;
168 }
169 
170 /*
171  * Cache the CallerAccess result obtained from doing a fileserver operation
172  * that returned a vnode status for a particular key.  If a callback break
173  * occurs whilst the operation was in progress then we have to ditch the cache
174  * as the ACL *may* have changed.
175  */
176 void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
177 		      unsigned int cb_break, struct afs_status_cb *scb)
178 {
179 	struct afs_permits *permits, *xpermits, *replacement, *zap, *new = NULL;
180 	afs_access_t caller_access = scb->status.caller_access;
181 	size_t size = 0;
182 	bool changed = false;
183 	int i, j;
184 
185 	_enter("{%llx:%llu},%x,%x",
186 	       vnode->fid.vid, vnode->fid.vnode, key_serial(key), caller_access);
187 
188 	rcu_read_lock();
189 
190 	/* Check for the common case first: We got back the same access as last
191 	 * time we tried and already have it recorded.
192 	 */
193 	permits = rcu_dereference(vnode->permit_cache);
194 	if (permits) {
195 		if (!permits->invalidated) {
196 			for (i = 0; i < permits->nr_permits; i++) {
197 				if (permits->permits[i].key < key)
198 					continue;
199 				if (permits->permits[i].key > key)
200 					break;
201 				if (permits->permits[i].access != caller_access) {
202 					changed = true;
203 					break;
204 				}
205 
206 				if (afs_cb_is_broken(cb_break, vnode)) {
207 					changed = true;
208 					break;
209 				}
210 
211 				/* The cache is still good. */
212 				rcu_read_unlock();
213 				return;
214 			}
215 		}
216 
217 		changed |= permits->invalidated;
218 		size = permits->nr_permits;
219 
220 		/* If this set of permits is now wrong, clear the permits
221 		 * pointer so that no one tries to use the stale information.
222 		 */
223 		if (changed) {
224 			spin_lock(&vnode->lock);
225 			if (permits != rcu_access_pointer(vnode->permit_cache))
226 				goto someone_else_changed_it_unlock;
227 			RCU_INIT_POINTER(vnode->permit_cache, NULL);
228 			spin_unlock(&vnode->lock);
229 
230 			afs_put_permits(permits);
231 			permits = NULL;
232 			size = 0;
233 		}
234 	}
235 
236 	if (afs_cb_is_broken(cb_break, vnode))
237 		goto someone_else_changed_it;
238 
239 	/* We need a ref on any permits list we want to copy as we'll have to
240 	 * drop the lock to do memory allocation.
241 	 */
242 	if (permits && !refcount_inc_not_zero(&permits->usage))
243 		goto someone_else_changed_it;
244 
245 	rcu_read_unlock();
246 
247 	/* Speculatively create a new list with the revised permission set.  We
248 	 * discard this if we find an extant match already in the hash, but
249 	 * it's easier to compare with memcmp this way.
250 	 *
251 	 * We fill in the key pointers at this time, but we don't get the refs
252 	 * yet.
253 	 */
254 	size++;
255 	new = kzalloc(struct_size(new, permits, size), GFP_NOFS);
256 	if (!new)
257 		goto out_put;
258 
259 	refcount_set(&new->usage, 1);
260 	new->nr_permits = size;
261 	i = j = 0;
262 	if (permits) {
263 		for (i = 0; i < permits->nr_permits; i++) {
264 			if (j == i && permits->permits[i].key > key) {
265 				new->permits[j].key = key;
266 				new->permits[j].access = caller_access;
267 				j++;
268 			}
269 			new->permits[j].key = permits->permits[i].key;
270 			new->permits[j].access = permits->permits[i].access;
271 			j++;
272 		}
273 	}
274 
275 	if (j == i) {
276 		new->permits[j].key = key;
277 		new->permits[j].access = caller_access;
278 	}
279 
280 	afs_hash_permits(new);
281 
282 	/* Now see if the permit list we want is actually already available */
283 	spin_lock(&afs_permits_lock);
284 
285 	hash_for_each_possible(afs_permits_cache, xpermits, hash_node, new->h) {
286 		if (xpermits->h != new->h ||
287 		    xpermits->invalidated ||
288 		    xpermits->nr_permits != new->nr_permits ||
289 		    memcmp(xpermits->permits, new->permits,
290 			   new->nr_permits * sizeof(struct afs_permit)) != 0)
291 			continue;
292 
293 		if (refcount_inc_not_zero(&xpermits->usage)) {
294 			replacement = xpermits;
295 			goto found;
296 		}
297 
298 		break;
299 	}
300 
301 	for (i = 0; i < new->nr_permits; i++)
302 		key_get(new->permits[i].key);
303 	hash_add_rcu(afs_permits_cache, &new->hash_node, new->h);
304 	replacement = new;
305 	new = NULL;
306 
307 found:
308 	spin_unlock(&afs_permits_lock);
309 
310 	kfree(new);
311 
312 	rcu_read_lock();
313 	spin_lock(&vnode->lock);
314 	zap = rcu_access_pointer(vnode->permit_cache);
315 	if (!afs_cb_is_broken(cb_break, vnode) && zap == permits)
316 		rcu_assign_pointer(vnode->permit_cache, replacement);
317 	else
318 		zap = replacement;
319 	spin_unlock(&vnode->lock);
320 	rcu_read_unlock();
321 	afs_put_permits(zap);
322 out_put:
323 	afs_put_permits(permits);
324 	return;
325 
326 someone_else_changed_it_unlock:
327 	spin_unlock(&vnode->lock);
328 someone_else_changed_it:
329 	/* Someone else changed the cache under us - don't recheck at this
330 	 * time.
331 	 */
332 	rcu_read_unlock();
333 	return;
334 }
335 
336 static bool afs_check_permit_rcu(struct afs_vnode *vnode, struct key *key,
337 				 afs_access_t *_access)
338 {
339 	const struct afs_permits *permits;
340 	int i;
341 
342 	_enter("{%llx:%llu},%x",
343 	       vnode->fid.vid, vnode->fid.vnode, key_serial(key));
344 
345 	/* check the permits to see if we've got one yet */
346 	if (key == vnode->volume->cell->anonymous_key) {
347 		*_access = vnode->status.anon_access;
348 		_leave(" = t [anon %x]", *_access);
349 		return true;
350 	}
351 
352 	permits = rcu_dereference(vnode->permit_cache);
353 	if (permits) {
354 		for (i = 0; i < permits->nr_permits; i++) {
355 			if (permits->permits[i].key < key)
356 				continue;
357 			if (permits->permits[i].key > key)
358 				break;
359 
360 			*_access = permits->permits[i].access;
361 			_leave(" = %u [perm %x]", !permits->invalidated, *_access);
362 			return !permits->invalidated;
363 		}
364 	}
365 
366 	_leave(" = f");
367 	return false;
368 }
369 
370 /*
371  * check with the fileserver to see if the directory or parent directory is
372  * permitted to be accessed with this authorisation, and if so, what access it
373  * is granted
374  */
375 int afs_check_permit(struct afs_vnode *vnode, struct key *key,
376 		     afs_access_t *_access)
377 {
378 	struct afs_permits *permits;
379 	bool valid = false;
380 	int i, ret;
381 
382 	_enter("{%llx:%llu},%x",
383 	       vnode->fid.vid, vnode->fid.vnode, key_serial(key));
384 
385 	/* check the permits to see if we've got one yet */
386 	if (key == vnode->volume->cell->anonymous_key) {
387 		_debug("anon");
388 		*_access = vnode->status.anon_access;
389 		valid = true;
390 	} else {
391 		rcu_read_lock();
392 		permits = rcu_dereference(vnode->permit_cache);
393 		if (permits) {
394 			for (i = 0; i < permits->nr_permits; i++) {
395 				if (permits->permits[i].key < key)
396 					continue;
397 				if (permits->permits[i].key > key)
398 					break;
399 
400 				*_access = permits->permits[i].access;
401 				valid = !permits->invalidated;
402 				break;
403 			}
404 		}
405 		rcu_read_unlock();
406 	}
407 
408 	if (!valid) {
409 		/* Check the status on the file we're actually interested in
410 		 * (the post-processing will cache the result).
411 		 */
412 		_debug("no valid permit");
413 
414 		ret = afs_fetch_status(vnode, key, false, _access);
415 		if (ret < 0) {
416 			*_access = 0;
417 			_leave(" = %d", ret);
418 			return ret;
419 		}
420 	}
421 
422 	_leave(" = 0 [access %x]", *_access);
423 	return 0;
424 }
425 
426 /*
427  * check the permissions on an AFS file
428  * - AFS ACLs are attached to directories only, and a file is controlled by its
429  *   parent directory's ACL
430  */
431 int afs_permission(struct mnt_idmap *idmap, struct inode *inode,
432 		   int mask)
433 {
434 	struct afs_vnode *vnode = AFS_FS_I(inode);
435 	afs_access_t access;
436 	struct key *key;
437 	int ret = 0;
438 
439 	_enter("{{%llx:%llu},%lx},%x,",
440 	       vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask);
441 
442 	if (mask & MAY_NOT_BLOCK) {
443 		key = afs_request_key_rcu(vnode->volume->cell);
444 		if (IS_ERR_OR_NULL(key))
445 			return -ECHILD;
446 
447 		ret = -ECHILD;
448 		if (!afs_check_validity(vnode) ||
449 		    !afs_check_permit_rcu(vnode, key, &access))
450 			goto error;
451 	} else {
452 		key = afs_request_key(vnode->volume->cell);
453 		if (IS_ERR(key)) {
454 			_leave(" = %ld [key]", PTR_ERR(key));
455 			return PTR_ERR(key);
456 		}
457 
458 		ret = afs_validate(vnode, key);
459 		if (ret < 0)
460 			goto error;
461 
462 		/* check the permits to see if we've got one yet */
463 		ret = afs_check_permit(vnode, key, &access);
464 		if (ret < 0)
465 			goto error;
466 	}
467 
468 	/* interpret the access mask */
469 	_debug("REQ %x ACC %x on %s",
470 	       mask, access, S_ISDIR(inode->i_mode) ? "dir" : "file");
471 
472 	ret = 0;
473 	if (S_ISDIR(inode->i_mode)) {
474 		if (mask & (MAY_EXEC | MAY_READ | MAY_CHDIR)) {
475 			if (!(access & AFS_ACE_LOOKUP))
476 				goto permission_denied;
477 		}
478 		if (mask & MAY_WRITE) {
479 			if (!(access & (AFS_ACE_DELETE | /* rmdir, unlink, rename from */
480 					AFS_ACE_INSERT))) /* create, mkdir, symlink, rename to */
481 				goto permission_denied;
482 		}
483 	} else {
484 		if (!(access & AFS_ACE_LOOKUP))
485 			goto permission_denied;
486 		if ((mask & MAY_EXEC) && !(inode->i_mode & S_IXUSR))
487 			goto permission_denied;
488 		if (mask & (MAY_EXEC | MAY_READ)) {
489 			if (!(access & AFS_ACE_READ))
490 				goto permission_denied;
491 			if (!(inode->i_mode & S_IRUSR))
492 				goto permission_denied;
493 		} else if (mask & MAY_WRITE) {
494 			if (!(access & AFS_ACE_WRITE))
495 				goto permission_denied;
496 			if (!(inode->i_mode & S_IWUSR))
497 				goto permission_denied;
498 		}
499 	}
500 
501 	key_put(key);
502 	_leave(" = %d", ret);
503 	return ret;
504 
505 permission_denied:
506 	ret = -EACCES;
507 error:
508 	key_put(key);
509 	_leave(" = %d", ret);
510 	return ret;
511 }
512 
513 void __exit afs_clean_up_permit_cache(void)
514 {
515 	int i;
516 
517 	for (i = 0; i < HASH_SIZE(afs_permits_cache); i++)
518 		WARN_ON_ONCE(!hlist_empty(&afs_permits_cache[i]));
519 
520 }
521