Skip to content

Commit eee7d0f

Browse files
committed
landlock: Update various code to use landlock_domain
- Replace domain in landlock_cred with landlock_domain. - Replace landlock_merge_ruleset with landlock_domain_merge_ruleset. - Pull landlock_put_hierarchy out of domain.h. This allows domain.h to not depend on audit.h, as audit.h -> cred.h will need to depend on domain.h instead of ruleset.h after changing it to use the new domain struct. - Update uses of landlock_ruleset-domains to landlock_domain checkpath seems to not like the `layer_mask_t (*const layer_masks)[]` argument: WARNING: function definition argument 'layer_mask_t' should also have an identifier name torvalds#171: FILE: security/landlock/domain.h:397: +bool landlock_unmask_layers(const struct landlock_found_rule rule, WARNING: function definition argument 'layer_mask_t' should also have an identifier name torvalds#176: FILE: security/landlock/domain.h:402: +access_mask_t Signed-off-by: Tingmao Wang <m@maowtm.org>
1 parent 06eacee commit eee7d0f

File tree

11 files changed

+190
-169
lines changed

11 files changed

+190
-169
lines changed

security/landlock/audit.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ static void log_domain(struct landlock_hierarchy *const hierarchy)
134134
}
135135

136136
static struct landlock_hierarchy *
137-
get_hierarchy(const struct landlock_ruleset *const domain, const size_t layer)
137+
get_hierarchy(const struct landlock_domain *const domain, const size_t layer)
138138
{
139139
struct landlock_hierarchy *hierarchy = domain->hierarchy;
140140
ssize_t i;
@@ -167,7 +167,7 @@ static void test_get_hierarchy(struct kunit *const test)
167167
.parent = &dom1_hierarchy,
168168
.id = 30,
169169
};
170-
struct landlock_ruleset dom2 = {
170+
struct landlock_domain dom2 = {
171171
.hierarchy = &dom2_hierarchy,
172172
.num_layers = 3,
173173
};
@@ -180,7 +180,7 @@ static void test_get_hierarchy(struct kunit *const test)
180180

181181
#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */
182182

183-
static size_t get_denied_layer(const struct landlock_ruleset *const domain,
183+
static size_t get_denied_layer(const struct landlock_domain *const domain,
184184
access_mask_t *const access_request,
185185
const layer_mask_t (*const layer_masks)[],
186186
const size_t layer_masks_size)
@@ -218,7 +218,7 @@ static size_t get_denied_layer(const struct landlock_ruleset *const domain,
218218

219219
static void test_get_denied_layer(struct kunit *const test)
220220
{
221-
const struct landlock_ruleset dom = {
221+
const struct landlock_domain dom = {
222222
.num_layers = 5,
223223
};
224224
const layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {

security/landlock/cred.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
#include "common.h"
1515
#include "cred.h"
16-
#include "ruleset.h"
16+
#include "domain.h"
1717
#include "setup.h"
1818

1919
static void hook_cred_transfer(struct cred *const new,
@@ -23,7 +23,7 @@ static void hook_cred_transfer(struct cred *const new,
2323
landlock_cred(old);
2424

2525
if (old_llcred->domain) {
26-
landlock_get_ruleset(old_llcred->domain);
26+
landlock_get_domain(old_llcred->domain);
2727
*landlock_cred(new) = *old_llcred;
2828
}
2929
}
@@ -37,10 +37,10 @@ static int hook_cred_prepare(struct cred *const new,
3737

3838
static void hook_cred_free(struct cred *const cred)
3939
{
40-
struct landlock_ruleset *const dom = landlock_cred(cred)->domain;
41-
42-
if (dom)
43-
landlock_put_ruleset_deferred(dom);
40+
/*
41+
* landlock_put_domain_deferred does nothing if domain is NULL
42+
*/
43+
landlock_put_domain_deferred(landlock_cred(cred)->domain);
4444
}
4545

4646
#ifdef CONFIG_AUDIT

security/landlock/cred.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
#include "access.h"
1919
#include "limits.h"
20-
#include "ruleset.h"
20+
#include "domain.h"
2121
#include "setup.h"
2222

2323
/**
@@ -29,9 +29,9 @@
2929
*/
3030
struct landlock_cred_security {
3131
/**
32-
* @domain: Immutable ruleset enforced on a task.
32+
* @domain: Immutable domain enforced on a task.
3333
*/
34-
struct landlock_ruleset *domain;
34+
struct landlock_domain *domain;
3535

3636
#ifdef CONFIG_AUDIT
3737
/**
@@ -65,15 +65,15 @@ landlock_cred(const struct cred *cred)
6565
return cred->security + landlock_blob_sizes.lbs_cred;
6666
}
6767

68-
static inline struct landlock_ruleset *landlock_get_current_domain(void)
68+
static inline struct landlock_domain *landlock_get_current_domain(void)
6969
{
7070
return landlock_cred(current_cred())->domain;
7171
}
7272

7373
/*
7474
* The call needs to come from an RCU read-side critical section.
7575
*/
76-
static inline const struct landlock_ruleset *
76+
static inline const struct landlock_domain *
7777
landlock_get_task_domain(const struct task_struct *const task)
7878
{
7979
return landlock_cred(__task_cred(task))->domain;
@@ -114,7 +114,7 @@ landlock_get_applicable_subject(const struct cred *const cred,
114114
const union access_masks_all masks_all = {
115115
.masks = masks,
116116
};
117-
const struct landlock_ruleset *domain;
117+
const struct landlock_domain *domain;
118118
ssize_t layer_level;
119119

120120
if (!cred)
@@ -127,7 +127,7 @@ landlock_get_applicable_subject(const struct cred *const cred,
127127
for (layer_level = domain->num_layers - 1; layer_level >= 0;
128128
layer_level--) {
129129
union access_masks_all layer = {
130-
.masks = domain->access_masks[layer_level],
130+
.masks = dom_access_masks(domain)[layer_level],
131131
};
132132

133133
if (layer.all & masks_all.all) {

security/landlock/domain.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/uidgid.h>
2222

2323
#include "access.h"
24+
#include "audit.h"
2425
#include "common.h"
2526
#include "domain.h"
2627
#include "id.h"
@@ -788,6 +789,79 @@ landlock_get_deny_masks(const access_mask_t all_existing_optional_access,
788789
return deny_masks;
789790
}
790791

792+
void landlock_put_hierarchy(struct landlock_hierarchy *hierarchy)
793+
{
794+
while (hierarchy && refcount_dec_and_test(&hierarchy->usage)) {
795+
const struct landlock_hierarchy *const freeme = hierarchy;
796+
797+
landlock_log_drop_domain(hierarchy);
798+
landlock_free_hierarchy_details(hierarchy);
799+
hierarchy = hierarchy->parent;
800+
kfree(freeme);
801+
}
802+
}
803+
804+
/*
805+
* @layer_masks is read and may be updated according to the access request and
806+
* the matching rule.
807+
* @masks_array_size must be equal to ARRAY_SIZE(*layer_masks).
808+
*
809+
* Returns true if the request is allowed (i.e. relevant layer masks for the
810+
* request are empty).
811+
*/
812+
bool landlock_unmask_layers(const struct landlock_found_rule rule,
813+
const access_mask_t access_request,
814+
layer_mask_t (*const layer_masks)[],
815+
const size_t masks_array_size)
816+
{
817+
const struct landlock_layer *layer;
818+
819+
if (!access_request || !layer_masks)
820+
return true;
821+
822+
if (rule.layers_start == rule.layers_end)
823+
return false;
824+
825+
if (WARN_ON_ONCE(rule.layers_start > rule.layers_end))
826+
return false;
827+
828+
/* We should not have layers_start being NULL but layers_end not */
829+
if (WARN_ON_ONCE(rule.layers_start == NULL))
830+
return false;
831+
832+
/*
833+
* An access is granted if, for each policy layer, at least one rule
834+
* encountered on the pathwalk grants the requested access,
835+
* regardless of its position in the layer stack. We must then check
836+
* the remaining layers for each inode, from the first added layer to
837+
* the last one. When there is multiple requested accesses, for each
838+
* policy layer, the full set of requested accesses may not be granted
839+
* by only one rule, but by the union (binary OR) of multiple rules.
840+
* E.g. /a/b <execute> + /a <read> => /a/b <execute + read>
841+
*/
842+
dom_rule_for_each_layer(rule, layer)
843+
{
844+
const layer_mask_t layer_bit = BIT_ULL(layer->level - 1);
845+
const unsigned long access_req = access_request;
846+
unsigned long access_bit;
847+
bool is_empty;
848+
849+
/*
850+
* Records in @layer_masks which layer grants access to each requested
851+
* access: bit cleared if the related layer grants access.
852+
*/
853+
is_empty = true;
854+
for_each_set_bit(access_bit, &access_req, masks_array_size) {
855+
if (layer->access & BIT_ULL(access_bit))
856+
(*layer_masks)[access_bit] &= ~layer_bit;
857+
is_empty = is_empty && !(*layer_masks)[access_bit];
858+
}
859+
if (is_empty)
860+
return true;
861+
}
862+
return false;
863+
}
864+
791865
#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST
792866

793867
static void test_landlock_get_deny_masks(struct kunit *const test)

security/landlock/domain.h

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
#include <linux/slab.h>
2121

2222
#include "access.h"
23-
#include "audit.h"
2423
#include "ruleset.h"
2524
#include "coalesced_hash.h"
2625

@@ -393,16 +392,65 @@ landlock_get_hierarchy(struct landlock_hierarchy *const hierarchy)
393392
refcount_inc(&hierarchy->usage);
394393
}
395394

396-
static inline void landlock_put_hierarchy(struct landlock_hierarchy *hierarchy)
395+
void landlock_put_hierarchy(struct landlock_hierarchy *hierarchy);
396+
397+
bool landlock_unmask_layers(const struct landlock_found_rule rule,
398+
const access_mask_t access_request,
399+
layer_mask_t (*const layer_masks)[],
400+
const size_t masks_array_size);
401+
402+
access_mask_t
403+
landlock_init_layer_masks(const struct landlock_domain *const domain,
404+
const access_mask_t access_request,
405+
layer_mask_t (*const layer_masks)[],
406+
const enum landlock_key_type key_type);
407+
408+
static inline access_mask_t
409+
landlock_dom_get_fs_access_mask(const struct landlock_domain *const domain,
410+
const u16 layer_level)
411+
{
412+
/* Handles all initially denied by default access rights. */
413+
return dom_access_masks(domain)[layer_level].fs |
414+
_LANDLOCK_ACCESS_FS_INITIALLY_DENIED;
415+
}
416+
417+
static inline access_mask_t
418+
landlock_dom_get_net_access_mask(const struct landlock_domain *const domain,
419+
const u16 layer_level)
420+
{
421+
return dom_access_masks(domain)[layer_level].net;
422+
}
423+
424+
static inline access_mask_t
425+
landlock_dom_get_scope_mask(const struct landlock_domain *const domain,
426+
const u16 layer_level)
397427
{
398-
while (hierarchy && refcount_dec_and_test(&hierarchy->usage)) {
399-
const struct landlock_hierarchy *const freeme = hierarchy;
428+
return dom_access_masks(domain)[layer_level].scope;
429+
}
400430

401-
landlock_log_drop_domain(hierarchy);
402-
landlock_free_hierarchy_details(hierarchy);
403-
hierarchy = hierarchy->parent;
404-
kfree(freeme);
431+
/**
432+
* landlock_dom_union_access_masks - Return all access rights handled in
433+
* the domain
434+
*
435+
* @domain: Landlock domain
436+
*
437+
* Returns: an access_masks result of the OR of all the domain's access masks.
438+
*/
439+
static inline struct access_masks
440+
landlock_dom_union_access_masks(const struct landlock_domain *const domain)
441+
{
442+
union access_masks_all matches = {};
443+
size_t layer_level;
444+
445+
for (layer_level = 0; layer_level < domain->num_layers; layer_level++) {
446+
union access_masks_all layer = {
447+
.masks = dom_access_masks(domain)[layer_level],
448+
};
449+
450+
matches.all |= layer.all;
405451
}
452+
453+
return matches.masks;
406454
}
407455

408456
#endif /* _SECURITY_LANDLOCK_DOMAIN_H */

security/landlock/fs.c

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -360,26 +360,24 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
360360
*
361361
* Returns NULL if no rule is found or if @dentry is negative.
362362
*/
363-
static const struct landlock_rule *
364-
find_rule(const struct landlock_ruleset *const domain,
363+
static struct landlock_found_rule
364+
find_rule(const struct landlock_domain *const domain,
365365
const struct dentry *const dentry)
366366
{
367-
const struct landlock_rule *rule;
368367
const struct inode *inode;
369-
struct landlock_id id = {
370-
.type = LANDLOCK_KEY_INODE,
371-
};
368+
union landlock_key key;
369+
struct landlock_found_rule found_rule = {};
372370

373371
/* Ignores nonexistent leafs. */
374372
if (d_is_negative(dentry))
375-
return NULL;
373+
return found_rule;
376374

377375
inode = d_backing_inode(dentry);
378376
rcu_read_lock();
379-
id.key.object = rcu_dereference(landlock_inode(inode)->object);
380-
rule = landlock_find_rule(domain, id);
377+
key.object = rcu_dereference(landlock_inode(inode)->object);
378+
found_rule = dom_find_index_fs(domain, key);
381379
rcu_read_unlock();
382-
return rule;
380+
return found_rule;
383381
}
384382

385383
/*
@@ -753,7 +751,7 @@ static void test_is_eacces_with_write(struct kunit *const test)
753751
* - false otherwise.
754752
*/
755753
static bool is_access_to_paths_allowed(
756-
const struct landlock_ruleset *const domain,
754+
const struct landlock_domain *const domain,
757755
const struct path *const path,
758756
const access_mask_t access_request_parent1,
759757
layer_mask_t (*const layer_masks_parent1)[LANDLOCK_NUM_ACCESS_FS],
@@ -799,7 +797,7 @@ static bool is_access_to_paths_allowed(
799797
* a superset of the meaningful requested accesses).
800798
*/
801799
access_masked_parent1 = access_masked_parent2 =
802-
landlock_union_access_masks(domain).fs;
800+
landlock_dom_union_access_masks(domain).fs;
803801
is_dom_check = true;
804802
} else {
805803
if (WARN_ON_ONCE(dentry_child1 || dentry_child2))
@@ -838,7 +836,7 @@ static bool is_access_to_paths_allowed(
838836
* restriction.
839837
*/
840838
while (true) {
841-
const struct landlock_rule *rule;
839+
struct landlock_found_rule rule;
842840

843841
/*
844842
* If at least all accesses allowed on the destination are
@@ -1045,7 +1043,7 @@ static access_mask_t maybe_remove(const struct dentry *const dentry)
10451043
* - false if the walk reached @mnt_root.
10461044
*/
10471045
static bool collect_domain_accesses(
1048-
const struct landlock_ruleset *const domain,
1046+
const struct landlock_domain *const domain,
10491047
const struct dentry *const mnt_root, struct dentry *dir,
10501048
layer_mask_t (*const layer_masks_dom)[LANDLOCK_NUM_ACCESS_FS])
10511049
{
@@ -1814,7 +1812,7 @@ static bool control_current_fowner(struct fown_struct *const fown)
18141812

18151813
static void hook_file_set_fowner(struct file *file)
18161814
{
1817-
struct landlock_ruleset *prev_dom;
1815+
struct landlock_domain *prev_dom;
18181816
struct landlock_cred_security fown_subject = {};
18191817
size_t fown_layer = 0;
18201818

@@ -1826,7 +1824,7 @@ static void hook_file_set_fowner(struct file *file)
18261824
landlock_get_applicable_subject(
18271825
current_cred(), signal_scope, &fown_layer);
18281826
if (new_subject) {
1829-
landlock_get_ruleset(new_subject->domain);
1827+
landlock_get_domain(new_subject->domain);
18301828
fown_subject = *new_subject;
18311829
}
18321830
}
@@ -1838,12 +1836,12 @@ static void hook_file_set_fowner(struct file *file)
18381836
#endif /* CONFIG_AUDIT*/
18391837

18401838
/* May be called in an RCU read-side critical section. */
1841-
landlock_put_ruleset_deferred(prev_dom);
1839+
landlock_put_domain_deferred(prev_dom);
18421840
}
18431841

18441842
static void hook_file_free_security(struct file *file)
18451843
{
1846-
landlock_put_ruleset_deferred(landlock_file(file)->fown_subject.domain);
1844+
landlock_put_domain_deferred(landlock_file(file)->fown_subject.domain);
18471845
}
18481846

18491847
static struct security_hook_list landlock_hooks[] __ro_after_init = {

0 commit comments

Comments
 (0)