mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* linux-next: manual merge of the landlock tree with the origin tree
@ 2026-10-19 17:21 Mark Brown
  2026-10-19 21:15 ` Mickaël Salaün
  0 siblings, 1 reply; 2+ messages in thread
From: Mark Brown @ 2026-10-19 17:21 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: Linux Kernel Mailing List, Linux Next Mailing List, Nguyen Ngoc Thang

[-- Attachment #1: Type: text/plain, Size: 6845 bytes --]

Hi all,

Today's linux-next merge of the landlock tree got a conflict in:

  security/landlock/domain.h

between commit:

  3d8cc52db2f86 ("landlock: Drop __counted_by from landlock_domain.handled_masks")

from the origin tree and commit:

  395c985dac578 ("landlock: Wrap per-layer access masks in struct layer_config")

from the landlock tree.  I kept the __counted_by in the hope that the
refactoring helped the compiler figure out what's going on.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined security/landlock/domain.h
index 428c1d9890dbf,60e8eb2d6ac27..0000000000000
--- a/security/landlock/domain.h
+++ b/security/landlock/domain.h
@@@ -130,10 -130,15 +130,15 @@@ struct landlock_hierarchy 
  		 */
  		log_new_exec : 1;
  	/**
- 	 * @quiet_masks: Bitmasks of access that should be quieted (i.e. not
+ 	 * @quiet_access: Bitmasks of access that should be quieted (i.e. not
  	 * logged) if the related object is marked as quiet.
  	 */
- 	struct access_masks quiet_masks;
+ 	struct access_masks quiet_access;
+ 	/**
+ 	 * @quiet_permission: Per-member quiet bitmasks for permission types in
+ 	 * this layer.
+ 	 */
+ 	struct permission_masks quiet_permission;
  #endif /* CONFIG_SECURITY_LANDLOCK_LOG */
  };
  
@@@ -217,7 -222,7 +222,7 @@@ struct landlock_domain 
  		 * @work_free: Enables to free a domain within a lockless
  		 * section.  This is only used by landlock_put_domain_deferred()
  		 * when @usage reaches zero.  The fields @usage, @num_layers and
- 		 * @handled_masks are then unused.
+ 		 * @layers are then unused.
  		 */
  		struct work_struct work_free;
  		struct {
@@@ -233,23 -238,16 +238,16 @@@
  			 */
  			u32 num_layers;
  			/**
- 			 * @handled_masks: Contains the subset of filesystem and
- 			 * network actions that are restricted by a domain.  A
- 			 * domain saves all layers of merged rulesets in a stack
- 			 * (FAM), starting from the first layer to the last one.
- 			 * These layers are used when merging rulesets, for user
- 			 * space backward compatibility (i.e. future-proof), and
- 			 * to properly handle merged rulesets without
- 			 * overlapping access rights.  These layers are set once
- 			 * and never changed for the lifetime of the domain.
- 			 *
- 			 * Not annotated with __counted_by(num_layers): clang
- 			 * miscomputes the counter address for a FAM nested in
- 			 * an anonymous struct within a union, which trips
- 			 * FORTIFY:
- 			 * https://github.com/llvm/llvm-project/pull/228309
+ 			 * @layers: Per-layer access configuration.  A domain
+ 			 * saves all layers of merged rulesets in a stack (FAM),
+ 			 * starting from the first layer to the last one.  These
+ 			 * layers are used when merging rulesets, for user space
+ 			 * backward compatibility (i.e. future-proof), and to
+ 			 * properly handle merged rulesets without overlapping
+ 			 * access rights.  These layers are set once and never
+ 			 * changed for the lifetime of the domain.
  			 */
- 			struct access_masks handled_masks[];
+ 			struct layer_config layers[] __counted_by(num_layers);
  		};
  	};
  };
@@@ -259,7 -257,7 +257,7 @@@ landlock_get_fs_access_mask(const struc
  			    const u16 layer_level)
  {
  	/* Handles all initially denied by default access rights. */
- 	return domain->handled_masks[layer_level].fs |
+ 	return domain->layers[layer_level].handled.fs |
  	       _LANDLOCK_ACCESS_FS_INITIALLY_DENIED;
  }
  
@@@ -267,14 -265,14 +265,14 @@@ static inline access_mask_
  landlock_get_net_access_mask(const struct landlock_domain *const domain,
  			     const u16 layer_level)
  {
- 	return domain->handled_masks[layer_level].net;
+ 	return domain->layers[layer_level].handled.net;
  }
  
  static inline access_mask_t
  landlock_get_scope_mask(const struct landlock_domain *const domain,
  			const u16 layer_level)
  {
- 	return domain->handled_masks[layer_level].scope;
+ 	return domain->layers[layer_level].handled.scope;
  }
  
  /**
@@@ -293,7 -291,7 +291,7 @@@ landlock_union_access_masks(const struc
  
  	for (layer_level = 0; layer_level < domain->num_layers; layer_level++) {
  		union access_masks_all layer = {
- 			.masks = domain->handled_masks[layer_level],
+ 			.masks = domain->layers[layer_level].handled,
  		};
  
  		matches.all |= layer.all;
@@@ -329,4 -327,63 +327,63 @@@ static inline void landlock_get_domain(
  		refcount_inc(&domain->usage);
  }
  
+ /**
+  * landlock_permission_is_denied - Check if a permission request is denied
+  *
+  * @domain: The enforced domain.
+  * @permission_bit: The LANDLOCK_PERMISSION_* flag to check.  Must have
+  *                  exactly one bit set.
+  * @request_value: Compact bitmask to look for (e.g. the result of
+  *                 landlock_ns_type_to_bit()).  Must have exactly one bit set.
+  *
+  * Iterate from the youngest layer to the oldest.  For each layer that handles
+  * @permission_bit, check whether @request_value is present in the layer's
+  * allowed bitmask.  Return on the first (youngest) denying layer.
+  *
+  * Return: The youngest denying layer + 1, or 0 if allowed.
+  */
+ static inline size_t
+ landlock_permission_is_denied(const struct landlock_domain *const domain,
+ 			      const access_mask_t permission_bit,
+ 			      const u64 request_value)
+ {
+ 	ssize_t layer;
+ 
+ 	BUILD_BUG_ON(sizeof(permission_bit) > sizeof(u32));
+ 
+ 	if (WARN_ON_ONCE(hweight32(permission_bit) != 1) ||
+ 	    WARN_ON_ONCE(hweight64(request_value) != 1))
+ 		return domain->num_layers;
+ 
+ 	for (layer = domain->num_layers - 1; layer >= 0; layer--) {
+ 		u64 allowed;
+ 
+ 		if (!(domain->layers[layer].handled.permissions &
+ 		      permission_bit))
+ 			continue;
+ 
+ 		/*
+ 		 * Current callers pass only permission types with an explicit
+ 		 * case below.  The default catches a new caller missing its
+ 		 * member mask.
+ 		 */
+ 		switch (permission_bit) {
+ 		case LANDLOCK_PERMISSION_NAMESPACE_USE:
+ 			allowed = domain->layers[layer].allowed.ns_types;
+ 			break;
+ 		case LANDLOCK_PERMISSION_CAPABILITY_USE:
+ 			allowed = domain->layers[layer].allowed.caps;
+ 			break;
+ 		default:
+ 			WARN_ONCE(1, "Unknown permission %u\n",
+ 				  (unsigned int)permission_bit);
+ 			return layer + 1;
+ 		}
+ 
+ 		if (!(allowed & request_value))
+ 			return layer + 1;
+ 	}
+ 	return 0;
+ }
+ 
  #endif /* _SECURITY_LANDLOCK_DOMAIN_H */

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: linux-next: manual merge of the landlock tree with the origin tree
  2026-10-19 17:21 linux-next: manual merge of the landlock tree with the origin tree Mark Brown
@ 2026-10-19 21:15 ` Mickaël Salaün
  0 siblings, 0 replies; 2+ messages in thread
From: Mickaël Salaün @ 2026-10-19 21:15 UTC (permalink / raw)
  To: Mark Brown
  Cc: Linux Kernel Mailing List, Linux Next Mailing List, Nguyen Ngoc Thang

On Mon, Oct 19, 2026 at 06:21:54PM +0100, Mark Brown wrote:
> Hi all,
> 
> Today's linux-next merge of the landlock tree got a conflict in:
> 
>   security/landlock/domain.h
> 
> between commit:
> 
>   3d8cc52db2f86 ("landlock: Drop __counted_by from landlock_domain.handled_masks")

This commit was merged with v7.3-rc7

> 
> from the origin tree and commit:
> 
>   395c985dac578 ("landlock: Wrap per-layer access masks in struct layer_config")

This commit should no longer be in linux-next, it was a previous
mic/next branch.  The new mic/next branch now properly handles the
merge.

> 
> from the landlock tree.  I kept the __counted_by in the hope that the
> refactoring helped the compiler figure out what's going on.

The "Drop __counted_by" is correct and my new mic/next branch (from
Friday) is based on v7.3-rc7, so I guess the next-20261001/landlock
merge should just be removed.

> 
> I fixed it up (see below) and can carry the fix as necessary. This
> is now fixed as far as linux-next is concerned, but any non trivial
> conflicts should be mentioned to your upstream maintainer when your tree
> is submitted for merging.  You may also want to consider cooperating
> with the maintainer of the conflicting tree to minimise any particularly
> complex conflicts.
> 
> diff --combined security/landlock/domain.h
> index 428c1d9890dbf,60e8eb2d6ac27..0000000000000
> --- a/security/landlock/domain.h
> +++ b/security/landlock/domain.h
> @@@ -130,10 -130,15 +130,15 @@@ struct landlock_hierarchy 
>   		 */
>   		log_new_exec : 1;
>   	/**
> - 	 * @quiet_masks: Bitmasks of access that should be quieted (i.e. not
> + 	 * @quiet_access: Bitmasks of access that should be quieted (i.e. not
>   	 * logged) if the related object is marked as quiet.
>   	 */
> - 	struct access_masks quiet_masks;
> + 	struct access_masks quiet_access;
> + 	/**
> + 	 * @quiet_permission: Per-member quiet bitmasks for permission types in
> + 	 * this layer.
> + 	 */
> + 	struct permission_masks quiet_permission;
>   #endif /* CONFIG_SECURITY_LANDLOCK_LOG */
>   };
>   
> @@@ -217,7 -222,7 +222,7 @@@ struct landlock_domain 
>   		 * @work_free: Enables to free a domain within a lockless
>   		 * section.  This is only used by landlock_put_domain_deferred()
>   		 * when @usage reaches zero.  The fields @usage, @num_layers and
> - 		 * @handled_masks are then unused.
> + 		 * @layers are then unused.
>   		 */
>   		struct work_struct work_free;
>   		struct {
> @@@ -233,23 -238,16 +238,16 @@@
>   			 */
>   			u32 num_layers;
>   			/**
> - 			 * @handled_masks: Contains the subset of filesystem and
> - 			 * network actions that are restricted by a domain.  A
> - 			 * domain saves all layers of merged rulesets in a stack
> - 			 * (FAM), starting from the first layer to the last one.
> - 			 * These layers are used when merging rulesets, for user
> - 			 * space backward compatibility (i.e. future-proof), and
> - 			 * to properly handle merged rulesets without
> - 			 * overlapping access rights.  These layers are set once
> - 			 * and never changed for the lifetime of the domain.
> - 			 *
> - 			 * Not annotated with __counted_by(num_layers): clang
> - 			 * miscomputes the counter address for a FAM nested in
> - 			 * an anonymous struct within a union, which trips
> - 			 * FORTIFY:
> - 			 * https://github.com/llvm/llvm-project/pull/228309
> + 			 * @layers: Per-layer access configuration.  A domain
> + 			 * saves all layers of merged rulesets in a stack (FAM),
> + 			 * starting from the first layer to the last one.  These
> + 			 * layers are used when merging rulesets, for user space
> + 			 * backward compatibility (i.e. future-proof), and to
> + 			 * properly handle merged rulesets without overlapping
> + 			 * access rights.  These layers are set once and never
> + 			 * changed for the lifetime of the domain.
>   			 */
> - 			struct access_masks handled_masks[];
> + 			struct layer_config layers[] __counted_by(num_layers);
>   		};
>   	};
>   };
> @@@ -259,7 -257,7 +257,7 @@@ landlock_get_fs_access_mask(const struc
>   			    const u16 layer_level)
>   {
>   	/* Handles all initially denied by default access rights. */
> - 	return domain->handled_masks[layer_level].fs |
> + 	return domain->layers[layer_level].handled.fs |
>   	       _LANDLOCK_ACCESS_FS_INITIALLY_DENIED;
>   }
>   
> @@@ -267,14 -265,14 +265,14 @@@ static inline access_mask_
>   landlock_get_net_access_mask(const struct landlock_domain *const domain,
>   			     const u16 layer_level)
>   {
> - 	return domain->handled_masks[layer_level].net;
> + 	return domain->layers[layer_level].handled.net;
>   }
>   
>   static inline access_mask_t
>   landlock_get_scope_mask(const struct landlock_domain *const domain,
>   			const u16 layer_level)
>   {
> - 	return domain->handled_masks[layer_level].scope;
> + 	return domain->layers[layer_level].handled.scope;
>   }
>   
>   /**
> @@@ -293,7 -291,7 +291,7 @@@ landlock_union_access_masks(const struc
>   
>   	for (layer_level = 0; layer_level < domain->num_layers; layer_level++) {
>   		union access_masks_all layer = {
> - 			.masks = domain->handled_masks[layer_level],
> + 			.masks = domain->layers[layer_level].handled,
>   		};
>   
>   		matches.all |= layer.all;
> @@@ -329,4 -327,63 +327,63 @@@ static inline void landlock_get_domain(
>   		refcount_inc(&domain->usage);
>   }
>   
> + /**
> +  * landlock_permission_is_denied - Check if a permission request is denied
> +  *
> +  * @domain: The enforced domain.
> +  * @permission_bit: The LANDLOCK_PERMISSION_* flag to check.  Must have
> +  *                  exactly one bit set.
> +  * @request_value: Compact bitmask to look for (e.g. the result of
> +  *                 landlock_ns_type_to_bit()).  Must have exactly one bit set.
> +  *
> +  * Iterate from the youngest layer to the oldest.  For each layer that handles
> +  * @permission_bit, check whether @request_value is present in the layer's
> +  * allowed bitmask.  Return on the first (youngest) denying layer.
> +  *
> +  * Return: The youngest denying layer + 1, or 0 if allowed.
> +  */
> + static inline size_t
> + landlock_permission_is_denied(const struct landlock_domain *const domain,
> + 			      const access_mask_t permission_bit,
> + 			      const u64 request_value)
> + {
> + 	ssize_t layer;
> + 
> + 	BUILD_BUG_ON(sizeof(permission_bit) > sizeof(u32));
> + 
> + 	if (WARN_ON_ONCE(hweight32(permission_bit) != 1) ||
> + 	    WARN_ON_ONCE(hweight64(request_value) != 1))
> + 		return domain->num_layers;
> + 
> + 	for (layer = domain->num_layers - 1; layer >= 0; layer--) {
> + 		u64 allowed;
> + 
> + 		if (!(domain->layers[layer].handled.permissions &
> + 		      permission_bit))
> + 			continue;
> + 
> + 		/*
> + 		 * Current callers pass only permission types with an explicit
> + 		 * case below.  The default catches a new caller missing its
> + 		 * member mask.
> + 		 */
> + 		switch (permission_bit) {
> + 		case LANDLOCK_PERMISSION_NAMESPACE_USE:
> + 			allowed = domain->layers[layer].allowed.ns_types;
> + 			break;
> + 		case LANDLOCK_PERMISSION_CAPABILITY_USE:
> + 			allowed = domain->layers[layer].allowed.caps;
> + 			break;
> + 		default:
> + 			WARN_ONCE(1, "Unknown permission %u\n",
> + 				  (unsigned int)permission_bit);
> + 			return layer + 1;
> + 		}
> + 
> + 		if (!(allowed & request_value))
> + 			return layer + 1;
> + 	}
> + 	return 0;
> + }
> + 
>   #endif /* _SECURITY_LANDLOCK_DOMAIN_H */



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-19 21:15 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-19 17:21 linux-next: manual merge of the landlock tree with the origin tree Mark Brown
2026-10-19 21:15 ` Mickaël Salaün

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®