Skip to content

Commit 7a11275

Browse files
BoardzMasterl0kod
authored andcommitted
landlock: Refactor layer helpers
Add a new key_type argument to the landlock_init_layer_masks() helper. Add a masks_array_size argument to the landlock_unmask_layers() helper. These modifications support implementing new rule types in the next Landlock versions. Signed-off-by: Konstantin Meskhidze <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mickaël Salaün <[email protected]>
1 parent 0e74101 commit 7a11275

File tree

3 files changed

+66
-42
lines changed

3 files changed

+66
-42
lines changed

security/landlock/fs.c

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -442,20 +442,22 @@ static bool is_access_to_paths_allowed(
442442
}
443443

444444
if (unlikely(dentry_child1)) {
445-
landlock_unmask_layers(find_rule(domain, dentry_child1),
446-
landlock_init_layer_masks(
447-
domain, LANDLOCK_MASK_ACCESS_FS,
448-
&_layer_masks_child1),
449-
&_layer_masks_child1);
445+
landlock_unmask_layers(
446+
find_rule(domain, dentry_child1),
447+
landlock_init_layer_masks(
448+
domain, LANDLOCK_MASK_ACCESS_FS,
449+
&_layer_masks_child1, LANDLOCK_KEY_INODE),
450+
&_layer_masks_child1, ARRAY_SIZE(_layer_masks_child1));
450451
layer_masks_child1 = &_layer_masks_child1;
451452
child1_is_directory = d_is_dir(dentry_child1);
452453
}
453454
if (unlikely(dentry_child2)) {
454-
landlock_unmask_layers(find_rule(domain, dentry_child2),
455-
landlock_init_layer_masks(
456-
domain, LANDLOCK_MASK_ACCESS_FS,
457-
&_layer_masks_child2),
458-
&_layer_masks_child2);
455+
landlock_unmask_layers(
456+
find_rule(domain, dentry_child2),
457+
landlock_init_layer_masks(
458+
domain, LANDLOCK_MASK_ACCESS_FS,
459+
&_layer_masks_child2, LANDLOCK_KEY_INODE),
460+
&_layer_masks_child2, ARRAY_SIZE(_layer_masks_child2));
459461
layer_masks_child2 = &_layer_masks_child2;
460462
child2_is_directory = d_is_dir(dentry_child2);
461463
}
@@ -508,14 +510,15 @@ static bool is_access_to_paths_allowed(
508510

509511
rule = find_rule(domain, walker_path.dentry);
510512
allowed_parent1 = landlock_unmask_layers(
511-
rule, access_masked_parent1, layer_masks_parent1);
513+
rule, access_masked_parent1, layer_masks_parent1,
514+
ARRAY_SIZE(*layer_masks_parent1));
512515
allowed_parent2 = landlock_unmask_layers(
513-
rule, access_masked_parent2, layer_masks_parent2);
516+
rule, access_masked_parent2, layer_masks_parent2,
517+
ARRAY_SIZE(*layer_masks_parent2));
514518

515519
/* Stops when a rule from each layer grants access. */
516520
if (allowed_parent1 && allowed_parent2)
517521
break;
518-
519522
jump_up:
520523
if (walker_path.dentry == walker_path.mnt->mnt_root) {
521524
if (follow_up(&walker_path)) {
@@ -554,8 +557,8 @@ static inline int check_access_path(const struct landlock_ruleset *const domain,
554557
{
555558
layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {};
556559

557-
access_request =
558-
landlock_init_layer_masks(domain, access_request, &layer_masks);
560+
access_request = landlock_init_layer_masks(
561+
domain, access_request, &layer_masks, LANDLOCK_KEY_INODE);
559562
if (is_access_to_paths_allowed(domain, path, access_request,
560563
&layer_masks, NULL, 0, NULL, NULL))
561564
return 0;
@@ -641,15 +644,17 @@ static bool collect_domain_accesses(
641644
return true;
642645

643646
access_dom = landlock_init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS,
644-
layer_masks_dom);
647+
layer_masks_dom,
648+
LANDLOCK_KEY_INODE);
645649

646650
dget(dir);
647651
while (true) {
648652
struct dentry *parent_dentry;
649653

650654
/* Gets all layers allowing all domain accesses. */
651655
if (landlock_unmask_layers(find_rule(domain, dir), access_dom,
652-
layer_masks_dom)) {
656+
layer_masks_dom,
657+
ARRAY_SIZE(*layer_masks_dom))) {
653658
/*
654659
* Stops when all handled accesses are allowed by at
655660
* least one rule in each layer.
@@ -764,7 +769,7 @@ static int current_check_refer_path(struct dentry *const old_dentry,
764769
*/
765770
access_request_parent1 = landlock_init_layer_masks(
766771
dom, access_request_parent1 | access_request_parent2,
767-
&layer_masks_parent1);
772+
&layer_masks_parent1, LANDLOCK_KEY_INODE);
768773
if (is_access_to_paths_allowed(
769774
dom, new_dir, access_request_parent1,
770775
&layer_masks_parent1, NULL, 0, NULL, NULL))
@@ -1140,7 +1145,7 @@ static int hook_file_open(struct file *const file)
11401145
if (is_access_to_paths_allowed(
11411146
dom, &file->f_path,
11421147
landlock_init_layer_masks(dom, full_access_request,
1143-
&layer_masks),
1148+
&layer_masks, LANDLOCK_KEY_INODE),
11441149
&layer_masks, NULL, 0, NULL, NULL)) {
11451150
allowed_access = full_access_request;
11461151
} else {

security/landlock/ruleset.c

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -573,14 +573,15 @@ landlock_find_rule(const struct landlock_ruleset *const ruleset,
573573
/*
574574
* @layer_masks is read and may be updated according to the access request and
575575
* the matching rule.
576+
* @masks_array_size must be equal to ARRAY_SIZE(*layer_masks).
576577
*
577578
* Returns true if the request is allowed (i.e. relevant layer masks for the
578579
* request are empty).
579580
*/
580-
bool landlock_unmask_layers(
581-
const struct landlock_rule *const rule,
582-
const access_mask_t access_request,
583-
layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS])
581+
bool landlock_unmask_layers(const struct landlock_rule *const rule,
582+
const access_mask_t access_request,
583+
layer_mask_t (*const layer_masks)[],
584+
const size_t masks_array_size)
584585
{
585586
size_t layer_level;
586587

@@ -612,8 +613,7 @@ bool landlock_unmask_layers(
612613
* requested access.
613614
*/
614615
is_empty = true;
615-
for_each_set_bit(access_bit, &access_req,
616-
ARRAY_SIZE(*layer_masks)) {
616+
for_each_set_bit(access_bit, &access_req, masks_array_size) {
617617
if (layer->access & BIT_ULL(access_bit))
618618
(*layer_masks)[access_bit] &= ~layer_bit;
619619
is_empty = is_empty && !(*layer_masks)[access_bit];
@@ -624,6 +624,10 @@ bool landlock_unmask_layers(
624624
return false;
625625
}
626626

627+
typedef access_mask_t
628+
get_access_mask_t(const struct landlock_ruleset *const ruleset,
629+
const u16 layer_level);
630+
627631
/**
628632
* landlock_init_layer_masks - Initialize layer masks from an access request
629633
*
@@ -633,19 +637,34 @@ bool landlock_unmask_layers(
633637
* @domain: The domain that defines the current restrictions.
634638
* @access_request: The requested access rights to check.
635639
* @layer_masks: The layer masks to populate.
640+
* @key_type: The key type to switch between access masks of different types.
636641
*
637642
* Returns: An access mask where each access right bit is set which is handled
638643
* in any of the active layers in @domain.
639644
*/
640-
access_mask_t landlock_init_layer_masks(
641-
const struct landlock_ruleset *const domain,
642-
const access_mask_t access_request,
643-
layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS])
645+
access_mask_t
646+
landlock_init_layer_masks(const struct landlock_ruleset *const domain,
647+
const access_mask_t access_request,
648+
layer_mask_t (*const layer_masks)[],
649+
const enum landlock_key_type key_type)
644650
{
645651
access_mask_t handled_accesses = 0;
646-
size_t layer_level;
652+
size_t layer_level, num_access;
653+
get_access_mask_t *get_access_mask;
654+
655+
switch (key_type) {
656+
case LANDLOCK_KEY_INODE:
657+
get_access_mask = landlock_get_fs_access_mask;
658+
num_access = LANDLOCK_NUM_ACCESS_FS;
659+
break;
660+
default:
661+
WARN_ON_ONCE(1);
662+
return 0;
663+
}
664+
665+
memset(layer_masks, 0,
666+
array_size(sizeof((*layer_masks)[0]), num_access));
647667

648-
memset(layer_masks, 0, sizeof(*layer_masks));
649668
/* An empty access request can happen because of O_WRONLY | O_RDWR. */
650669
if (!access_request)
651670
return 0;
@@ -655,10 +674,9 @@ access_mask_t landlock_init_layer_masks(
655674
const unsigned long access_req = access_request;
656675
unsigned long access_bit;
657676

658-
for_each_set_bit(access_bit, &access_req,
659-
ARRAY_SIZE(*layer_masks)) {
677+
for_each_set_bit(access_bit, &access_req, num_access) {
660678
if (BIT_ULL(access_bit) &
661-
landlock_get_fs_access_mask(domain, layer_level)) {
679+
get_access_mask(domain, layer_level)) {
662680
(*layer_masks)[access_bit] |=
663681
BIT_ULL(layer_level);
664682
handled_accesses |= BIT_ULL(access_bit);

security/landlock/ruleset.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -267,14 +267,15 @@ landlock_get_fs_access_mask(const struct landlock_ruleset *const ruleset,
267267
LANDLOCK_ACCESS_FS_INITIALLY_DENIED;
268268
}
269269

270-
bool landlock_unmask_layers(
271-
const struct landlock_rule *const rule,
272-
const access_mask_t access_request,
273-
layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS]);
270+
bool landlock_unmask_layers(const struct landlock_rule *const rule,
271+
const access_mask_t access_request,
272+
layer_mask_t (*const layer_masks)[],
273+
const size_t masks_array_size);
274274

275-
access_mask_t landlock_init_layer_masks(
276-
const struct landlock_ruleset *const domain,
277-
const access_mask_t access_request,
278-
layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS]);
275+
access_mask_t
276+
landlock_init_layer_masks(const struct landlock_ruleset *const domain,
277+
const access_mask_t access_request,
278+
layer_mask_t (*const layer_masks)[],
279+
const enum landlock_key_type key_type);
279280

280281
#endif /* _SECURITY_LANDLOCK_RULESET_H */

0 commit comments

Comments
 (0)