VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

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