public inbox for linux-security-module@vger.kernel.org
 help / color / mirror / Atom feed
From: "Mickaël Salaün" <mic@digikod.net>
To: "Günther Noack" <gnoack3000@gmail.com>
Cc: linux-security-module@vger.kernel.org,
	Tingmao Wang <m@maowtm.org>,
	 Justin Suess <utilityemal77@gmail.com>,
	Samasth Norway Ananda <samasth.norway.ananda@oracle.com>,
	 Matthieu Buffet <matthieu@buffet.re>,
	Mikhail Ivanov <ivanov.mikhail1@huawei-partners.com>,
	 konstantin.meskhidze@huawei.com,
	Randy Dunlap <rdunlap@infradead.org>
Subject: Re: [PATCH v3 3/3] landlock: transpose the layer masks data structure
Date: Sat, 7 Feb 2026 11:17:34 +0100	[thread overview]
Message-ID: <20260207.zolaiy1ail8H@digikod.net> (raw)
In-Reply-To: <20260206151154.97915-5-gnoack3000@gmail.com>

On Fri, Feb 06, 2026 at 04:11:55PM +0100, Günther Noack wrote:
> The layer masks data structure tracks the requested but unfulfilled
> access rights during an operation's security check.  It stores one bit
> for each combination of access right and layer index.  If the bit is
> set, that access right is not granted (yet) in the given layer and we
> have to traverse the path further upwards to grant it.
> 
> Previously, the layer masks were stored as arrays mapping from access
> right indices to layer_mask_t.  The layer_mask_t value then indicates
> all layers in which the given access right is still (tentatively)
> denied.
> 
> This patch introduces struct layer_access_masks instead: This struct
> contains an array with the access_mask_t of each (tentatively) denied
> access right in that layer.
> 
> The hypothesis of this patch is that this simplifies the code enough
> so that the resulting code will run faster:
> 
> * We can use bitwise operations in multiple places where we previously
>   looped over bits individually with macros.  (Should require less
>   branch speculation and lends itself to better loop unrolling.)
> 
> * Code is ~75 lines smaller.
> 
> Other noteworthy changes:
> 
> * In no_more_access(), call a new helper function may_refer(), which
>   only solves the asymmetric case.  Previously, the code interleaved
>   the checks for the two symmetric cases in RENAME_EXCHANGE.  It feels
>   that the code is clearer when renames without RENAME_EXCHANGE are
>   more obviously the normal case.
> 
> Tradeoffs:
> 
> This change improves performance, at a slight size increase to the
> layer masks data structure.
> 
> This fixes the size of the data structure at 32 bytes for all types of
> access rights. (64, once we introduce a 17th filesystem access right).
> 
> For filesystem access rights, at the moment, the data structure has
> the same size as before, but once we introduce the 17th filesystem
> access right, it will double in size (from 32 to 64 bytes), as
> access_mask_t grows from 16 to 32 bit. [1]
> 
> Link: https://lore.kernel.org/all/20260120.haeCh4li9Vae@digikod.net/ [1]
> Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> ---
>  security/landlock/access.h  |  15 +-
>  security/landlock/audit.c   |  81 +++------
>  security/landlock/audit.h   |   3 +-
>  security/landlock/domain.c  |  45 ++---
>  security/landlock/domain.h  |   4 +-
>  security/landlock/fs.c      | 348 ++++++++++++++++--------------------
>  security/landlock/net.c     |   9 +-
>  security/landlock/ruleset.c |  89 ++++-----
>  security/landlock/ruleset.h |  21 ++-
>  9 files changed, 274 insertions(+), 341 deletions(-)
> 
> diff --git a/security/landlock/access.h b/security/landlock/access.h
> index bab403470a6c..f0a9afeb4a2a 100644
> --- a/security/landlock/access.h
> +++ b/security/landlock/access.h
> @@ -61,14 +61,15 @@ union access_masks_all {
>  static_assert(sizeof(typeof_member(union access_masks_all, masks)) ==
>  	      sizeof(typeof_member(union access_masks_all, all)));
>  
> -typedef u16 layer_mask_t;
> -
> -/* Makes sure all layers can be checked. */
> -static_assert(BITS_PER_TYPE(layer_mask_t) >= LANDLOCK_MAX_NUM_LAYERS);
> -
>  /*
> - * Tracks domains responsible of a denied access.  This is required to avoid
> - * storing in each object the full layer_masks[] required by update_request().
> + * Tracks domains responsible of a denied access.  This avoids storing in each
> + * object the full matrix of per-layer unfulfilled access rights, which is
> + * required by update_request().
> + *
> + * Each nibble represents the layer index of the newest layer which denied a
> + * certain access right.  For file system access rights, the upper four bits are
> + * the index of the layer which denies LANDLOCK_ACCESS_FS_IOCTL_DEV and the
> + * lower nibble represents LANDLOCK_ACCESS_FS_TRUNCATE.
>   */
>  typedef u8 deny_masks_t;
>  

> diff --git a/security/landlock/domain.c b/security/landlock/domain.c
> index a647b68e8d06..d2a4354feeb4 100644
> --- a/security/landlock/domain.c
> +++ b/security/landlock/domain.c
> @@ -7,6 +7,7 @@
>   * Copyright © 2024-2025 Microsoft Corporation
>   */
>  
> +#include "ruleset.h"

To avoid this new include (which makes a dependency on ruleset
definitions for domain-specific definitions), I moved the struct
layer_access_masks definition to access.h, which makes more sense
anyway.


>  #include <kunit/test.h>
>  #include <linux/bitops.h>
>  #include <linux/bits.h>

> diff --git a/security/landlock/domain.h b/security/landlock/domain.h
> index 621f054c9a2b..227066d667f7 100644
> --- a/security/landlock/domain.h
> +++ b/security/landlock/domain.h
> @@ -10,6 +10,7 @@
>  #ifndef _SECURITY_LANDLOCK_DOMAIN_H
>  #define _SECURITY_LANDLOCK_DOMAIN_H
>  
> +#include "ruleset.h"
>  #include <linux/limits.h>
>  #include <linux/mm.h>
>  #include <linux/path.h>

> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
> index 1a78cba662b2..1ceb5fd674c9 100644
> --- a/security/landlock/ruleset.h
> +++ b/security/landlock/ruleset.h
> @@ -301,15 +301,28 @@ landlock_get_scope_mask(const struct landlock_ruleset *const ruleset,
>  	return ruleset->access_masks[layer_level].scope;
>  }
>  
> +/**
> + * struct layer_access_masks - A boolean matrix of layers and access rights
> + *
> + * This has a bit for each combination of layer numbers and access rights.
> + * During access checks, it is used to represent the access rights for each
> + * layer which still need to be fulfilled.  When all bits are 0, the access
> + * request is considered to be fulfilled.
> + */
> +struct layer_access_masks {
> +	/**
> +	 * @access: The unfulfilled access rights for each layer.
> +	 */
> +	access_mask_t access[LANDLOCK_MAX_NUM_LAYERS];
> +};
> +
>  bool landlock_unmask_layers(const struct landlock_rule *const rule,
> -			    const access_mask_t access_request,
> -			    layer_mask_t (*const layer_masks)[],
> -			    const size_t masks_array_size);
> +			    struct layer_access_masks *masks);
>  
>  access_mask_t
>  landlock_init_layer_masks(const struct landlock_ruleset *const domain,
>  			  const access_mask_t access_request,
> -			  layer_mask_t (*const layer_masks)[],
> +			  struct layer_access_masks *masks,
>  			  const enum landlock_key_type key_type);
>  
>  #endif /* _SECURITY_LANDLOCK_RULESET_H */
> -- 
> 2.52.0
> 
> 

  reply	other threads:[~2026-02-07 10:17 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-06 15:11 [PATCH v3 0/3] landlock: Refactor layer masks Günther Noack
2026-02-06 15:11 ` [PATCH v3 1/3] selftests/landlock: Add filesystem access benchmark Günther Noack
2026-02-10 15:42   ` Mickaël Salaün
2026-02-06 15:11 ` [PATCH v3 2/3] landlock: access_mask_subset() helper Günther Noack
2026-02-06 15:11 ` [PATCH v3 3/3] landlock: transpose the layer masks data structure Günther Noack
2026-02-07 10:17   ` Mickaël Salaün [this message]
2026-02-06 17:03 ` [PATCH v3 0/3] landlock: Refactor layer masks Mickaël Salaün

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260207.zolaiy1ail8H@digikod.net \
    --to=mic@digikod.net \
    --cc=gnoack3000@gmail.com \
    --cc=ivanov.mikhail1@huawei-partners.com \
    --cc=konstantin.meskhidze@huawei.com \
    --cc=linux-security-module@vger.kernel.org \
    --cc=m@maowtm.org \
    --cc=matthieu@buffet.re \
    --cc=rdunlap@infradead.org \
    --cc=samasth.norway.ananda@oracle.com \
    --cc=utilityemal77@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox