[RFC PATCH 2/2] landlock: transpose the layer masks data structure

Tingmao Wang m at maowtm.org
Sun Jan 25 01:52:13 UTC 2026


On 12/30/25 10:39, Günther Noack wrote:
> [...]
> diff --git a/security/landlock/audit.c b/security/landlock/audit.c
> index c52d079cdb77b..650bd7f5cb6be 100644
> --- a/security/landlock/audit.c
> +++ b/security/landlock/audit.c
> [...]
> -static size_t
> -get_layer_from_deny_masks(access_mask_t *const access_request,
> -			  const access_mask_t all_existing_optional_access,
> -			  const deny_masks_t deny_masks)
> +/*
> + * get_layer_from_fs_deny_masks - get the layer which denied the access request
> + *
> + * As a side effect, stores the denied access rights from that layer(!) in
> + * *access_request.
> + */
> +static size_t get_layer_from_fs_deny_masks(access_mask_t *const access_request,
> +					   const deny_masks_t deny_masks)
>  {
> -	const unsigned long access_opt = all_existing_optional_access;
> -	const unsigned long access_req = *access_request;
> -	access_mask_t missing = 0;
> +	const access_mask_t access_req = *access_request;
>  	size_t youngest_layer = 0;
> -	size_t access_index = 0;
> -	unsigned long access_bit;
> +	access_mask_t missing = 0;
>  
> -	/* This will require change with new object types. */
> -	WARN_ON_ONCE(access_opt != _LANDLOCK_ACCESS_FS_OPTIONAL);
> +	WARN_ON_ONCE((access_req | _LANDLOCK_ACCESS_FS_OPTIONAL) !=
> +		     _LANDLOCK_ACCESS_FS_OPTIONAL);
>  
> -	for_each_set_bit(access_bit, &access_opt,
> -			 BITS_PER_TYPE(access_mask_t)) {
> -		if (access_req & BIT(access_bit)) {
> -			const size_t layer =
> -				(deny_masks >> (access_index * 4)) &
> -				(LANDLOCK_MAX_NUM_LAYERS - 1);
> +	if (access_req & LANDLOCK_ACCESS_FS_TRUNCATE) {
> +		size_t layer = deny_masks & 0x0f;
>  
> -			if (layer > youngest_layer) {
> -				youngest_layer = layer;
> -				missing = BIT(access_bit);
> -			} else if (layer == youngest_layer) {
> -				missing |= BIT(access_bit);
> -			}
> -		}
> -		access_index++;
> +		missing |= LANDLOCK_ACCESS_FS_TRUNCATE;
> +		youngest_layer = max(youngest_layer, layer);
>  	}
> +	if (access_req & LANDLOCK_ACCESS_FS_IOCTL_DEV) {
> +		size_t layer = (deny_masks & 0xf0) >> 4;
>  
> +		if (layer > youngest_layer)
> +			missing = 0;
> +
> +		missing |= LANDLOCK_ACCESS_FS_IOCTL_DEV;

I think this should be under a `if (layer == youngest_layer)`. If layer <
youngest_layer, because *access_request is only supposed to contain the
missing access from the youngest denying layer, this would be incorrect.
Although I think it probably won't make a difference in practice right now
since we don't currently have any access request that has truncate and
ioctl at the same time.

> +		youngest_layer = max(youngest_layer, layer);
> +	}
>  	*access_request = missing;
>  	return youngest_layer;
>  }
>  
>  #ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST
>  
> -static void test_get_layer_from_deny_masks(struct kunit *const test)
> +static void test_get_layer_from_fs_deny_masks(struct kunit *const test)
>  {
>  	deny_masks_t deny_mask;
>  	access_mask_t access;
> [...]



More information about the Linux-security-module-archive mailing list