All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH] loadpin: allow untoggleable enforcement on filesystems which don't appear to be read-only
@ 2026-10-23 17:15 Amelia Crate
  2026-10-23 17:30 ` sashiko-bot
  2026-10-24  1:38 ` Randy Dunlap
  0 siblings, 2 replies; 3+ messages in thread
From: Amelia Crate @ 2026-10-23 17:15 UTC (permalink / raw)
  To: Kees Cook, linux-security-module
  Cc: Paul Moore, James Morris, Serge E . Hallyn, Jonathan Corbet,
	linux-doc, linux-kernel, Amelia Crate

Some filesystems, such as composefs created from layers which are entirely
read-only, can't be easily detected as a read-only file system. In addition to
filesystems which are read-only without having a backing read-only block device
I believe this is also useful for cases where immutability of the filesystem is
enforced by the hypervisor or the host, such as 9p shares or virtiofs.

It is still desirable to enforce LoadPin and disallow toggling enforcement in these cases.
This patch gives system administrators a way to disallow toggling LoadPin enforcement even
when the immutability of a filesystem is unclear.

Signed-off-by: Amelia Crate <acrate@waldn.net>
Assisted-by: Codex:gpt-6
---
 Documentation/admin-guide/LSM/LoadPin.rst     |  8 +++++++-
 .../admin-guide/kernel-parameters.txt         |  7 +++++++
 security/loadpin/loadpin.c                    | 20 ++++++++++++++++++-
 3 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/Documentation/admin-guide/LSM/LoadPin.rst b/Documentation/admin-guide/LSM/LoadPin.rst
index a90fd9dac960..f1e8825d0fe8 100644
--- a/Documentation/admin-guide/LSM/LoadPin.rst
+++ b/Documentation/admin-guide/LSM/LoadPin.rst
@@ -16,10 +16,16 @@ boot ("``loadpin.enforce=0``").
 
 LoadPin starts pinning when it sees the first file loaded. If the
 block device backing the filesystem is not read-only, a sysctl is
-created to toggle pinning: ``/proc/sys/kernel/loadpin/enabled``. (Having
+created to toggle pinning: ``/proc/sys/kernel/loadpin/enforce``. (Having
 a mutable filesystem means pinning is mutable too, but having the
 sysctl allows for easy testing on systems with a mutable filesystem.)
 
+Some filesystems may appear to be mutable, but are in fact read-only.
+In this case, ``loadpin.force_enforce=1`` can be set to require enforcement
+of LoadPin on all filesystems. When LoadPin is enabled,
+``/proc/sys/kernel/loadpin/force_enforce`` reports the state of this option.
+This option is independent of whether LoadPin is enabled.
+
 It's also possible to exclude specific file types from LoadPin using kernel
 command line option "``loadpin.exclude``". By default, all files are
 included, but they can be excluded using kernel command line option such
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 1b2ae71def21..df8c145cc63d 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -3540,6 +3540,13 @@ Kernel parameters
 			Enable Live Update Orchestrator (LUO).
 			Default: off.
 
+	loadpin.force_enforce= [SECURITY]
+			Format: <bool>
+			Force LoadPin enforcement until reboot, even when the
+			pinned filesystem is not backed by a read-only block
+			device. Requires LoadPin to be enabled in the active LSM list.
+			Default: off.
+
 	lockd.nlm_grace_period=P  [NFS] Assign grace period.
 			Format: <integer>
 
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
index f71861f98e1a..b260ad299a2c 100644
--- a/security/loadpin/loadpin.c
+++ b/security/loadpin/loadpin.c
@@ -45,6 +45,7 @@ static void report_load(const char *origin, struct file *file, char *operation)
 }
 
 static int enforce = IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENFORCE);
+static bool force_enforce __ro_after_init;
 static char *exclude_read_files[READING_MAX_ID];
 static int ignore_read_file_id[READING_MAX_ID] __ro_after_init;
 static struct super_block *pinned_root;
@@ -60,11 +61,19 @@ static bool loadpin_root_writable;
 static int proc_handler_loadpin(const struct ctl_table *table, int dir,
 				void *buffer, size_t *lenp, loff_t *ppos)
 {
-	if (!loadpin_root_writable && SYSCTL_USER_TO_KERN(dir))
+	if ((force_enforce || !loadpin_root_writable) && SYSCTL_USER_TO_KERN(dir))
 		return -EINVAL;
 	return proc_dointvec_minmax(table, dir, buffer, lenp, ppos);
 }
 
+static int proc_handler_force_enforce(const struct ctl_table *table, int dir,
+				      void *buffer, size_t *lenp, loff_t *ppos)
+{
+	if (SYSCTL_USER_TO_KERN(dir))
+		return -EPERM;
+	return proc_dobool(table, dir, buffer, lenp, ppos);
+}
+
 static const struct ctl_table loadpin_sysctl_table[] = {
 	{
 		.procname       = "enforce",
@@ -75,6 +84,13 @@ static const struct ctl_table loadpin_sysctl_table[] = {
 		.extra1         = SYSCTL_ZERO,
 		.extra2         = SYSCTL_ONE,
 	},
+	{
+		.procname       = "force_enforce",
+		.data           = &force_enforce,
+		.maxlen         = sizeof(force_enforce),
+		.mode           = 0444,
+		.proc_handler   = proc_handler_force_enforce,
+	},
 };
 #endif
 
@@ -436,6 +452,8 @@ DEFINE_LSM(loadpin) = {
 };
 
 /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
+module_param(force_enforce, bool, 0);
+MODULE_PARM_DESC(force_enforce, "Always enforce module/firmware pinning");
 module_param(enforce, int, 0);
 MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
 module_param_array_named(exclude, exclude_read_files, charp, NULL, 0);
-- 
2.54.0


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

* Re: [RFC PATCH] loadpin: allow untoggleable enforcement on filesystems which don't appear to be read-only
  2026-10-23 17:15 [RFC PATCH] loadpin: allow untoggleable enforcement on filesystems which don't appear to be read-only Amelia Crate
@ 2026-10-23 17:30 ` sashiko-bot
  2026-10-24  1:38 ` Randy Dunlap
  1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-10-23 17:30 UTC (permalink / raw)
  To: linux-security-module

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] loadpin: force_enforce fails to enable enforce and locks it to 0
--

commit dc93f122a0f976e677fefeb791538922df5a6557
Author: Amelia Crate <acrate@waldn.net>

loadpin: allow untoggleable enforcement on filesystems which don't appear to be read-only

This commit adds the loadpin.force_enforce kernel parameter and a
corresponding read-only sysctl to prevent toggling LoadPin enforcement on
filesystems that are not backed by a read-only block device.

> diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
> index f71861f98e1ab..b260ad299a2cc 100644
> --- a/security/loadpin/loadpin.c
> +++ b/security/loadpin/loadpin.c
> @@ -45,6 +45,7 @@ static void report_load(const char *origin, struct file *file, char *operation)
>  }
>  
>  static int enforce = IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENFORCE);
> +static bool force_enforce __ro_after_init;
>  static char *exclude_read_files[READING_MAX_ID];
>  static int ignore_read_file_id[READING_MAX_ID] __ro_after_init;
>  static struct super_block *pinned_root;
> @@ -60,11 +61,19 @@ static bool loadpin_root_writable;
>  static int proc_handler_loadpin(const struct ctl_table *table, int dir,
>  				void *buffer, size_t *lenp, loff_t *ppos)
>  {
> -	if (!loadpin_root_writable && SYSCTL_USER_TO_KERN(dir))
> +	if ((force_enforce || !loadpin_root_writable) && SYSCTL_USER_TO_KERN(dir))
>  		return -EINVAL;
>  	return proc_dointvec_minmax(table, dir, buffer, lenp, ppos);
>  }

[Severity: High]
What happens when a system is booted with loadpin.force_enforce=1 while
enforce is 0 (for example, when CONFIG_SECURITY_LOADPIN_ENFORCE=n and
loadpin.enforce=1 is not passed on the command line, or when
loadpin.enforce=0 is passed)?

The documentation in Documentation/admin-guide/kernel-parameters.txt states
that loadpin.force_enforce=1 forces LoadPin enforcement until reboot and
only requires LoadPin to be enabled in the active LSM list, and
MODULE_PARM_DESC(force_enforce, ...) describes it as "Always enforce
module/firmware pinning".

However, force_enforce is only checked here in proc_handler_loadpin()
(under CONFIG_SYSCTL) to reject writes to /proc/sys/kernel/loadpin/enforce.
It never sets enforce = 1 in loadpin_init(), and it is not checked in
loadpin_check() or loadpin_sb_free_security():

security/loadpin/loadpin.c:loadpin_sb_free_security() {
	if (!IS_ERR_OR_NULL(pinned_root) && mnt_sb == pinned_root) {
		if (enforce) {
			pinned_root = ERR_PTR(-EIO);
			pr_info("umount pinned fs: refusing further loads\n");
		} else {
			pinned_root = NULL;
		}
	}
}

security/loadpin/loadpin.c:loadpin_check() {
	...
	if (IS_ERR_OR_NULL(pinned_root) ||
	    ((load_root != pinned_root) && !dm_verity_loadpin_is_bdev_trusted(load_root->s_bdev))) {
		if (unlikely(!enforce)) {
			report_load(origin, file, "pinning-ignored");
			return 0;
		}

		report_load(origin, file, "denied");
		return -EPERM;
	}
}

If enforce is 0 at boot and force_enforce is 1, won't LoadPin fail to
enforce pinning in loadpin_check() and loadpin_sb_free_security(), while
proc_handler_loadpin() simultaneously blocks userspace from enabling it via
/proc/sys/kernel/loadpin/enforce, locking LoadPin in non-enforcing mode
until reboot (and making force_enforce a complete no-op when
CONFIG_SYSCTL=n)?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261023171508.3460300-1-acrate@waldn.net?part=1

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

* Re: [RFC PATCH] loadpin: allow untoggleable enforcement on filesystems which don't appear to be read-only
  2026-10-23 17:15 [RFC PATCH] loadpin: allow untoggleable enforcement on filesystems which don't appear to be read-only Amelia Crate
  2026-10-23 17:30 ` sashiko-bot
@ 2026-10-24  1:38 ` Randy Dunlap
  1 sibling, 0 replies; 3+ messages in thread
From: Randy Dunlap @ 2026-10-24  1:38 UTC (permalink / raw)
  To: Amelia Crate, Kees Cook, linux-security-module
  Cc: Paul Moore, James Morris, Serge E . Hallyn, Jonathan Corbet,
	linux-doc, linux-kernel

Hi,

On 10/23/26 10:15 AM, Amelia Crate wrote:
> Some filesystems, such as composefs created from layers which are entirely
> read-only, can't be easily detected as a read-only file system. In addition to
> filesystems which are read-only without having a backing read-only block device
> I believe this is also useful for cases where immutability of the filesystem is
> enforced by the hypervisor or the host, such as 9p shares or virtiofs.
> 
> It is still desirable to enforce LoadPin and disallow toggling enforcement in these cases.
> This patch gives system administrators a way to disallow toggling LoadPin enforcement even
> when the immutability of a filesystem is unclear.
> 
> Signed-off-by: Amelia Crate <acrate@waldn.net>
> Assisted-by: Codex:gpt-6
> ---
>  Documentation/admin-guide/LSM/LoadPin.rst     |  8 +++++++-
>  .../admin-guide/kernel-parameters.txt         |  7 +++++++
>  security/loadpin/loadpin.c                    | 20 ++++++++++++++++++-
>  3 files changed, 33 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/admin-guide/LSM/LoadPin.rst b/Documentation/admin-guide/LSM/LoadPin.rst
> index a90fd9dac960..f1e8825d0fe8 100644
> --- a/Documentation/admin-guide/LSM/LoadPin.rst
> +++ b/Documentation/admin-guide/LSM/LoadPin.rst
> @@ -16,10 +16,16 @@ boot ("``loadpin.enforce=0``").
>  
>  LoadPin starts pinning when it sees the first file loaded. If the
>  block device backing the filesystem is not read-only, a sysctl is
> -created to toggle pinning: ``/proc/sys/kernel/loadpin/enabled``. (Having
> +created to toggle pinning: ``/proc/sys/kernel/loadpin/enforce``. (Having

Ah. The sysctl documentation had the incorrect name there.

Would it be possible to put all of these command line parameters / sysctls
in the same place instead of having one of them in LoadPin.rst and
another one in kernel-parameters.txt ?

Thanks.

>  a mutable filesystem means pinning is mutable too, but having the
>  sysctl allows for easy testing on systems with a mutable filesystem.)
>  
> +Some filesystems may appear to be mutable, but are in fact read-only.
> +In this case, ``loadpin.force_enforce=1`` can be set to require enforcement
> +of LoadPin on all filesystems. When LoadPin is enabled,
> +``/proc/sys/kernel/loadpin/force_enforce`` reports the state of this option.
> +This option is independent of whether LoadPin is enabled.
> +
>  It's also possible to exclude specific file types from LoadPin using kernel
>  command line option "``loadpin.exclude``". By default, all files are
>  included, but they can be excluded using kernel command line option such
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index 1b2ae71def21..df8c145cc63d 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -3540,6 +3540,13 @@ Kernel parameters
>  			Enable Live Update Orchestrator (LUO).
>  			Default: off.
>  
> +	loadpin.force_enforce= [SECURITY]
> +			Format: <bool>
> +			Force LoadPin enforcement until reboot, even when the
> +			pinned filesystem is not backed by a read-only block
> +			device. Requires LoadPin to be enabled in the active LSM list.
> +			Default: off.
> +
>  	lockd.nlm_grace_period=P  [NFS] Assign grace period.
>  			Format: <integer>
>  
> diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
> index f71861f98e1a..b260ad299a2c 100644
> --- a/security/loadpin/loadpin.c
> +++ b/security/loadpin/loadpin.c
> @@ -45,6 +45,7 @@ static void report_load(const char *origin, struct file *file, char *operation)
>  }
>  
>  static int enforce = IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENFORCE);
> +static bool force_enforce __ro_after_init;
>  static char *exclude_read_files[READING_MAX_ID];
>  static int ignore_read_file_id[READING_MAX_ID] __ro_after_init;
>  static struct super_block *pinned_root;
> @@ -60,11 +61,19 @@ static bool loadpin_root_writable;
>  static int proc_handler_loadpin(const struct ctl_table *table, int dir,
>  				void *buffer, size_t *lenp, loff_t *ppos)
>  {
> -	if (!loadpin_root_writable && SYSCTL_USER_TO_KERN(dir))
> +	if ((force_enforce || !loadpin_root_writable) && SYSCTL_USER_TO_KERN(dir))
>  		return -EINVAL;
>  	return proc_dointvec_minmax(table, dir, buffer, lenp, ppos);
>  }
>  
> +static int proc_handler_force_enforce(const struct ctl_table *table, int dir,
> +				      void *buffer, size_t *lenp, loff_t *ppos)
> +{
> +	if (SYSCTL_USER_TO_KERN(dir))
> +		return -EPERM;
> +	return proc_dobool(table, dir, buffer, lenp, ppos);
> +}
> +
>  static const struct ctl_table loadpin_sysctl_table[] = {
>  	{
>  		.procname       = "enforce",
> @@ -75,6 +84,13 @@ static const struct ctl_table loadpin_sysctl_table[] = {
>  		.extra1         = SYSCTL_ZERO,
>  		.extra2         = SYSCTL_ONE,
>  	},
> +	{
> +		.procname       = "force_enforce",
> +		.data           = &force_enforce,
> +		.maxlen         = sizeof(force_enforce),
> +		.mode           = 0444,
> +		.proc_handler   = proc_handler_force_enforce,
> +	},
>  };
>  #endif
>  
> @@ -436,6 +452,8 @@ DEFINE_LSM(loadpin) = {
>  };
>  
>  /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
> +module_param(force_enforce, bool, 0);
> +MODULE_PARM_DESC(force_enforce, "Always enforce module/firmware pinning");
>  module_param(enforce, int, 0);
>  MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
>  module_param_array_named(exclude, exclude_read_files, charp, NULL, 0);

-- 
~Randy


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

end of thread, other threads:[~2026-10-24  1:38 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-23 17:15 [RFC PATCH] loadpin: allow untoggleable enforcement on filesystems which don't appear to be read-only Amelia Crate
2026-10-23 17:30 ` sashiko-bot
2026-10-24  1:38 ` Randy Dunlap

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.