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