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