Skip to content

Commit 0e74101

Browse files
BoardzMasterl0kod
authored andcommitted
landlock: Move and rename layer helpers
Move and rename landlock_unmask_layers() and landlock_init_layer_masks() helpers to ruleset.c to share them with Landlock network implementation in following commits. 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 6146b61 commit 0e74101

File tree

3 files changed

+129
-115
lines changed

3 files changed

+129
-115
lines changed

security/landlock/fs.c

Lines changed: 21 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -215,60 +215,6 @@ find_rule(const struct landlock_ruleset *const domain,
215215
return rule;
216216
}
217217

218-
/*
219-
* @layer_masks is read and may be updated according to the access request and
220-
* the matching rule.
221-
*
222-
* Returns true if the request is allowed (i.e. relevant layer masks for the
223-
* request are empty).
224-
*/
225-
static inline bool
226-
unmask_layers(const struct landlock_rule *const rule,
227-
const access_mask_t access_request,
228-
layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS])
229-
{
230-
size_t layer_level;
231-
232-
if (!access_request || !layer_masks)
233-
return true;
234-
if (!rule)
235-
return false;
236-
237-
/*
238-
* An access is granted if, for each policy layer, at least one rule
239-
* encountered on the pathwalk grants the requested access,
240-
* regardless of its position in the layer stack. We must then check
241-
* the remaining layers for each inode, from the first added layer to
242-
* the last one. When there is multiple requested accesses, for each
243-
* policy layer, the full set of requested accesses may not be granted
244-
* by only one rule, but by the union (binary OR) of multiple rules.
245-
* E.g. /a/b <execute> + /a <read> => /a/b <execute + read>
246-
*/
247-
for (layer_level = 0; layer_level < rule->num_layers; layer_level++) {
248-
const struct landlock_layer *const layer =
249-
&rule->layers[layer_level];
250-
const layer_mask_t layer_bit = BIT_ULL(layer->level - 1);
251-
const unsigned long access_req = access_request;
252-
unsigned long access_bit;
253-
bool is_empty;
254-
255-
/*
256-
* Records in @layer_masks which layer grants access to each
257-
* requested access.
258-
*/
259-
is_empty = true;
260-
for_each_set_bit(access_bit, &access_req,
261-
ARRAY_SIZE(*layer_masks)) {
262-
if (layer->access & BIT_ULL(access_bit))
263-
(*layer_masks)[access_bit] &= ~layer_bit;
264-
is_empty = is_empty && !(*layer_masks)[access_bit];
265-
}
266-
if (is_empty)
267-
return true;
268-
}
269-
return false;
270-
}
271-
272218
/*
273219
* Allows access to pseudo filesystems that will never be mountable (e.g.
274220
* sockfs, pipefs), but can still be reachable through
@@ -293,50 +239,6 @@ get_raw_handled_fs_accesses(const struct landlock_ruleset *const domain)
293239
return access_dom;
294240
}
295241

296-
/**
297-
* init_layer_masks - Initialize layer masks from an access request
298-
*
299-
* Populates @layer_masks such that for each access right in @access_request,
300-
* the bits for all the layers are set where this access right is handled.
301-
*
302-
* @domain: The domain that defines the current restrictions.
303-
* @access_request: The requested access rights to check.
304-
* @layer_masks: The layer masks to populate.
305-
*
306-
* Returns: An access mask where each access right bit is set which is handled
307-
* in any of the active layers in @domain.
308-
*/
309-
static inline access_mask_t
310-
init_layer_masks(const struct landlock_ruleset *const domain,
311-
const access_mask_t access_request,
312-
layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS])
313-
{
314-
access_mask_t handled_accesses = 0;
315-
size_t layer_level;
316-
317-
memset(layer_masks, 0, sizeof(*layer_masks));
318-
/* An empty access request can happen because of O_WRONLY | O_RDWR. */
319-
if (!access_request)
320-
return 0;
321-
322-
/* Saves all handled accesses per layer. */
323-
for (layer_level = 0; layer_level < domain->num_layers; layer_level++) {
324-
const unsigned long access_req = access_request;
325-
unsigned long access_bit;
326-
327-
for_each_set_bit(access_bit, &access_req,
328-
ARRAY_SIZE(*layer_masks)) {
329-
if (BIT_ULL(access_bit) &
330-
landlock_get_fs_access_mask(domain, layer_level)) {
331-
(*layer_masks)[access_bit] |=
332-
BIT_ULL(layer_level);
333-
handled_accesses |= BIT_ULL(access_bit);
334-
}
335-
}
336-
}
337-
return handled_accesses;
338-
}
339-
340242
static access_mask_t
341243
get_handled_fs_accesses(const struct landlock_ruleset *const domain)
342244
{
@@ -540,18 +442,20 @@ static bool is_access_to_paths_allowed(
540442
}
541443

542444
if (unlikely(dentry_child1)) {
543-
unmask_layers(find_rule(domain, dentry_child1),
544-
init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS,
445+
landlock_unmask_layers(find_rule(domain, dentry_child1),
446+
landlock_init_layer_masks(
447+
domain, LANDLOCK_MASK_ACCESS_FS,
545448
&_layer_masks_child1),
546-
&_layer_masks_child1);
449+
&_layer_masks_child1);
547450
layer_masks_child1 = &_layer_masks_child1;
548451
child1_is_directory = d_is_dir(dentry_child1);
549452
}
550453
if (unlikely(dentry_child2)) {
551-
unmask_layers(find_rule(domain, dentry_child2),
552-
init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS,
454+
landlock_unmask_layers(find_rule(domain, dentry_child2),
455+
landlock_init_layer_masks(
456+
domain, LANDLOCK_MASK_ACCESS_FS,
553457
&_layer_masks_child2),
554-
&_layer_masks_child2);
458+
&_layer_masks_child2);
555459
layer_masks_child2 = &_layer_masks_child2;
556460
child2_is_directory = d_is_dir(dentry_child2);
557461
}
@@ -603,10 +507,10 @@ static bool is_access_to_paths_allowed(
603507
}
604508

605509
rule = find_rule(domain, walker_path.dentry);
606-
allowed_parent1 = unmask_layers(rule, access_masked_parent1,
607-
layer_masks_parent1);
608-
allowed_parent2 = unmask_layers(rule, access_masked_parent2,
609-
layer_masks_parent2);
510+
allowed_parent1 = landlock_unmask_layers(
511+
rule, access_masked_parent1, layer_masks_parent1);
512+
allowed_parent2 = landlock_unmask_layers(
513+
rule, access_masked_parent2, layer_masks_parent2);
610514

611515
/* Stops when a rule from each layer grants access. */
612516
if (allowed_parent1 && allowed_parent2)
@@ -650,7 +554,8 @@ static inline int check_access_path(const struct landlock_ruleset *const domain,
650554
{
651555
layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {};
652556

653-
access_request = init_layer_masks(domain, access_request, &layer_masks);
557+
access_request =
558+
landlock_init_layer_masks(domain, access_request, &layer_masks);
654559
if (is_access_to_paths_allowed(domain, path, access_request,
655560
&layer_masks, NULL, 0, NULL, NULL))
656561
return 0;
@@ -735,16 +640,16 @@ static bool collect_domain_accesses(
735640
if (is_nouser_or_private(dir))
736641
return true;
737642

738-
access_dom = init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS,
739-
layer_masks_dom);
643+
access_dom = landlock_init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS,
644+
layer_masks_dom);
740645

741646
dget(dir);
742647
while (true) {
743648
struct dentry *parent_dentry;
744649

745650
/* Gets all layers allowing all domain accesses. */
746-
if (unmask_layers(find_rule(domain, dir), access_dom,
747-
layer_masks_dom)) {
651+
if (landlock_unmask_layers(find_rule(domain, dir), access_dom,
652+
layer_masks_dom)) {
748653
/*
749654
* Stops when all handled accesses are allowed by at
750655
* least one rule in each layer.
@@ -857,7 +762,7 @@ static int current_check_refer_path(struct dentry *const old_dentry,
857762
* The LANDLOCK_ACCESS_FS_REFER access right is not required
858763
* for same-directory referer (i.e. no reparenting).
859764
*/
860-
access_request_parent1 = init_layer_masks(
765+
access_request_parent1 = landlock_init_layer_masks(
861766
dom, access_request_parent1 | access_request_parent2,
862767
&layer_masks_parent1);
863768
if (is_access_to_paths_allowed(
@@ -1234,7 +1139,8 @@ static int hook_file_open(struct file *const file)
12341139

12351140
if (is_access_to_paths_allowed(
12361141
dom, &file->f_path,
1237-
init_layer_masks(dom, full_access_request, &layer_masks),
1142+
landlock_init_layer_masks(dom, full_access_request,
1143+
&layer_masks),
12381144
&layer_masks, NULL, 0, NULL, NULL)) {
12391145
allowed_access = full_access_request;
12401146
} else {

security/landlock/ruleset.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,3 +569,101 @@ landlock_find_rule(const struct landlock_ruleset *const ruleset,
569569
}
570570
return NULL;
571571
}
572+
573+
/*
574+
* @layer_masks is read and may be updated according to the access request and
575+
* the matching rule.
576+
*
577+
* Returns true if the request is allowed (i.e. relevant layer masks for the
578+
* request are empty).
579+
*/
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])
584+
{
585+
size_t layer_level;
586+
587+
if (!access_request || !layer_masks)
588+
return true;
589+
if (!rule)
590+
return false;
591+
592+
/*
593+
* An access is granted if, for each policy layer, at least one rule
594+
* encountered on the pathwalk grants the requested access,
595+
* regardless of its position in the layer stack. We must then check
596+
* the remaining layers for each inode, from the first added layer to
597+
* the last one. When there is multiple requested accesses, for each
598+
* policy layer, the full set of requested accesses may not be granted
599+
* by only one rule, but by the union (binary OR) of multiple rules.
600+
* E.g. /a/b <execute> + /a <read> => /a/b <execute + read>
601+
*/
602+
for (layer_level = 0; layer_level < rule->num_layers; layer_level++) {
603+
const struct landlock_layer *const layer =
604+
&rule->layers[layer_level];
605+
const layer_mask_t layer_bit = BIT_ULL(layer->level - 1);
606+
const unsigned long access_req = access_request;
607+
unsigned long access_bit;
608+
bool is_empty;
609+
610+
/*
611+
* Records in @layer_masks which layer grants access to each
612+
* requested access.
613+
*/
614+
is_empty = true;
615+
for_each_set_bit(access_bit, &access_req,
616+
ARRAY_SIZE(*layer_masks)) {
617+
if (layer->access & BIT_ULL(access_bit))
618+
(*layer_masks)[access_bit] &= ~layer_bit;
619+
is_empty = is_empty && !(*layer_masks)[access_bit];
620+
}
621+
if (is_empty)
622+
return true;
623+
}
624+
return false;
625+
}
626+
627+
/**
628+
* landlock_init_layer_masks - Initialize layer masks from an access request
629+
*
630+
* Populates @layer_masks such that for each access right in @access_request,
631+
* the bits for all the layers are set where this access right is handled.
632+
*
633+
* @domain: The domain that defines the current restrictions.
634+
* @access_request: The requested access rights to check.
635+
* @layer_masks: The layer masks to populate.
636+
*
637+
* Returns: An access mask where each access right bit is set which is handled
638+
* in any of the active layers in @domain.
639+
*/
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])
644+
{
645+
access_mask_t handled_accesses = 0;
646+
size_t layer_level;
647+
648+
memset(layer_masks, 0, sizeof(*layer_masks));
649+
/* An empty access request can happen because of O_WRONLY | O_RDWR. */
650+
if (!access_request)
651+
return 0;
652+
653+
/* Saves all handled accesses per layer. */
654+
for (layer_level = 0; layer_level < domain->num_layers; layer_level++) {
655+
const unsigned long access_req = access_request;
656+
unsigned long access_bit;
657+
658+
for_each_set_bit(access_bit, &access_req,
659+
ARRAY_SIZE(*layer_masks)) {
660+
if (BIT_ULL(access_bit) &
661+
landlock_get_fs_access_mask(domain, layer_level)) {
662+
(*layer_masks)[access_bit] |=
663+
BIT_ULL(layer_level);
664+
handled_accesses |= BIT_ULL(access_bit);
665+
}
666+
}
667+
}
668+
return handled_accesses;
669+
}

security/landlock/ruleset.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,4 +267,14 @@ 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]);
274+
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]);
279+
270280
#endif /* _SECURITY_LANDLOCK_RULESET_H */

0 commit comments

Comments
 (0)