hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/fs/afs/security.c
....@@ -1,12 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /* AFS security handling
23 *
34 * Copyright (C) 2007, 2017 Red Hat, Inc. All Rights Reserved.
45 * Written by David Howells (dhowells@redhat.com)
5
- *
6
- * This program is free software; you can redistribute it and/or
7
- * modify it under the terms of the GNU General Public License
8
- * as published by the Free Software Foundation; either version
9
- * 2 of the License, or (at your option) any later version.
106 */
117
128 #include <linux/init.h>
....@@ -31,8 +27,37 @@
3127 _enter("{%x}", key_serial(cell->anonymous_key));
3228
3329 _debug("key %s", cell->anonymous_key->description);
34
- key = request_key(&key_type_rxrpc, cell->anonymous_key->description,
35
- NULL);
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);
3661 if (IS_ERR(key)) {
3762 if (PTR_ERR(key) != -ENOKEY) {
3863 _leave(" = %ld", PTR_ERR(key));
....@@ -116,15 +141,15 @@
116141 * as the ACL *may* have changed.
117142 */
118143 void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
119
- unsigned int cb_break)
144
+ unsigned int cb_break, struct afs_status_cb *scb)
120145 {
121146 struct afs_permits *permits, *xpermits, *replacement, *zap, *new = NULL;
122
- afs_access_t caller_access = READ_ONCE(vnode->status.caller_access);
147
+ afs_access_t caller_access = scb->status.caller_access;
123148 size_t size = 0;
124149 bool changed = false;
125150 int i, j;
126151
127
- _enter("{%x:%u},%x,%x",
152
+ _enter("{%llx:%llu},%x,%x",
128153 vnode->fid.vid, vnode->fid.vnode, key_serial(key), caller_access);
129154
130155 rcu_read_lock();
....@@ -145,7 +170,7 @@
145170 break;
146171 }
147172
148
- if (cb_break != afs_cb_break_sum(vnode, vnode->cb_interest)) {
173
+ if (afs_cb_is_broken(cb_break, vnode)) {
149174 changed = true;
150175 break;
151176 }
....@@ -175,7 +200,7 @@
175200 }
176201 }
177202
178
- if (cb_break != afs_cb_break_sum(vnode, vnode->cb_interest))
203
+ if (afs_cb_is_broken(cb_break, vnode))
179204 goto someone_else_changed_it;
180205
181206 /* We need a ref on any permits list we want to copy as we'll have to
....@@ -252,14 +277,15 @@
252277
253278 kfree(new);
254279
280
+ rcu_read_lock();
255281 spin_lock(&vnode->lock);
256282 zap = rcu_access_pointer(vnode->permit_cache);
257
- if (cb_break == afs_cb_break_sum(vnode, vnode->cb_interest) &&
258
- zap == permits)
283
+ if (!afs_cb_is_broken(cb_break, vnode) && zap == permits)
259284 rcu_assign_pointer(vnode->permit_cache, replacement);
260285 else
261286 zap = replacement;
262287 spin_unlock(&vnode->lock);
288
+ rcu_read_unlock();
263289 afs_put_permits(zap);
264290 out_put:
265291 afs_put_permits(permits);
....@@ -275,6 +301,40 @@
275301 return;
276302 }
277303
304
+static bool afs_check_permit_rcu(struct afs_vnode *vnode, struct key *key,
305
+ afs_access_t *_access)
306
+{
307
+ const struct afs_permits *permits;
308
+ int i;
309
+
310
+ _enter("{%llx:%llu},%x",
311
+ vnode->fid.vid, vnode->fid.vnode, key_serial(key));
312
+
313
+ /* check the permits to see if we've got one yet */
314
+ if (key == vnode->volume->cell->anonymous_key) {
315
+ *_access = vnode->status.anon_access;
316
+ _leave(" = t [anon %x]", *_access);
317
+ return true;
318
+ }
319
+
320
+ permits = rcu_dereference(vnode->permit_cache);
321
+ if (permits) {
322
+ for (i = 0; i < permits->nr_permits; i++) {
323
+ if (permits->permits[i].key < key)
324
+ continue;
325
+ if (permits->permits[i].key > key)
326
+ break;
327
+
328
+ *_access = permits->permits[i].access;
329
+ _leave(" = %u [perm %x]", !permits->invalidated, *_access);
330
+ return !permits->invalidated;
331
+ }
332
+ }
333
+
334
+ _leave(" = f");
335
+ return false;
336
+}
337
+
278338 /*
279339 * check with the fileserver to see if the directory or parent directory is
280340 * permitted to be accessed with this authorisation, and if so, what access it
....@@ -287,7 +347,7 @@
287347 bool valid = false;
288348 int i, ret;
289349
290
- _enter("{%x:%u},%x",
350
+ _enter("{%llx:%llu},%x",
291351 vnode->fid.vid, vnode->fid.vnode, key_serial(key));
292352
293353 /* check the permits to see if we've got one yet */
....@@ -319,13 +379,12 @@
319379 */
320380 _debug("no valid permit");
321381
322
- ret = afs_fetch_status(vnode, key, false);
382
+ ret = afs_fetch_status(vnode, key, false, _access);
323383 if (ret < 0) {
324384 *_access = 0;
325385 _leave(" = %d", ret);
326386 return ret;
327387 }
328
- *_access = vnode->status.caller_access;
329388 }
330389
331390 _leave(" = 0 [access %x]", *_access);
....@@ -340,35 +399,44 @@
340399 int afs_permission(struct inode *inode, int mask)
341400 {
342401 struct afs_vnode *vnode = AFS_FS_I(inode);
343
- afs_access_t uninitialized_var(access);
402
+ afs_access_t access;
344403 struct key *key;
345
- int ret;
404
+ int ret = 0;
346405
347
- if (mask & MAY_NOT_BLOCK)
348
- return -ECHILD;
349
-
350
- _enter("{{%x:%u},%lx},%x,",
406
+ _enter("{{%llx:%llu},%lx},%x,",
351407 vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask);
352408
353
- key = afs_request_key(vnode->volume->cell);
354
- if (IS_ERR(key)) {
355
- _leave(" = %ld [key]", PTR_ERR(key));
356
- return PTR_ERR(key);
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;
357433 }
358
-
359
- ret = afs_validate(vnode, key);
360
- if (ret < 0)
361
- goto error;
362
-
363
- /* check the permits to see if we've got one yet */
364
- ret = afs_check_permit(vnode, key, &access);
365
- if (ret < 0)
366
- goto error;
367434
368435 /* interpret the access mask */
369436 _debug("REQ %x ACC %x on %s",
370437 mask, access, S_ISDIR(inode->i_mode) ? "dir" : "file");
371438
439
+ ret = 0;
372440 if (S_ISDIR(inode->i_mode)) {
373441 if (mask & (MAY_EXEC | MAY_READ | MAY_CHDIR)) {
374442 if (!(access & AFS_ACE_LOOKUP))