[PATCH v8 1/9] landlock: Add a place for flags to layer rules
Tingmao Wang
m at maowtm.org
Sun May 24 01:29:40 UTC 2026
On 5/23/26 21:48, Mickaël Salaün wrote:
> This patch doesn't build.
Missed a hunk in this patch (ended up in the next one), will add.
>> @@ -797,20 +803,28 @@ is_access_to_paths_allowed(const struct landlock_ruleset *const domain,
>> }
>>
>> if (unlikely(dentry_child1)) {
>> + /*
>> + * Get the layer masks for the child dentries for use by domain
>> + * check later. The rule_flags for child1 should have been
>> + * included in rule_flags_parent1 already (cf.
>> + * collect_domain_accesses), and is not relevant for domain check,
>> + * so we don't have to pass it to landlock_unmask_layers.
>> + */
>> if (landlock_init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS,
>> &_layer_masks_child1,
>> LANDLOCK_KEY_INODE))
>> landlock_unmask_layers(find_rule(domain, dentry_child1),
>> - &_layer_masks_child1);
>> + &_layer_masks_child1, NULL);
>> layer_masks_child1 = &_layer_masks_child1;
>> child1_is_directory = d_is_dir(dentry_child1);
>> }
>> if (unlikely(dentry_child2)) {
>> + /* See above comment for why NULL is passed as rule_flags_masks. */
>
> rule_flags_masks doesn't exist.
I guess I was probably referring to the rule_flags argument - will fix.
>> [...]
>> @@ -647,9 +648,14 @@ bool landlock_unmask_layers(const struct landlock_rule *const rule,
>> */
>> for (size_t i = 0; i < rule->num_layers; i++) {
>> const struct landlock_layer *const layer = &rule->layers[i];
>> + const layer_mask_t layer_bit = BIT_ULL(layer->level - 1);
>>
>
>> /* Clear the bits where the layer in the rule grants access. */
>> masks->access[layer->level - 1] &= ~layer->access;
>> +
>> + /* Collect rule flags for each layer. */
>> + if (rule_flags && layer->flags.quiet)
>> + rule_flags->quiet_masks |= layer_bit;
>
> Why not store the quiet bit in masks? That would not only be "access"
> bits anymore but it makes sense to store all this bits it the same
> place.
>
> We should then probably rename struct layer_access_masks to just struct
> layer_masks.
>
> We need to be careful to not increase too much the size of this struct
> though while keeping the [LANDLOCK_MAX_NUM_LAYERS] approach if possible
> (see Günther's commit that added it).
Most uses of struct layer_access_masks do not actually care about the rule
flags tho, e.g. in unmask_scoped_access, scope_to_request, or may_refer.
Such a rename would touch 31 places (and only a few of them would actually
touch the quiet flag).
If we want to refactor to make this be in the layer_access_masks (then
rename it), I guess there are 3 options, which do you prefer?
1. Add a u16 bitfield for which layers are quieted. Future rule flags
will be additional bitfields. struct layer_masks becomes 68 bytes (+4).
struct layer_masks {
access_mask_t access[LANDLOCK_MAX_NUM_LAYERS];
layer_mask_t quiet_layers;
};
2. Make the [LANDLOCK_MAX_NUM_LAYERS] array store both the access mask and
the quiet bit (or more bits for future rule flags). Size of struct stays
the same.
static_assert(LANDLOCK_NUM_ACCESS_NET <= LANDLOCK_NUM_ACCESS_FS);
static_assert(LANDLOCK_NUM_SCOPE <= LANDLOCK_NUM_ACCESS_FS);
struct layer_mask {
access_mask_t access:LANDLOCK_NUM_ACCESS_FS;
bool quiet:1;
};
struct layer_masks {
struct layer_mask layer[LANDLOCK_MAX_NUM_LAYERS];
};
(Maybe we can just make struct layer_masks a typedef to
layer_mask[LANDLOCK_MAX_NUM_LAYERS] instead? But currently not sure if
there are any gotchas with a typedef like that)
3. Mirror layer_access_masks::access[] - add a
rule_flags[LANDLOCK_MAX_NUM_LAYERS] too. struct layer_masks becomes 80
bytes (+16).
struct rule_flags {
bool quiet:1;
};
struct layer_masks {
/**
* @access: The unfulfilled access rights for each layer.
*/
access_mask_t access[LANDLOCK_MAX_NUM_LAYERS];
struct rule_flags rule_flags[LANDLOCK_MAX_NUM_LAYERS];
};
(3 seems very wasteful to me)
More information about the Linux-security-module-archive
mailing list