Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

landlock: Transpose the layer masks data structure

The layer masks data structure tracks the requested but unfulfilled
access rights during an operation's security check. It stores one bit
for each combination of access right and layer index. If the bit is
set, that access right is not granted (yet) in the given layer and we
have to traverse the path further upwards to grant it.

Previously, the layer masks were stored as arrays mapping from access
right indices to layer_mask_t. The layer_mask_t value then indicates
all layers in which the given access right is still (tentatively)
denied.

This patch introduces struct layer_access_masks instead: This struct
contains an array with the access_mask_t of each (tentatively) denied
access right in that layer.

The hypothesis of this patch is that this simplifies the code enough
so that the resulting code will run faster:

* We can use bitwise operations in multiple places where we previously
looped over bits individually with macros. (Should require less
branch speculation and lends itself to better loop unrolling.)

* Code is ~75 lines smaller.

Other noteworthy changes:

* In no_more_access(), call a new helper function may_refer(), which
only solves the asymmetric case. Previously, the code interleaved
the checks for the two symmetric cases in RENAME_EXCHANGE. It feels
that the code is clearer when renames without RENAME_EXCHANGE are
more obviously the normal case.

Tradeoffs:

This change improves performance, at a slight size increase to the
layer masks data structure.

This fixes the size of the data structure at 32 bytes for all types of
access rights. (64, once we introduce a 17th filesystem access right).

For filesystem access rights, at the moment, the data structure has
the same size as before, but once we introduce the 17th filesystem
access right, it will double in size (from 32 to 64 bytes), as
access_mask_t grows from 16 to 32 bit [1].

Link: https://lore.kernel.org/all/20260120.haeCh4li9Vae@digikod.net/ [1]
Signed-off-by: Günther Noack <gnoack3000@gmail.com>
Link: https://lore.kernel.org/r/20260206151154.97915-5-gnoack3000@gmail.com
[mic: Cosmetic fixes, moved struct layer_access_masks definition]
Signed-off-by: Mickaël Salaün <mic@digikod.net>

authored by

Günther Noack and committed by
Mickaël Salaün
65b691f8 45f2a292

+271 -340
+22 -6
security/landlock/access.h
··· 61 61 static_assert(sizeof(typeof_member(union access_masks_all, masks)) == 62 62 sizeof(typeof_member(union access_masks_all, all))); 63 63 64 - typedef u16 layer_mask_t; 65 - 66 - /* Makes sure all layers can be checked. */ 67 - static_assert(BITS_PER_TYPE(layer_mask_t) >= LANDLOCK_MAX_NUM_LAYERS); 64 + /** 65 + * struct layer_access_masks - A boolean matrix of layers and access rights 66 + * 67 + * This has a bit for each combination of layer numbers and access rights. 68 + * During access checks, it is used to represent the access rights for each 69 + * layer which still need to be fulfilled. When all bits are 0, the access 70 + * request is considered to be fulfilled. 71 + */ 72 + struct layer_access_masks { 73 + /** 74 + * @access: The unfulfilled access rights for each layer. 75 + */ 76 + access_mask_t access[LANDLOCK_MAX_NUM_LAYERS]; 77 + }; 68 78 69 79 /* 70 - * Tracks domains responsible of a denied access. This is required to avoid 71 - * storing in each object the full layer_masks[] required by update_request(). 80 + * Tracks domains responsible of a denied access. This avoids storing in each 81 + * object the full matrix of per-layer unfulfilled access rights, which is 82 + * required by update_request(). 83 + * 84 + * Each nibble represents the layer index of the newest layer which denied a 85 + * certain access right. For file system access rights, the upper four bits are 86 + * the index of the layer which denies LANDLOCK_ACCESS_FS_IOCTL_DEV and the 87 + * lower nibble represents LANDLOCK_ACCESS_FS_TRUNCATE. 72 88 */ 73 89 typedef u8 deny_masks_t; 74 90
+25 -56
security/landlock/audit.c
··· 180 180 181 181 #endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */ 182 182 183 + /* Get the youngest layer that denied the access_request. */ 183 184 static size_t get_denied_layer(const struct landlock_ruleset *const domain, 184 185 access_mask_t *const access_request, 185 - const layer_mask_t (*const layer_masks)[], 186 - const size_t layer_masks_size) 186 + const struct layer_access_masks *masks) 187 187 { 188 - const unsigned long access_req = *access_request; 189 - unsigned long access_bit; 190 - access_mask_t missing = 0; 191 - long youngest_layer = -1; 192 - 193 - for_each_set_bit(access_bit, &access_req, layer_masks_size) { 194 - const layer_mask_t mask = (*layer_masks)[access_bit]; 195 - long layer; 196 - 197 - if (!mask) 198 - continue; 199 - 200 - /* __fls(1) == 0 */ 201 - layer = __fls(mask); 202 - if (layer > youngest_layer) { 203 - youngest_layer = layer; 204 - missing = BIT(access_bit); 205 - } else if (layer == youngest_layer) { 206 - missing |= BIT(access_bit); 188 + for (ssize_t i = ARRAY_SIZE(masks->access) - 1; i >= 0; i--) { 189 + if (masks->access[i] & *access_request) { 190 + *access_request &= masks->access[i]; 191 + return i; 207 192 } 208 193 } 209 194 210 - *access_request = missing; 211 - if (youngest_layer == -1) 212 - return domain->num_layers - 1; 213 - 214 - return youngest_layer; 195 + /* Not found - fall back to default values */ 196 + *access_request = 0; 197 + return domain->num_layers - 1; 215 198 } 216 199 217 200 #ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST ··· 204 221 const struct landlock_ruleset dom = { 205 222 .num_layers = 5, 206 223 }; 207 - const layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = { 208 - [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT(0), 209 - [BIT_INDEX(LANDLOCK_ACCESS_FS_READ_FILE)] = BIT(1), 210 - [BIT_INDEX(LANDLOCK_ACCESS_FS_READ_DIR)] = BIT(1) | BIT(0), 211 - [BIT_INDEX(LANDLOCK_ACCESS_FS_REMOVE_DIR)] = BIT(2), 224 + const struct layer_access_masks masks = { 225 + .access[0] = LANDLOCK_ACCESS_FS_EXECUTE | 226 + LANDLOCK_ACCESS_FS_READ_DIR, 227 + .access[1] = LANDLOCK_ACCESS_FS_READ_FILE | 228 + LANDLOCK_ACCESS_FS_READ_DIR, 229 + .access[2] = LANDLOCK_ACCESS_FS_REMOVE_DIR, 212 230 }; 213 231 access_mask_t access; 214 232 215 233 access = LANDLOCK_ACCESS_FS_EXECUTE; 216 - KUNIT_EXPECT_EQ(test, 0, 217 - get_denied_layer(&dom, &access, &layer_masks, 218 - sizeof(layer_masks))); 234 + KUNIT_EXPECT_EQ(test, 0, get_denied_layer(&dom, &access, &masks)); 219 235 KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_EXECUTE); 220 236 221 237 access = LANDLOCK_ACCESS_FS_READ_FILE; 222 - KUNIT_EXPECT_EQ(test, 1, 223 - get_denied_layer(&dom, &access, &layer_masks, 224 - sizeof(layer_masks))); 238 + KUNIT_EXPECT_EQ(test, 1, get_denied_layer(&dom, &access, &masks)); 225 239 KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_READ_FILE); 226 240 227 241 access = LANDLOCK_ACCESS_FS_READ_DIR; 228 - KUNIT_EXPECT_EQ(test, 1, 229 - get_denied_layer(&dom, &access, &layer_masks, 230 - sizeof(layer_masks))); 242 + KUNIT_EXPECT_EQ(test, 1, get_denied_layer(&dom, &access, &masks)); 231 243 KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_READ_DIR); 232 244 233 245 access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR; 234 - KUNIT_EXPECT_EQ(test, 1, 235 - get_denied_layer(&dom, &access, &layer_masks, 236 - sizeof(layer_masks))); 246 + KUNIT_EXPECT_EQ(test, 1, get_denied_layer(&dom, &access, &masks)); 237 247 KUNIT_EXPECT_EQ(test, access, 238 248 LANDLOCK_ACCESS_FS_READ_FILE | 239 249 LANDLOCK_ACCESS_FS_READ_DIR); 240 250 241 251 access = LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_READ_DIR; 242 - KUNIT_EXPECT_EQ(test, 1, 243 - get_denied_layer(&dom, &access, &layer_masks, 244 - sizeof(layer_masks))); 252 + KUNIT_EXPECT_EQ(test, 1, get_denied_layer(&dom, &access, &masks)); 245 253 KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_READ_DIR); 246 254 247 255 access = LANDLOCK_ACCESS_FS_WRITE_FILE; 248 - KUNIT_EXPECT_EQ(test, 4, 249 - get_denied_layer(&dom, &access, &layer_masks, 250 - sizeof(layer_masks))); 256 + KUNIT_EXPECT_EQ(test, 4, get_denied_layer(&dom, &access, &masks)); 251 257 KUNIT_EXPECT_EQ(test, access, 0); 252 258 } 253 259 ··· 342 370 return false; 343 371 } 344 372 345 - if (WARN_ON_ONCE(!!request->layer_masks ^ !!request->layer_masks_size)) 346 - return false; 347 - 348 373 if (request->deny_masks) { 349 374 if (WARN_ON_ONCE(!request->all_existing_optional_access)) 350 375 return false; ··· 375 406 if (missing) { 376 407 /* Gets the nearest domain that denies the request. */ 377 408 if (request->layer_masks) { 378 - youngest_layer = get_denied_layer( 379 - subject->domain, &missing, request->layer_masks, 380 - request->layer_masks_size); 409 + youngest_layer = get_denied_layer(subject->domain, 410 + &missing, 411 + request->layer_masks); 381 412 } else { 382 413 youngest_layer = get_layer_from_deny_masks( 383 - &missing, request->all_existing_optional_access, 414 + &missing, _LANDLOCK_ACCESS_FS_OPTIONAL, 384 415 request->deny_masks); 385 416 } 386 417 youngest_denied =
+1 -2
security/landlock/audit.h
··· 43 43 access_mask_t access; 44 44 45 45 /* Required fields for requests with layer masks. */ 46 - const layer_mask_t (*layer_masks)[]; 47 - size_t layer_masks_size; 46 + const struct layer_access_masks *layer_masks; 48 47 49 48 /* Required fields for requests with deny masks. */ 50 49 const access_mask_t all_existing_optional_access;
+24 -20
security/landlock/domain.c
··· 182 182 deny_masks_t 183 183 landlock_get_deny_masks(const access_mask_t all_existing_optional_access, 184 184 const access_mask_t optional_access, 185 - const layer_mask_t (*const layer_masks)[], 186 - const size_t layer_masks_size) 185 + const struct layer_access_masks *const masks) 187 186 { 188 187 const unsigned long access_opt = optional_access; 189 188 unsigned long access_bit; 190 189 deny_masks_t deny_masks = 0; 190 + access_mask_t all_denied = 0; 191 191 192 192 /* This may require change with new object types. */ 193 - WARN_ON_ONCE(access_opt != 194 - (optional_access & all_existing_optional_access)); 193 + WARN_ON_ONCE(!access_mask_subset(optional_access, 194 + all_existing_optional_access)); 195 195 196 - if (WARN_ON_ONCE(!layer_masks)) 196 + if (WARN_ON_ONCE(!masks)) 197 197 return 0; 198 198 199 199 if (WARN_ON_ONCE(!access_opt)) 200 200 return 0; 201 201 202 - for_each_set_bit(access_bit, &access_opt, layer_masks_size) { 203 - const layer_mask_t mask = (*layer_masks)[access_bit]; 202 + for (ssize_t i = ARRAY_SIZE(masks->access) - 1; i >= 0; i--) { 203 + const access_mask_t denied = masks->access[i] & optional_access; 204 + const unsigned long newly_denied = denied & ~all_denied; 204 205 205 - if (!mask) 206 + if (!newly_denied) 206 207 continue; 207 208 208 - /* __fls(1) == 0 */ 209 - deny_masks |= get_layer_deny_mask(all_existing_optional_access, 210 - access_bit, __fls(mask)); 209 + for_each_set_bit(access_bit, &newly_denied, 210 + 8 * sizeof(access_mask_t)) { 211 + deny_masks |= get_layer_deny_mask( 212 + all_existing_optional_access, access_bit, i); 213 + } 214 + all_denied |= denied; 211 215 } 212 216 return deny_masks; 213 217 } ··· 220 216 221 217 static void test_landlock_get_deny_masks(struct kunit *const test) 222 218 { 223 - const layer_mask_t layers1[BITS_PER_TYPE(access_mask_t)] = { 224 - [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(0) | 225 - BIT_ULL(9), 226 - [BIT_INDEX(LANDLOCK_ACCESS_FS_TRUNCATE)] = BIT_ULL(1), 227 - [BIT_INDEX(LANDLOCK_ACCESS_FS_IOCTL_DEV)] = BIT_ULL(2) | 228 - BIT_ULL(0), 219 + const struct layer_access_masks layers1 = { 220 + .access[0] = LANDLOCK_ACCESS_FS_EXECUTE | 221 + LANDLOCK_ACCESS_FS_IOCTL_DEV, 222 + .access[1] = LANDLOCK_ACCESS_FS_TRUNCATE, 223 + .access[2] = LANDLOCK_ACCESS_FS_IOCTL_DEV, 224 + .access[9] = LANDLOCK_ACCESS_FS_EXECUTE, 229 225 }; 230 226 231 227 KUNIT_EXPECT_EQ(test, 0x1, 232 228 landlock_get_deny_masks(_LANDLOCK_ACCESS_FS_OPTIONAL, 233 229 LANDLOCK_ACCESS_FS_TRUNCATE, 234 - &layers1, ARRAY_SIZE(layers1))); 230 + &layers1)); 235 231 KUNIT_EXPECT_EQ(test, 0x20, 236 232 landlock_get_deny_masks(_LANDLOCK_ACCESS_FS_OPTIONAL, 237 233 LANDLOCK_ACCESS_FS_IOCTL_DEV, 238 - &layers1, ARRAY_SIZE(layers1))); 234 + &layers1)); 239 235 KUNIT_EXPECT_EQ( 240 236 test, 0x21, 241 237 landlock_get_deny_masks(_LANDLOCK_ACCESS_FS_OPTIONAL, 242 238 LANDLOCK_ACCESS_FS_TRUNCATE | 243 239 LANDLOCK_ACCESS_FS_IOCTL_DEV, 244 - &layers1, ARRAY_SIZE(layers1))); 240 + &layers1)); 245 241 } 246 242 247 243 #endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */
+1 -2
security/landlock/domain.h
··· 122 122 deny_masks_t 123 123 landlock_get_deny_masks(const access_mask_t all_existing_optional_access, 124 124 const access_mask_t optional_access, 125 - const layer_mask_t (*const layer_masks)[], 126 - size_t layer_masks_size); 125 + const struct layer_access_masks *const masks); 127 126 128 127 int landlock_init_hierarchy_log(struct landlock_hierarchy *const hierarchy); 129 128
+157 -191
security/landlock/fs.c
··· 399 399 }; 400 400 401 401 /* 402 + * Returns true iff the child file with the given src_child access rights under 403 + * src_parent would result in having the same or fewer access rights if it were 404 + * moved under new_parent. 405 + */ 406 + static bool may_refer(const struct layer_access_masks *const src_parent, 407 + const struct layer_access_masks *const src_child, 408 + const struct layer_access_masks *const new_parent, 409 + const bool child_is_dir) 410 + { 411 + for (size_t i = 0; i < ARRAY_SIZE(new_parent->access); i++) { 412 + access_mask_t child_access = src_parent->access[i] & 413 + src_child->access[i]; 414 + access_mask_t parent_access = new_parent->access[i]; 415 + 416 + if (!child_is_dir) { 417 + child_access &= ACCESS_FILE; 418 + parent_access &= ACCESS_FILE; 419 + } 420 + 421 + if (!access_mask_subset(child_access, parent_access)) 422 + return false; 423 + } 424 + return true; 425 + } 426 + 427 + /* 402 428 * Check that a destination file hierarchy has more restrictions than a source 403 429 * file hierarchy. This is only used for link and rename actions. 404 430 * 405 - * @layer_masks_child2: Optional child masks. 431 + * Returns: true if child1 may be moved from parent1 to parent2 without 432 + * increasing its access rights. If child2 is set, an additional condition is 433 + * that child2 may be used from parent2 to parent1 without increasing its access 434 + * rights. 406 435 */ 407 - static bool no_more_access( 408 - const layer_mask_t (*const layer_masks_parent1)[LANDLOCK_NUM_ACCESS_FS], 409 - const layer_mask_t (*const layer_masks_child1)[LANDLOCK_NUM_ACCESS_FS], 410 - const bool child1_is_directory, 411 - const layer_mask_t (*const layer_masks_parent2)[LANDLOCK_NUM_ACCESS_FS], 412 - const layer_mask_t (*const layer_masks_child2)[LANDLOCK_NUM_ACCESS_FS], 413 - const bool child2_is_directory) 436 + static bool no_more_access(const struct layer_access_masks *const parent1, 437 + const struct layer_access_masks *const child1, 438 + const bool child1_is_dir, 439 + const struct layer_access_masks *const parent2, 440 + const struct layer_access_masks *const child2, 441 + const bool child2_is_dir) 414 442 { 415 - unsigned long access_bit; 443 + if (!may_refer(parent1, child1, parent2, child1_is_dir)) 444 + return false; 416 445 417 - for (access_bit = 0; access_bit < ARRAY_SIZE(*layer_masks_parent2); 418 - access_bit++) { 419 - /* Ignores accesses that only make sense for directories. */ 420 - const bool is_file_access = 421 - !!(BIT_ULL(access_bit) & ACCESS_FILE); 446 + if (!child2) 447 + return true; 422 448 423 - if (child1_is_directory || is_file_access) { 424 - /* 425 - * Checks if the destination restrictions are a 426 - * superset of the source ones (i.e. inherited access 427 - * rights without child exceptions): 428 - * restrictions(parent2) >= restrictions(child1) 429 - */ 430 - if ((((*layer_masks_parent1)[access_bit] & 431 - (*layer_masks_child1)[access_bit]) | 432 - (*layer_masks_parent2)[access_bit]) != 433 - (*layer_masks_parent2)[access_bit]) 434 - return false; 435 - } 436 - 437 - if (!layer_masks_child2) 438 - continue; 439 - if (child2_is_directory || is_file_access) { 440 - /* 441 - * Checks inverted restrictions for RENAME_EXCHANGE: 442 - * restrictions(parent1) >= restrictions(child2) 443 - */ 444 - if ((((*layer_masks_parent2)[access_bit] & 445 - (*layer_masks_child2)[access_bit]) | 446 - (*layer_masks_parent1)[access_bit]) != 447 - (*layer_masks_parent1)[access_bit]) 448 - return false; 449 - } 450 - } 451 - return true; 449 + return may_refer(parent2, child2, parent1, child2_is_dir); 452 450 } 453 451 454 452 #define NMA_TRUE(...) KUNIT_EXPECT_TRUE(test, no_more_access(__VA_ARGS__)) ··· 456 458 457 459 static void test_no_more_access(struct kunit *const test) 458 460 { 459 - const layer_mask_t rx0[LANDLOCK_NUM_ACCESS_FS] = { 460 - [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(0), 461 - [BIT_INDEX(LANDLOCK_ACCESS_FS_READ_FILE)] = BIT_ULL(0), 461 + const struct layer_access_masks rx0 = { 462 + .access[0] = LANDLOCK_ACCESS_FS_EXECUTE | 463 + LANDLOCK_ACCESS_FS_READ_FILE, 462 464 }; 463 - const layer_mask_t mx0[LANDLOCK_NUM_ACCESS_FS] = { 464 - [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(0), 465 - [BIT_INDEX(LANDLOCK_ACCESS_FS_MAKE_REG)] = BIT_ULL(0), 465 + const struct layer_access_masks mx0 = { 466 + .access[0] = LANDLOCK_ACCESS_FS_EXECUTE | 467 + LANDLOCK_ACCESS_FS_MAKE_REG, 466 468 }; 467 - const layer_mask_t x0[LANDLOCK_NUM_ACCESS_FS] = { 468 - [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(0), 469 + const struct layer_access_masks x0 = { 470 + .access[0] = LANDLOCK_ACCESS_FS_EXECUTE, 469 471 }; 470 - const layer_mask_t x1[LANDLOCK_NUM_ACCESS_FS] = { 471 - [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(1), 472 + const struct layer_access_masks x1 = { 473 + .access[1] = LANDLOCK_ACCESS_FS_EXECUTE, 472 474 }; 473 - const layer_mask_t x01[LANDLOCK_NUM_ACCESS_FS] = { 474 - [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(0) | 475 - BIT_ULL(1), 475 + const struct layer_access_masks x01 = { 476 + .access[0] = LANDLOCK_ACCESS_FS_EXECUTE, 477 + .access[1] = LANDLOCK_ACCESS_FS_EXECUTE, 476 478 }; 477 - const layer_mask_t allows_all[LANDLOCK_NUM_ACCESS_FS] = {}; 479 + const struct layer_access_masks allows_all = {}; 478 480 479 481 /* Checks without restriction. */ 480 482 NMA_TRUE(&x0, &allows_all, false, &allows_all, NULL, false); ··· 562 564 #undef NMA_TRUE 563 565 #undef NMA_FALSE 564 566 565 - static bool is_layer_masks_allowed( 566 - layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS]) 567 + static bool is_layer_masks_allowed(const struct layer_access_masks *masks) 567 568 { 568 - return !memchr_inv(layer_masks, 0, sizeof(*layer_masks)); 569 + return !memchr_inv(&masks->access, 0, sizeof(masks->access)); 569 570 } 570 571 571 572 /* 572 - * Removes @layer_masks accesses that are not requested. 573 + * Removes @masks accesses that are not requested. 573 574 * 574 575 * Returns true if the request is allowed, false otherwise. 575 576 */ 576 - static bool 577 - scope_to_request(const access_mask_t access_request, 578 - layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS]) 577 + static bool scope_to_request(const access_mask_t access_request, 578 + struct layer_access_masks *masks) 579 579 { 580 - const unsigned long access_req = access_request; 581 - unsigned long access_bit; 580 + bool saw_unfulfilled_access = false; 582 581 583 - if (WARN_ON_ONCE(!layer_masks)) 582 + if (WARN_ON_ONCE(!masks)) 584 583 return true; 585 584 586 - for_each_clear_bit(access_bit, &access_req, ARRAY_SIZE(*layer_masks)) 587 - (*layer_masks)[access_bit] = 0; 588 - 589 - return is_layer_masks_allowed(layer_masks); 585 + for (size_t i = 0; i < ARRAY_SIZE(masks->access); i++) { 586 + masks->access[i] &= access_request; 587 + if (masks->access[i]) 588 + saw_unfulfilled_access = true; 589 + } 590 + return !saw_unfulfilled_access; 590 591 } 591 592 592 593 #ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST ··· 593 596 static void test_scope_to_request_with_exec_none(struct kunit *const test) 594 597 { 595 598 /* Allows everything. */ 596 - layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {}; 599 + struct layer_access_masks masks = {}; 597 600 598 601 /* Checks and scopes with execute. */ 599 - KUNIT_EXPECT_TRUE(test, scope_to_request(LANDLOCK_ACCESS_FS_EXECUTE, 600 - &layer_masks)); 601 - KUNIT_EXPECT_EQ(test, 0, 602 - layer_masks[BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)]); 603 - KUNIT_EXPECT_EQ(test, 0, 604 - layer_masks[BIT_INDEX(LANDLOCK_ACCESS_FS_WRITE_FILE)]); 602 + KUNIT_EXPECT_TRUE(test, 603 + scope_to_request(LANDLOCK_ACCESS_FS_EXECUTE, &masks)); 604 + KUNIT_EXPECT_EQ(test, 0, masks.access[0]); 605 605 } 606 606 607 607 static void test_scope_to_request_with_exec_some(struct kunit *const test) 608 608 { 609 609 /* Denies execute and write. */ 610 - layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = { 611 - [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(0), 612 - [BIT_INDEX(LANDLOCK_ACCESS_FS_WRITE_FILE)] = BIT_ULL(1), 610 + struct layer_access_masks masks = { 611 + .access[0] = LANDLOCK_ACCESS_FS_EXECUTE, 612 + .access[1] = LANDLOCK_ACCESS_FS_WRITE_FILE, 613 613 }; 614 614 615 615 /* Checks and scopes with execute. */ 616 616 KUNIT_EXPECT_FALSE(test, scope_to_request(LANDLOCK_ACCESS_FS_EXECUTE, 617 - &layer_masks)); 618 - KUNIT_EXPECT_EQ(test, BIT_ULL(0), 619 - layer_masks[BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)]); 620 - KUNIT_EXPECT_EQ(test, 0, 621 - layer_masks[BIT_INDEX(LANDLOCK_ACCESS_FS_WRITE_FILE)]); 617 + &masks)); 618 + KUNIT_EXPECT_EQ(test, LANDLOCK_ACCESS_FS_EXECUTE, masks.access[0]); 619 + KUNIT_EXPECT_EQ(test, 0, masks.access[1]); 622 620 } 623 621 624 622 static void test_scope_to_request_without_access(struct kunit *const test) 625 623 { 626 624 /* Denies execute and write. */ 627 - layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = { 628 - [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(0), 629 - [BIT_INDEX(LANDLOCK_ACCESS_FS_WRITE_FILE)] = BIT_ULL(1), 625 + struct layer_access_masks masks = { 626 + .access[0] = LANDLOCK_ACCESS_FS_EXECUTE, 627 + .access[1] = LANDLOCK_ACCESS_FS_WRITE_FILE, 630 628 }; 631 629 632 630 /* Checks and scopes without access request. */ 633 - KUNIT_EXPECT_TRUE(test, scope_to_request(0, &layer_masks)); 634 - KUNIT_EXPECT_EQ(test, 0, 635 - layer_masks[BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)]); 636 - KUNIT_EXPECT_EQ(test, 0, 637 - layer_masks[BIT_INDEX(LANDLOCK_ACCESS_FS_WRITE_FILE)]); 631 + KUNIT_EXPECT_TRUE(test, scope_to_request(0, &masks)); 632 + KUNIT_EXPECT_EQ(test, 0, masks.access[0]); 633 + KUNIT_EXPECT_EQ(test, 0, masks.access[1]); 638 634 } 639 635 640 636 #endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */ ··· 636 646 * Returns true if there is at least one access right different than 637 647 * LANDLOCK_ACCESS_FS_REFER. 638 648 */ 639 - static bool 640 - is_eacces(const layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS], 641 - const access_mask_t access_request) 649 + static bool is_eacces(const struct layer_access_masks *masks, 650 + const access_mask_t access_request) 642 651 { 643 - unsigned long access_bit; 644 - /* LANDLOCK_ACCESS_FS_REFER alone must return -EXDEV. */ 645 - const unsigned long access_check = access_request & 646 - ~LANDLOCK_ACCESS_FS_REFER; 647 - 648 - if (!layer_masks) 652 + if (!masks) 649 653 return false; 650 654 651 - for_each_set_bit(access_bit, &access_check, ARRAY_SIZE(*layer_masks)) { 652 - if ((*layer_masks)[access_bit]) 655 + for (size_t i = 0; i < ARRAY_SIZE(masks->access); i++) { 656 + /* LANDLOCK_ACCESS_FS_REFER alone must return -EXDEV. */ 657 + if (masks->access[i] & access_request & 658 + ~LANDLOCK_ACCESS_FS_REFER) 653 659 return true; 654 660 } 655 661 return false; ··· 658 672 659 673 static void test_is_eacces_with_none(struct kunit *const test) 660 674 { 661 - const layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {}; 675 + const struct layer_access_masks masks = {}; 662 676 663 - IE_FALSE(&layer_masks, 0); 664 - IE_FALSE(&layer_masks, LANDLOCK_ACCESS_FS_REFER); 665 - IE_FALSE(&layer_masks, LANDLOCK_ACCESS_FS_EXECUTE); 666 - IE_FALSE(&layer_masks, LANDLOCK_ACCESS_FS_WRITE_FILE); 677 + IE_FALSE(&masks, 0); 678 + IE_FALSE(&masks, LANDLOCK_ACCESS_FS_REFER); 679 + IE_FALSE(&masks, LANDLOCK_ACCESS_FS_EXECUTE); 680 + IE_FALSE(&masks, LANDLOCK_ACCESS_FS_WRITE_FILE); 667 681 } 668 682 669 683 static void test_is_eacces_with_refer(struct kunit *const test) 670 684 { 671 - const layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = { 672 - [BIT_INDEX(LANDLOCK_ACCESS_FS_REFER)] = BIT_ULL(0), 685 + const struct layer_access_masks masks = { 686 + .access[0] = LANDLOCK_ACCESS_FS_REFER, 673 687 }; 674 688 675 - IE_FALSE(&layer_masks, 0); 676 - IE_FALSE(&layer_masks, LANDLOCK_ACCESS_FS_REFER); 677 - IE_FALSE(&layer_masks, LANDLOCK_ACCESS_FS_EXECUTE); 678 - IE_FALSE(&layer_masks, LANDLOCK_ACCESS_FS_WRITE_FILE); 689 + IE_FALSE(&masks, 0); 690 + IE_FALSE(&masks, LANDLOCK_ACCESS_FS_REFER); 691 + IE_FALSE(&masks, LANDLOCK_ACCESS_FS_EXECUTE); 692 + IE_FALSE(&masks, LANDLOCK_ACCESS_FS_WRITE_FILE); 679 693 } 680 694 681 695 static void test_is_eacces_with_write(struct kunit *const test) 682 696 { 683 - const layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = { 684 - [BIT_INDEX(LANDLOCK_ACCESS_FS_WRITE_FILE)] = BIT_ULL(0), 697 + const struct layer_access_masks masks = { 698 + .access[0] = LANDLOCK_ACCESS_FS_WRITE_FILE, 685 699 }; 686 700 687 - IE_FALSE(&layer_masks, 0); 688 - IE_FALSE(&layer_masks, LANDLOCK_ACCESS_FS_REFER); 689 - IE_FALSE(&layer_masks, LANDLOCK_ACCESS_FS_EXECUTE); 701 + IE_FALSE(&masks, 0); 702 + IE_FALSE(&masks, LANDLOCK_ACCESS_FS_REFER); 703 + IE_FALSE(&masks, LANDLOCK_ACCESS_FS_EXECUTE); 690 704 691 - IE_TRUE(&layer_masks, LANDLOCK_ACCESS_FS_WRITE_FILE); 705 + IE_TRUE(&masks, LANDLOCK_ACCESS_FS_WRITE_FILE); 692 706 } 693 707 694 708 #endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */ ··· 738 752 * - true if the access request is granted; 739 753 * - false otherwise. 740 754 */ 741 - static bool is_access_to_paths_allowed( 742 - const struct landlock_ruleset *const domain, 743 - const struct path *const path, 744 - const access_mask_t access_request_parent1, 745 - layer_mask_t (*const layer_masks_parent1)[LANDLOCK_NUM_ACCESS_FS], 746 - struct landlock_request *const log_request_parent1, 747 - struct dentry *const dentry_child1, 748 - const access_mask_t access_request_parent2, 749 - layer_mask_t (*const layer_masks_parent2)[LANDLOCK_NUM_ACCESS_FS], 750 - struct landlock_request *const log_request_parent2, 751 - struct dentry *const dentry_child2) 755 + static bool 756 + is_access_to_paths_allowed(const struct landlock_ruleset *const domain, 757 + const struct path *const path, 758 + const access_mask_t access_request_parent1, 759 + struct layer_access_masks *layer_masks_parent1, 760 + struct landlock_request *const log_request_parent1, 761 + struct dentry *const dentry_child1, 762 + const access_mask_t access_request_parent2, 763 + struct layer_access_masks *layer_masks_parent2, 764 + struct landlock_request *const log_request_parent2, 765 + struct dentry *const dentry_child2) 752 766 { 753 767 bool allowed_parent1 = false, allowed_parent2 = false, is_dom_check, 754 768 child1_is_directory = true, child2_is_directory = true; 755 769 struct path walker_path; 756 770 access_mask_t access_masked_parent1, access_masked_parent2; 757 - layer_mask_t _layer_masks_child1[LANDLOCK_NUM_ACCESS_FS], 758 - _layer_masks_child2[LANDLOCK_NUM_ACCESS_FS]; 759 - layer_mask_t(*layer_masks_child1)[LANDLOCK_NUM_ACCESS_FS] = NULL, 760 - (*layer_masks_child2)[LANDLOCK_NUM_ACCESS_FS] = NULL; 771 + struct layer_access_masks _layer_masks_child1, _layer_masks_child2; 772 + struct layer_access_masks *layer_masks_child1 = NULL, 773 + *layer_masks_child2 = NULL; 761 774 762 775 if (!access_request_parent1 && !access_request_parent2) 763 776 return true; ··· 796 811 } 797 812 798 813 if (unlikely(dentry_child1)) { 799 - landlock_unmask_layers( 800 - find_rule(domain, dentry_child1), 801 - landlock_init_layer_masks( 802 - domain, LANDLOCK_MASK_ACCESS_FS, 803 - &_layer_masks_child1, LANDLOCK_KEY_INODE), 804 - &_layer_masks_child1, ARRAY_SIZE(_layer_masks_child1)); 814 + if (landlock_init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS, 815 + &_layer_masks_child1, 816 + LANDLOCK_KEY_INODE)) 817 + landlock_unmask_layers(find_rule(domain, dentry_child1), 818 + &_layer_masks_child1); 805 819 layer_masks_child1 = &_layer_masks_child1; 806 820 child1_is_directory = d_is_dir(dentry_child1); 807 821 } 808 822 if (unlikely(dentry_child2)) { 809 - landlock_unmask_layers( 810 - find_rule(domain, dentry_child2), 811 - landlock_init_layer_masks( 812 - domain, LANDLOCK_MASK_ACCESS_FS, 813 - &_layer_masks_child2, LANDLOCK_KEY_INODE), 814 - &_layer_masks_child2, ARRAY_SIZE(_layer_masks_child2)); 823 + if (landlock_init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS, 824 + &_layer_masks_child2, 825 + LANDLOCK_KEY_INODE)) 826 + landlock_unmask_layers(find_rule(domain, dentry_child2), 827 + &_layer_masks_child2); 815 828 layer_masks_child2 = &_layer_masks_child2; 816 829 child2_is_directory = d_is_dir(dentry_child2); 817 830 } ··· 864 881 } 865 882 866 883 rule = find_rule(domain, walker_path.dentry); 867 - allowed_parent1 = allowed_parent1 || 868 - landlock_unmask_layers( 869 - rule, access_masked_parent1, 870 - layer_masks_parent1, 871 - ARRAY_SIZE(*layer_masks_parent1)); 872 - allowed_parent2 = allowed_parent2 || 873 - landlock_unmask_layers( 874 - rule, access_masked_parent2, 875 - layer_masks_parent2, 876 - ARRAY_SIZE(*layer_masks_parent2)); 884 + allowed_parent1 = 885 + allowed_parent1 || 886 + landlock_unmask_layers(rule, layer_masks_parent1); 887 + allowed_parent2 = 888 + allowed_parent2 || 889 + landlock_unmask_layers(rule, layer_masks_parent2); 877 890 878 891 /* Stops when a rule from each layer grants access. */ 879 892 if (allowed_parent1 && allowed_parent2) ··· 929 950 log_request_parent1->audit.u.path = *path; 930 951 log_request_parent1->access = access_masked_parent1; 931 952 log_request_parent1->layer_masks = layer_masks_parent1; 932 - log_request_parent1->layer_masks_size = 933 - ARRAY_SIZE(*layer_masks_parent1); 934 953 } 935 954 936 955 if (!allowed_parent2 && log_request_parent2) { ··· 937 960 log_request_parent2->audit.u.path = *path; 938 961 log_request_parent2->access = access_masked_parent2; 939 962 log_request_parent2->layer_masks = layer_masks_parent2; 940 - log_request_parent2->layer_masks_size = 941 - ARRAY_SIZE(*layer_masks_parent2); 942 963 } 943 964 #endif /* CONFIG_AUDIT */ 944 965 ··· 951 976 }; 952 977 const struct landlock_cred_security *const subject = 953 978 landlock_get_applicable_subject(current_cred(), masks, NULL); 954 - layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {}; 979 + struct layer_access_masks layer_masks; 955 980 struct landlock_request request = {}; 956 981 957 982 if (!subject) ··· 1026 1051 * - true if all the domain access rights are allowed for @dir; 1027 1052 * - false if the walk reached @mnt_root. 1028 1053 */ 1029 - static bool collect_domain_accesses( 1030 - const struct landlock_ruleset *const domain, 1031 - const struct dentry *const mnt_root, struct dentry *dir, 1032 - layer_mask_t (*const layer_masks_dom)[LANDLOCK_NUM_ACCESS_FS]) 1054 + static bool collect_domain_accesses(const struct landlock_ruleset *const domain, 1055 + const struct dentry *const mnt_root, 1056 + struct dentry *dir, 1057 + struct layer_access_masks *layer_masks_dom) 1033 1058 { 1034 - unsigned long access_dom; 1035 1059 bool ret = false; 1036 1060 1037 1061 if (WARN_ON_ONCE(!domain || !mnt_root || !dir || !layer_masks_dom)) ··· 1038 1064 if (is_nouser_or_private(dir)) 1039 1065 return true; 1040 1066 1041 - access_dom = landlock_init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS, 1042 - layer_masks_dom, 1043 - LANDLOCK_KEY_INODE); 1067 + if (!landlock_init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS, 1068 + layer_masks_dom, LANDLOCK_KEY_INODE)) 1069 + return true; 1044 1070 1045 1071 dget(dir); 1046 1072 while (true) { 1047 1073 struct dentry *parent_dentry; 1048 1074 1049 1075 /* Gets all layers allowing all domain accesses. */ 1050 - if (landlock_unmask_layers(find_rule(domain, dir), access_dom, 1051 - layer_masks_dom, 1052 - ARRAY_SIZE(*layer_masks_dom))) { 1076 + if (landlock_unmask_layers(find_rule(domain, dir), 1077 + layer_masks_dom)) { 1053 1078 /* 1054 1079 * Stops when all handled accesses are allowed by at 1055 1080 * least one rule in each layer. ··· 1136 1163 access_mask_t access_request_parent1, access_request_parent2; 1137 1164 struct path mnt_dir; 1138 1165 struct dentry *old_parent; 1139 - layer_mask_t layer_masks_parent1[LANDLOCK_NUM_ACCESS_FS] = {}, 1140 - layer_masks_parent2[LANDLOCK_NUM_ACCESS_FS] = {}; 1166 + struct layer_access_masks layer_masks_parent1 = {}, 1167 + layer_masks_parent2 = {}; 1141 1168 struct landlock_request request1 = {}, request2 = {}; 1142 1169 1143 1170 if (!subject) ··· 1613 1640 1614 1641 static int hook_file_open(struct file *const file) 1615 1642 { 1616 - layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {}; 1643 + struct layer_access_masks layer_masks = {}; 1617 1644 access_mask_t open_access_request, full_access_request, allowed_access, 1618 1645 optional_access; 1619 1646 const struct landlock_cred_security *const subject = ··· 1648 1675 &layer_masks, &request, NULL, 0, NULL, NULL, NULL)) { 1649 1676 allowed_access = full_access_request; 1650 1677 } else { 1651 - unsigned long access_bit; 1652 - const unsigned long access_req = full_access_request; 1653 - 1654 1678 /* 1655 1679 * Calculate the actual allowed access rights from layer_masks. 1656 - * Add each access right to allowed_access which has not been 1657 - * vetoed by any layer. 1680 + * Remove the access rights from the full access request which 1681 + * are still unfulfilled in any of the layers. 1658 1682 */ 1659 - allowed_access = 0; 1660 - for_each_set_bit(access_bit, &access_req, 1661 - ARRAY_SIZE(layer_masks)) { 1662 - if (!layer_masks[access_bit]) 1663 - allowed_access |= BIT_ULL(access_bit); 1664 - } 1683 + allowed_access = full_access_request; 1684 + for (size_t i = 0; i < ARRAY_SIZE(layer_masks.access); i++) 1685 + allowed_access &= ~layer_masks.access[i]; 1665 1686 } 1666 1687 1667 1688 /* ··· 1667 1700 landlock_file(file)->allowed_access = allowed_access; 1668 1701 #ifdef CONFIG_AUDIT 1669 1702 landlock_file(file)->deny_masks = landlock_get_deny_masks( 1670 - _LANDLOCK_ACCESS_FS_OPTIONAL, optional_access, &layer_masks, 1671 - ARRAY_SIZE(layer_masks)); 1703 + _LANDLOCK_ACCESS_FS_OPTIONAL, optional_access, &layer_masks); 1672 1704 #endif /* CONFIG_AUDIT */ 1673 1705 1674 1706 if (access_mask_subset(open_access_request, allowed_access))
+5 -4
security/landlock/net.c
··· 47 47 access_mask_t access_request) 48 48 { 49 49 __be16 port; 50 - layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_NET] = {}; 50 + struct layer_access_masks layer_masks = {}; 51 51 const struct landlock_rule *rule; 52 52 struct landlock_id id = { 53 53 .type = LANDLOCK_KEY_NET_PORT, ··· 191 191 access_request = landlock_init_layer_masks(subject->domain, 192 192 access_request, &layer_masks, 193 193 LANDLOCK_KEY_NET_PORT); 194 - if (landlock_unmask_layers(rule, access_request, &layer_masks, 195 - ARRAY_SIZE(layer_masks))) 194 + if (!access_request) 195 + return 0; 196 + 197 + if (landlock_unmask_layers(rule, &layer_masks)) 196 198 return 0; 197 199 198 200 audit_net.family = address->sa_family; ··· 205 203 .audit.u.net = &audit_net, 206 204 .access = access_request, 207 205 .layer_masks = &layer_masks, 208 - .layer_masks_size = ARRAY_SIZE(layer_masks), 209 206 }); 210 207 return -EACCES; 211 208 }
+34 -55
security/landlock/ruleset.c
··· 612 612 return NULL; 613 613 } 614 614 615 - /* 616 - * @layer_masks is read and may be updated according to the access request and 617 - * the matching rule. 618 - * @masks_array_size must be equal to ARRAY_SIZE(*layer_masks). 615 + /** 616 + * landlock_unmask_layers - Remove the access rights in @masks 617 + * which are granted in @rule 619 618 * 620 - * Returns true if the request is allowed (i.e. relevant layer masks for the 621 - * request are empty). 619 + * Updates the set of (per-layer) unfulfilled access rights @masks 620 + * so that all the access rights granted in @rule are removed from it 621 + * (because they are now fulfilled). 622 + * 623 + * @rule: A rule that grants a set of access rights for each layer 624 + * @masks: A matrix of unfulfilled access rights for each layer 625 + * 626 + * Returns true if the request is allowed (i.e. the access rights granted all 627 + * remaining unfulfilled access rights and masks has no leftover set bits). 622 628 */ 623 629 bool landlock_unmask_layers(const struct landlock_rule *const rule, 624 - const access_mask_t access_request, 625 - layer_mask_t (*const layer_masks)[], 626 - const size_t masks_array_size) 630 + struct layer_access_masks *masks) 627 631 { 628 - size_t layer_level; 629 - 630 - if (!access_request || !layer_masks) 632 + if (!masks) 631 633 return true; 632 634 if (!rule) 633 635 return false; ··· 644 642 * by only one rule, but by the union (binary OR) of multiple rules. 645 643 * E.g. /a/b <execute> + /a <read> => /a/b <execute + read> 646 644 */ 647 - for (layer_level = 0; layer_level < rule->num_layers; layer_level++) { 648 - const struct landlock_layer *const layer = 649 - &rule->layers[layer_level]; 650 - const layer_mask_t layer_bit = BIT_ULL(layer->level - 1); 651 - const unsigned long access_req = access_request; 652 - unsigned long access_bit; 653 - bool is_empty; 645 + for (size_t i = 0; i < rule->num_layers; i++) { 646 + const struct landlock_layer *const layer = &rule->layers[i]; 654 647 655 - /* 656 - * Records in @layer_masks which layer grants access to each requested 657 - * access: bit cleared if the related layer grants access. 658 - */ 659 - is_empty = true; 660 - for_each_set_bit(access_bit, &access_req, masks_array_size) { 661 - if (layer->access & BIT_ULL(access_bit)) 662 - (*layer_masks)[access_bit] &= ~layer_bit; 663 - is_empty = is_empty && !(*layer_masks)[access_bit]; 664 - } 665 - if (is_empty) 666 - return true; 648 + /* Clear the bits where the layer in the rule grants access. */ 649 + masks->access[layer->level - 1] &= ~layer->access; 667 650 } 668 - return false; 651 + 652 + for (size_t i = 0; i < ARRAY_SIZE(masks->access); i++) { 653 + if (masks->access[i]) 654 + return false; 655 + } 656 + return true; 669 657 } 670 658 671 659 typedef access_mask_t ··· 665 673 /** 666 674 * landlock_init_layer_masks - Initialize layer masks from an access request 667 675 * 668 - * Populates @layer_masks such that for each access right in @access_request, 676 + * Populates @masks such that for each access right in @access_request, 669 677 * the bits for all the layers are set where this access right is handled. 670 678 * 671 679 * @domain: The domain that defines the current restrictions. 672 680 * @access_request: The requested access rights to check. 673 - * @layer_masks: It must contain %LANDLOCK_NUM_ACCESS_FS or 674 - * %LANDLOCK_NUM_ACCESS_NET elements according to @key_type. 681 + * @masks: Layer access masks to populate. 675 682 * @key_type: The key type to switch between access masks of different types. 676 683 * 677 684 * Returns: An access mask where each access right bit is set which is handled ··· 679 688 access_mask_t 680 689 landlock_init_layer_masks(const struct landlock_ruleset *const domain, 681 690 const access_mask_t access_request, 682 - layer_mask_t (*const layer_masks)[], 691 + struct layer_access_masks *const masks, 683 692 const enum landlock_key_type key_type) 684 693 { 685 694 access_mask_t handled_accesses = 0; 686 - size_t layer_level, num_access; 687 695 get_access_mask_t *get_access_mask; 688 696 689 697 switch (key_type) { 690 698 case LANDLOCK_KEY_INODE: 691 699 get_access_mask = landlock_get_fs_access_mask; 692 - num_access = LANDLOCK_NUM_ACCESS_FS; 693 700 break; 694 701 695 702 #if IS_ENABLED(CONFIG_INET) 696 703 case LANDLOCK_KEY_NET_PORT: 697 704 get_access_mask = landlock_get_net_access_mask; 698 - num_access = LANDLOCK_NUM_ACCESS_NET; 699 705 break; 700 706 #endif /* IS_ENABLED(CONFIG_INET) */ 701 707 ··· 701 713 return 0; 702 714 } 703 715 704 - memset(layer_masks, 0, 705 - array_size(sizeof((*layer_masks)[0]), num_access)); 706 - 707 716 /* An empty access request can happen because of O_WRONLY | O_RDWR. */ 708 717 if (!access_request) 709 718 return 0; 710 719 711 - /* Saves all handled accesses per layer. */ 712 - for (layer_level = 0; layer_level < domain->num_layers; layer_level++) { 713 - const unsigned long access_req = access_request; 714 - const access_mask_t access_mask = 715 - get_access_mask(domain, layer_level); 716 - unsigned long access_bit; 720 + for (size_t i = 0; i < domain->num_layers; i++) { 721 + const access_mask_t handled = get_access_mask(domain, i); 717 722 718 - for_each_set_bit(access_bit, &access_req, num_access) { 719 - if (BIT_ULL(access_bit) & access_mask) { 720 - (*layer_masks)[access_bit] |= 721 - BIT_ULL(layer_level); 722 - handled_accesses |= BIT_ULL(access_bit); 723 - } 724 - } 723 + masks->access[i] = access_request & handled; 724 + handled_accesses |= masks->access[i]; 725 725 } 726 + for (size_t i = domain->num_layers; i < ARRAY_SIZE(masks->access); i++) 727 + masks->access[i] = 0; 728 + 726 729 return handled_accesses; 727 730 }
+2 -4
security/landlock/ruleset.h
··· 302 302 } 303 303 304 304 bool landlock_unmask_layers(const struct landlock_rule *const rule, 305 - const access_mask_t access_request, 306 - layer_mask_t (*const layer_masks)[], 307 - const size_t masks_array_size); 305 + struct layer_access_masks *masks); 308 306 309 307 access_mask_t 310 308 landlock_init_layer_masks(const struct landlock_ruleset *const domain, 311 309 const access_mask_t access_request, 312 - layer_mask_t (*const layer_masks)[], 310 + struct layer_access_masks *masks, 313 311 const enum landlock_key_type key_type); 314 312 315 313 #endif /* _SECURITY_LANDLOCK_RULESET_H */