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) }