linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] LSM: ModPin LSM for module loading restrictions
@ 2013-09-20 20:35 Kees Cook
  2013-09-24  1:24 ` James Morris
  2013-10-17  8:02 ` James Morris
  0 siblings, 2 replies; 23+ messages in thread
From: Kees Cook @ 2013-09-20 20:35 UTC (permalink / raw)
  To: linux-kernel; +Cc: James Morris, Casey Schaufler, linux-security-module

This LSM enforces that modules must all come from the same filesystem,
with the expectation that such a filesystem is backed by a read-only
device such as dm-verity or CDROM. This allows systems that have a
verified or unchanging filesystem to enforce module loading restrictions
without needing to sign the modules individually.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 security/Kconfig         |    6 ++
 security/Makefile        |    2 +
 security/modpin/Kconfig  |    9 +++
 security/modpin/Makefile |    1 +
 security/modpin/modpin.c |  197 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 215 insertions(+)
 create mode 100644 security/modpin/Kconfig
 create mode 100644 security/modpin/Makefile
 create mode 100644 security/modpin/modpin.c

diff --git a/security/Kconfig b/security/Kconfig
index e9c6ac7..80172fd 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -121,6 +121,7 @@ source security/selinux/Kconfig
 source security/smack/Kconfig
 source security/tomoyo/Kconfig
 source security/apparmor/Kconfig
+source security/modpin/Kconfig
 source security/yama/Kconfig
 
 source security/integrity/Kconfig
@@ -131,6 +132,7 @@ choice
 	default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
 	default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
 	default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
+	default DEFAULT_SECURITY_MODPIN if SECURITY_MODPIN
 	default DEFAULT_SECURITY_YAMA if SECURITY_YAMA
 	default DEFAULT_SECURITY_DAC
 
@@ -150,6 +152,9 @@ choice
 	config DEFAULT_SECURITY_APPARMOR
 		bool "AppArmor" if SECURITY_APPARMOR=y
 
+	config DEFAULT_SECURITY_MODPIN
+		bool "ModPin" if SECURITY_MODPIN=y
+
 	config DEFAULT_SECURITY_YAMA
 		bool "Yama" if SECURITY_YAMA=y
 
@@ -164,6 +169,7 @@ config DEFAULT_SECURITY
 	default "smack" if DEFAULT_SECURITY_SMACK
 	default "tomoyo" if DEFAULT_SECURITY_TOMOYO
 	default "apparmor" if DEFAULT_SECURITY_APPARMOR
+	default "modpin" if DEFAULT_SECURITY_MODPIN
 	default "yama" if DEFAULT_SECURITY_YAMA
 	default "" if DEFAULT_SECURITY_DAC
 
diff --git a/security/Makefile b/security/Makefile
index c26c81e..73d0a05 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -7,6 +7,7 @@ subdir-$(CONFIG_SECURITY_SELINUX)	+= selinux
 subdir-$(CONFIG_SECURITY_SMACK)		+= smack
 subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
 subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
+subdir-$(CONFIG_SECURITY_MODPIN)	+= modpin
 subdir-$(CONFIG_SECURITY_YAMA)		+= yama
 
 # always enable default capabilities
@@ -22,6 +23,7 @@ obj-$(CONFIG_SECURITY_SMACK)		+= smack/built-in.o
 obj-$(CONFIG_AUDIT)			+= lsm_audit.o
 obj-$(CONFIG_SECURITY_TOMOYO)		+= tomoyo/built-in.o
 obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/built-in.o
+obj-$(CONFIG_SECURITY_MODPIN)		+= modpin/built-in.o
 obj-$(CONFIG_SECURITY_YAMA)		+= yama/built-in.o
 obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
 
diff --git a/security/modpin/Kconfig b/security/modpin/Kconfig
new file mode 100644
index 0000000..5be9dd5
--- /dev/null
+++ b/security/modpin/Kconfig
@@ -0,0 +1,9 @@
+config SECURITY_MODPIN
+	bool "Module filesystem origin pinning"
+	depends on SECURITY
+	help
+	  Module loading will be pinned to the first filesystem used for
+	  loading. Any modules that come from other filesystems will be
+	  rejected. This is best used on systems without an initrd that
+	  have a root filesystem backed by a read-only device such as
+	  dm-verity or a CDROM.
diff --git a/security/modpin/Makefile b/security/modpin/Makefile
new file mode 100644
index 0000000..9080b29
--- /dev/null
+++ b/security/modpin/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SECURITY_MODPIN) += modpin.o
diff --git a/security/modpin/modpin.c b/security/modpin/modpin.c
new file mode 100644
index 0000000..107b4d8
--- /dev/null
+++ b/security/modpin/modpin.c
@@ -0,0 +1,197 @@
+/*
+ * Module Pinning Security Module
+ *
+ * Copyright 2011-2013 Google Inc.
+ *
+ * Authors:
+ *      Kees Cook       <keescook@chromium.org>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "ModPin LSM: " fmt
+
+#include <linux/module.h>
+#include <linux/security.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/fs_struct.h>
+#include <linux/mount.h>
+#include <linux/path.h>
+#include <linux/root_dev.h>
+
+static void report_load_module(struct path *path, char *operation)
+{
+	char *alloced = NULL;
+	char *pathname; /* Pointer to either static string or "alloced". */
+
+	if (!path)
+		pathname = "<unknown>";
+	else {
+		/* We will allow 11 spaces for ' (deleted)' to be appended */
+		alloced = pathname = kmalloc(PATH_MAX+11, GFP_KERNEL);
+		if (!pathname)
+			pathname = "<no_memory>";
+		else {
+			pathname = d_path(path, pathname, PATH_MAX+11);
+			if (IS_ERR(pathname))
+				pathname = "<too_long>";
+		}
+	}
+
+	pr_notice("init_module %s module=%s pid=%d\n",
+		  operation, pathname, task_pid_nr(current));
+
+	kfree(alloced);
+}
+
+static int modpin_enforced = 1;
+static struct dentry *pinned_root;
+static DEFINE_SPINLOCK(pinned_root_spinlock);
+
+#ifdef CONFIG_SYSCTL
+static int zero;
+static int one = 1;
+
+static struct ctl_path modpin_sysctl_path[] = {
+	{ .procname = "kernel", },
+	{ .procname = "modpin", },
+	{ }
+};
+
+static struct ctl_table modpin_sysctl_table[] = {
+	{
+		.procname       = "enforced",
+		.data           = &modpin_enforced,
+		.maxlen         = sizeof(int),
+		.mode           = 0644,
+		.proc_handler   = proc_dointvec_minmax,
+		.extra1         = &zero,
+		.extra2         = &one,
+	},
+	{ }
+};
+
+/*
+ * Check if the root device is read-only (e.g. dm-verity is enabled).
+ * This must be called after early kernel init, since only then is the
+ * rootdev available.
+ */
+static bool rootdev_readonly(void)
+{
+	bool rc;
+	struct block_device *bdev;
+	const fmode_t mode = FMODE_WRITE;
+
+	bdev = blkdev_get_by_dev(ROOT_DEV, mode, NULL);
+	if (IS_ERR(bdev)) {
+		/* In this weird case, assume it is read-only. */
+		pr_info("dev(%u,%u): FMODE_WRITE disallowed?!\n",
+			MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
+		return true;
+	}
+
+	rc = bdev_read_only(bdev);
+	blkdev_put(bdev, mode);
+
+	pr_info("dev(%u,%u): %s\n", MAJOR(ROOT_DEV), MINOR(ROOT_DEV),
+		rc ? "read-only" : "writable");
+
+	return rc;
+}
+
+static void check_pinning_enforcement(void)
+{
+	/*
+	 * If module pinning is not being enforced, allow sysctl to change
+	 * modes for testing.
+	 */
+	if (!rootdev_readonly()) {
+		if (!register_sysctl_paths(modpin_sysctl_path,
+					   modpin_sysctl_table))
+			pr_notice("sysctl registration failed!\n");
+		else
+			pr_info("module pinning can be disabled.\n");
+	} else
+		pr_info("module pinning engaged.\n");
+}
+#else
+static void check_pinning_enforcement(void) { }
+#endif
+
+
+static int modpin_load_module(struct file *file)
+{
+	struct dentry *module_root;
+
+	if (!file) {
+		if (!modpin_enforced) {
+			report_load_module(NULL, "old-api-pinning-ignored");
+			return 0;
+		}
+
+		report_load_module(NULL, "old-api-denied");
+		return -EPERM;
+	}
+
+	module_root = file->f_path.mnt->mnt_root;
+
+	/* First loaded module defines the root for all others. */
+	spin_lock(&pinned_root_spinlock);
+	if (!pinned_root) {
+		pinned_root = dget(module_root);
+		/*
+		 * Unlock now since it's only pinned_root we care about.
+		 * In the worst case, we will (correctly) report pinning
+		 * failures before we have announced that pinning is
+		 * enabled. This would be purely cosmetic.
+		 */
+		spin_unlock(&pinned_root_spinlock);
+		check_pinning_enforcement();
+		report_load_module(&file->f_path, "pinned");
+		return 0;
+	}
+	spin_unlock(&pinned_root_spinlock);
+
+	if (module_root != pinned_root) {
+		if (unlikely(!modpin_enforced)) {
+			report_load_module(&file->f_path, "pinning-ignored");
+			return 0;
+		}
+
+		report_load_module(&file->f_path, "denied");
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+static struct security_operations modpin_ops = {
+	.name	= "modpin",
+	.kernel_module_from_file = modpin_load_module,
+};
+
+static int __init modpin_init(void)
+{
+	int error;
+
+	error = register_security(&modpin_ops);
+
+	if (error)
+		panic("Could not register ModPin security module");
+
+	pr_info("ready to pin.\n");
+
+	return error;
+}
+security_initcall(modpin_init);
+
+module_param(modpin_enforced, int, S_IRUSR);
+MODULE_PARM_DESC(modpin_enforced, "Module pinning enforced (default: true)");
-- 
1.7.9.5


-- 
Kees Cook
Chrome OS Security

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-09-20 20:35 [PATCH] LSM: ModPin LSM for module loading restrictions Kees Cook
@ 2013-09-24  1:24 ` James Morris
  2013-09-24  1:28   ` James Morris
  2013-10-17  8:02 ` James Morris
  1 sibling, 1 reply; 23+ messages in thread
From: James Morris @ 2013-09-24  1:24 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-kernel, James Morris, Casey Schaufler, linux-security-module

On Fri, 20 Sep 2013, Kees Cook wrote:

> This LSM enforces that modules must all come from the same filesystem,
> with the expectation that such a filesystem is backed by a read-only
> device such as dm-verity or CDROM. This allows systems that have a
> verified or unchanging filesystem to enforce module loading restrictions
> without needing to sign the modules individually.
> 
> Signed-off-by: Kees Cook <keescook@chromium.org>

Are you using this for ChromeOS?


> ---
>  security/Kconfig         |    6 ++
>  security/Makefile        |    2 +
>  security/modpin/Kconfig  |    9 +++
>  security/modpin/Makefile |    1 +
>  security/modpin/modpin.c |  197 ++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 215 insertions(+)
>  create mode 100644 security/modpin/Kconfig
>  create mode 100644 security/modpin/Makefile
>  create mode 100644 security/modpin/modpin.c
> 
> diff --git a/security/Kconfig b/security/Kconfig
> index e9c6ac7..80172fd 100644
> --- a/security/Kconfig
> +++ b/security/Kconfig
> @@ -121,6 +121,7 @@ source security/selinux/Kconfig
>  source security/smack/Kconfig
>  source security/tomoyo/Kconfig
>  source security/apparmor/Kconfig
> +source security/modpin/Kconfig
>  source security/yama/Kconfig
>  
>  source security/integrity/Kconfig
> @@ -131,6 +132,7 @@ choice
>  	default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
>  	default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
>  	default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
> +	default DEFAULT_SECURITY_MODPIN if SECURITY_MODPIN
>  	default DEFAULT_SECURITY_YAMA if SECURITY_YAMA
>  	default DEFAULT_SECURITY_DAC
>  
> @@ -150,6 +152,9 @@ choice
>  	config DEFAULT_SECURITY_APPARMOR
>  		bool "AppArmor" if SECURITY_APPARMOR=y
>  
> +	config DEFAULT_SECURITY_MODPIN
> +		bool "ModPin" if SECURITY_MODPIN=y
> +
>  	config DEFAULT_SECURITY_YAMA
>  		bool "Yama" if SECURITY_YAMA=y
>  
> @@ -164,6 +169,7 @@ config DEFAULT_SECURITY
>  	default "smack" if DEFAULT_SECURITY_SMACK
>  	default "tomoyo" if DEFAULT_SECURITY_TOMOYO
>  	default "apparmor" if DEFAULT_SECURITY_APPARMOR
> +	default "modpin" if DEFAULT_SECURITY_MODPIN
>  	default "yama" if DEFAULT_SECURITY_YAMA
>  	default "" if DEFAULT_SECURITY_DAC
>  
> diff --git a/security/Makefile b/security/Makefile
> index c26c81e..73d0a05 100644
> --- a/security/Makefile
> +++ b/security/Makefile
> @@ -7,6 +7,7 @@ subdir-$(CONFIG_SECURITY_SELINUX)	+= selinux
>  subdir-$(CONFIG_SECURITY_SMACK)		+= smack
>  subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
>  subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
> +subdir-$(CONFIG_SECURITY_MODPIN)	+= modpin
>  subdir-$(CONFIG_SECURITY_YAMA)		+= yama
>  
>  # always enable default capabilities
> @@ -22,6 +23,7 @@ obj-$(CONFIG_SECURITY_SMACK)		+= smack/built-in.o
>  obj-$(CONFIG_AUDIT)			+= lsm_audit.o
>  obj-$(CONFIG_SECURITY_TOMOYO)		+= tomoyo/built-in.o
>  obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/built-in.o
> +obj-$(CONFIG_SECURITY_MODPIN)		+= modpin/built-in.o
>  obj-$(CONFIG_SECURITY_YAMA)		+= yama/built-in.o
>  obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
>  
> diff --git a/security/modpin/Kconfig b/security/modpin/Kconfig
> new file mode 100644
> index 0000000..5be9dd5
> --- /dev/null
> +++ b/security/modpin/Kconfig
> @@ -0,0 +1,9 @@
> +config SECURITY_MODPIN
> +	bool "Module filesystem origin pinning"
> +	depends on SECURITY
> +	help
> +	  Module loading will be pinned to the first filesystem used for
> +	  loading. Any modules that come from other filesystems will be
> +	  rejected. This is best used on systems without an initrd that
> +	  have a root filesystem backed by a read-only device such as
> +	  dm-verity or a CDROM.
> diff --git a/security/modpin/Makefile b/security/modpin/Makefile
> new file mode 100644
> index 0000000..9080b29
> --- /dev/null
> +++ b/security/modpin/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_SECURITY_MODPIN) += modpin.o
> diff --git a/security/modpin/modpin.c b/security/modpin/modpin.c
> new file mode 100644
> index 0000000..107b4d8
> --- /dev/null
> +++ b/security/modpin/modpin.c
> @@ -0,0 +1,197 @@
> +/*
> + * Module Pinning Security Module
> + *
> + * Copyright 2011-2013 Google Inc.
> + *
> + * Authors:
> + *      Kees Cook       <keescook@chromium.org>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#define pr_fmt(fmt) "ModPin LSM: " fmt
> +
> +#include <linux/module.h>
> +#include <linux/security.h>
> +#include <linux/sched.h>
> +#include <linux/fs.h>
> +#include <linux/fs_struct.h>
> +#include <linux/mount.h>
> +#include <linux/path.h>
> +#include <linux/root_dev.h>
> +
> +static void report_load_module(struct path *path, char *operation)
> +{
> +	char *alloced = NULL;
> +	char *pathname; /* Pointer to either static string or "alloced". */
> +
> +	if (!path)
> +		pathname = "<unknown>";
> +	else {
> +		/* We will allow 11 spaces for ' (deleted)' to be appended */
> +		alloced = pathname = kmalloc(PATH_MAX+11, GFP_KERNEL);
> +		if (!pathname)
> +			pathname = "<no_memory>";
> +		else {
> +			pathname = d_path(path, pathname, PATH_MAX+11);
> +			if (IS_ERR(pathname))
> +				pathname = "<too_long>";
> +		}
> +	}
> +
> +	pr_notice("init_module %s module=%s pid=%d\n",
> +		  operation, pathname, task_pid_nr(current));
> +
> +	kfree(alloced);
> +}
> +
> +static int modpin_enforced = 1;
> +static struct dentry *pinned_root;
> +static DEFINE_SPINLOCK(pinned_root_spinlock);
> +
> +#ifdef CONFIG_SYSCTL
> +static int zero;
> +static int one = 1;
> +
> +static struct ctl_path modpin_sysctl_path[] = {
> +	{ .procname = "kernel", },
> +	{ .procname = "modpin", },
> +	{ }
> +};
> +
> +static struct ctl_table modpin_sysctl_table[] = {
> +	{
> +		.procname       = "enforced",
> +		.data           = &modpin_enforced,
> +		.maxlen         = sizeof(int),
> +		.mode           = 0644,
> +		.proc_handler   = proc_dointvec_minmax,
> +		.extra1         = &zero,
> +		.extra2         = &one,
> +	},
> +	{ }
> +};
> +
> +/*
> + * Check if the root device is read-only (e.g. dm-verity is enabled).
> + * This must be called after early kernel init, since only then is the
> + * rootdev available.
> + */
> +static bool rootdev_readonly(void)
> +{
> +	bool rc;
> +	struct block_device *bdev;
> +	const fmode_t mode = FMODE_WRITE;
> +
> +	bdev = blkdev_get_by_dev(ROOT_DEV, mode, NULL);
> +	if (IS_ERR(bdev)) {
> +		/* In this weird case, assume it is read-only. */
> +		pr_info("dev(%u,%u): FMODE_WRITE disallowed?!\n",
> +			MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
> +		return true;
> +	}
> +
> +	rc = bdev_read_only(bdev);
> +	blkdev_put(bdev, mode);
> +
> +	pr_info("dev(%u,%u): %s\n", MAJOR(ROOT_DEV), MINOR(ROOT_DEV),
> +		rc ? "read-only" : "writable");
> +
> +	return rc;
> +}
> +
> +static void check_pinning_enforcement(void)
> +{
> +	/*
> +	 * If module pinning is not being enforced, allow sysctl to change
> +	 * modes for testing.
> +	 */
> +	if (!rootdev_readonly()) {
> +		if (!register_sysctl_paths(modpin_sysctl_path,
> +					   modpin_sysctl_table))
> +			pr_notice("sysctl registration failed!\n");
> +		else
> +			pr_info("module pinning can be disabled.\n");
> +	} else
> +		pr_info("module pinning engaged.\n");
> +}
> +#else
> +static void check_pinning_enforcement(void) { }
> +#endif
> +
> +
> +static int modpin_load_module(struct file *file)
> +{
> +	struct dentry *module_root;
> +
> +	if (!file) {
> +		if (!modpin_enforced) {
> +			report_load_module(NULL, "old-api-pinning-ignored");
> +			return 0;
> +		}
> +
> +		report_load_module(NULL, "old-api-denied");
> +		return -EPERM;
> +	}
> +
> +	module_root = file->f_path.mnt->mnt_root;
> +
> +	/* First loaded module defines the root for all others. */
> +	spin_lock(&pinned_root_spinlock);
> +	if (!pinned_root) {
> +		pinned_root = dget(module_root);
> +		/*
> +		 * Unlock now since it's only pinned_root we care about.
> +		 * In the worst case, we will (correctly) report pinning
> +		 * failures before we have announced that pinning is
> +		 * enabled. This would be purely cosmetic.
> +		 */
> +		spin_unlock(&pinned_root_spinlock);
> +		check_pinning_enforcement();
> +		report_load_module(&file->f_path, "pinned");
> +		return 0;
> +	}
> +	spin_unlock(&pinned_root_spinlock);
> +
> +	if (module_root != pinned_root) {
> +		if (unlikely(!modpin_enforced)) {
> +			report_load_module(&file->f_path, "pinning-ignored");
> +			return 0;
> +		}
> +
> +		report_load_module(&file->f_path, "denied");
> +		return -EPERM;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct security_operations modpin_ops = {
> +	.name	= "modpin",
> +	.kernel_module_from_file = modpin_load_module,
> +};
> +
> +static int __init modpin_init(void)
> +{
> +	int error;
> +
> +	error = register_security(&modpin_ops);
> +
> +	if (error)
> +		panic("Could not register ModPin security module");
> +
> +	pr_info("ready to pin.\n");
> +
> +	return error;
> +}
> +security_initcall(modpin_init);
> +
> +module_param(modpin_enforced, int, S_IRUSR);
> +MODULE_PARM_DESC(modpin_enforced, "Module pinning enforced (default: true)");
> -- 
> 1.7.9.5
> 
> 
> -- 
> Kees Cook
> Chrome OS Security
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 

-- 
James Morris
<jmorris@namei.org>

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-09-24  1:24 ` James Morris
@ 2013-09-24  1:28   ` James Morris
  2013-09-24  1:45     ` Kees Cook
  0 siblings, 1 reply; 23+ messages in thread
From: James Morris @ 2013-09-24  1:28 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-kernel, James Morris, Casey Schaufler, linux-security-module

On Tue, 24 Sep 2013, James Morris wrote:

> On Fri, 20 Sep 2013, Kees Cook wrote:
> 
> > This LSM enforces that modules must all come from the same filesystem,
> > with the expectation that such a filesystem is backed by a read-only
> > device such as dm-verity or CDROM. This allows systems that have a
> > verified or unchanging filesystem to enforce module loading restrictions
> > without needing to sign the modules individually.
> > 
> > Signed-off-by: Kees Cook <keescook@chromium.org>
> 
> Are you using this for ChromeOS?

Also, you should CC Rusty on this.


> 
> 
> > ---
> >  security/Kconfig         |    6 ++
> >  security/Makefile        |    2 +
> >  security/modpin/Kconfig  |    9 +++
> >  security/modpin/Makefile |    1 +
> >  security/modpin/modpin.c |  197 ++++++++++++++++++++++++++++++++++++++++++++++
> >  5 files changed, 215 insertions(+)
> >  create mode 100644 security/modpin/Kconfig
> >  create mode 100644 security/modpin/Makefile
> >  create mode 100644 security/modpin/modpin.c
> > 
> > diff --git a/security/Kconfig b/security/Kconfig
> > index e9c6ac7..80172fd 100644
> > --- a/security/Kconfig
> > +++ b/security/Kconfig
> > @@ -121,6 +121,7 @@ source security/selinux/Kconfig
> >  source security/smack/Kconfig
> >  source security/tomoyo/Kconfig
> >  source security/apparmor/Kconfig
> > +source security/modpin/Kconfig
> >  source security/yama/Kconfig
> >  
> >  source security/integrity/Kconfig
> > @@ -131,6 +132,7 @@ choice
> >  	default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
> >  	default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
> >  	default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
> > +	default DEFAULT_SECURITY_MODPIN if SECURITY_MODPIN
> >  	default DEFAULT_SECURITY_YAMA if SECURITY_YAMA
> >  	default DEFAULT_SECURITY_DAC
> >  
> > @@ -150,6 +152,9 @@ choice
> >  	config DEFAULT_SECURITY_APPARMOR
> >  		bool "AppArmor" if SECURITY_APPARMOR=y
> >  
> > +	config DEFAULT_SECURITY_MODPIN
> > +		bool "ModPin" if SECURITY_MODPIN=y
> > +
> >  	config DEFAULT_SECURITY_YAMA
> >  		bool "Yama" if SECURITY_YAMA=y
> >  
> > @@ -164,6 +169,7 @@ config DEFAULT_SECURITY
> >  	default "smack" if DEFAULT_SECURITY_SMACK
> >  	default "tomoyo" if DEFAULT_SECURITY_TOMOYO
> >  	default "apparmor" if DEFAULT_SECURITY_APPARMOR
> > +	default "modpin" if DEFAULT_SECURITY_MODPIN
> >  	default "yama" if DEFAULT_SECURITY_YAMA
> >  	default "" if DEFAULT_SECURITY_DAC
> >  
> > diff --git a/security/Makefile b/security/Makefile
> > index c26c81e..73d0a05 100644
> > --- a/security/Makefile
> > +++ b/security/Makefile
> > @@ -7,6 +7,7 @@ subdir-$(CONFIG_SECURITY_SELINUX)	+= selinux
> >  subdir-$(CONFIG_SECURITY_SMACK)		+= smack
> >  subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
> >  subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
> > +subdir-$(CONFIG_SECURITY_MODPIN)	+= modpin
> >  subdir-$(CONFIG_SECURITY_YAMA)		+= yama
> >  
> >  # always enable default capabilities
> > @@ -22,6 +23,7 @@ obj-$(CONFIG_SECURITY_SMACK)		+= smack/built-in.o
> >  obj-$(CONFIG_AUDIT)			+= lsm_audit.o
> >  obj-$(CONFIG_SECURITY_TOMOYO)		+= tomoyo/built-in.o
> >  obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/built-in.o
> > +obj-$(CONFIG_SECURITY_MODPIN)		+= modpin/built-in.o
> >  obj-$(CONFIG_SECURITY_YAMA)		+= yama/built-in.o
> >  obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
> >  
> > diff --git a/security/modpin/Kconfig b/security/modpin/Kconfig
> > new file mode 100644
> > index 0000000..5be9dd5
> > --- /dev/null
> > +++ b/security/modpin/Kconfig
> > @@ -0,0 +1,9 @@
> > +config SECURITY_MODPIN
> > +	bool "Module filesystem origin pinning"
> > +	depends on SECURITY
> > +	help
> > +	  Module loading will be pinned to the first filesystem used for
> > +	  loading. Any modules that come from other filesystems will be
> > +	  rejected. This is best used on systems without an initrd that
> > +	  have a root filesystem backed by a read-only device such as
> > +	  dm-verity or a CDROM.
> > diff --git a/security/modpin/Makefile b/security/modpin/Makefile
> > new file mode 100644
> > index 0000000..9080b29
> > --- /dev/null
> > +++ b/security/modpin/Makefile
> > @@ -0,0 +1 @@
> > +obj-$(CONFIG_SECURITY_MODPIN) += modpin.o
> > diff --git a/security/modpin/modpin.c b/security/modpin/modpin.c
> > new file mode 100644
> > index 0000000..107b4d8
> > --- /dev/null
> > +++ b/security/modpin/modpin.c
> > @@ -0,0 +1,197 @@
> > +/*
> > + * Module Pinning Security Module
> > + *
> > + * Copyright 2011-2013 Google Inc.
> > + *
> > + * Authors:
> > + *      Kees Cook       <keescook@chromium.org>
> > + *
> > + * This software is licensed under the terms of the GNU General Public
> > + * License version 2, as published by the Free Software Foundation, and
> > + * may be copied, distributed, and modified under those terms.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#define pr_fmt(fmt) "ModPin LSM: " fmt
> > +
> > +#include <linux/module.h>
> > +#include <linux/security.h>
> > +#include <linux/sched.h>
> > +#include <linux/fs.h>
> > +#include <linux/fs_struct.h>
> > +#include <linux/mount.h>
> > +#include <linux/path.h>
> > +#include <linux/root_dev.h>
> > +
> > +static void report_load_module(struct path *path, char *operation)
> > +{
> > +	char *alloced = NULL;
> > +	char *pathname; /* Pointer to either static string or "alloced". */
> > +
> > +	if (!path)
> > +		pathname = "<unknown>";
> > +	else {
> > +		/* We will allow 11 spaces for ' (deleted)' to be appended */
> > +		alloced = pathname = kmalloc(PATH_MAX+11, GFP_KERNEL);
> > +		if (!pathname)
> > +			pathname = "<no_memory>";
> > +		else {
> > +			pathname = d_path(path, pathname, PATH_MAX+11);
> > +			if (IS_ERR(pathname))
> > +				pathname = "<too_long>";
> > +		}
> > +	}
> > +
> > +	pr_notice("init_module %s module=%s pid=%d\n",
> > +		  operation, pathname, task_pid_nr(current));
> > +
> > +	kfree(alloced);
> > +}
> > +
> > +static int modpin_enforced = 1;
> > +static struct dentry *pinned_root;
> > +static DEFINE_SPINLOCK(pinned_root_spinlock);
> > +
> > +#ifdef CONFIG_SYSCTL
> > +static int zero;
> > +static int one = 1;
> > +
> > +static struct ctl_path modpin_sysctl_path[] = {
> > +	{ .procname = "kernel", },
> > +	{ .procname = "modpin", },
> > +	{ }
> > +};
> > +
> > +static struct ctl_table modpin_sysctl_table[] = {
> > +	{
> > +		.procname       = "enforced",
> > +		.data           = &modpin_enforced,
> > +		.maxlen         = sizeof(int),
> > +		.mode           = 0644,
> > +		.proc_handler   = proc_dointvec_minmax,
> > +		.extra1         = &zero,
> > +		.extra2         = &one,
> > +	},
> > +	{ }
> > +};
> > +
> > +/*
> > + * Check if the root device is read-only (e.g. dm-verity is enabled).
> > + * This must be called after early kernel init, since only then is the
> > + * rootdev available.
> > + */
> > +static bool rootdev_readonly(void)
> > +{
> > +	bool rc;
> > +	struct block_device *bdev;
> > +	const fmode_t mode = FMODE_WRITE;
> > +
> > +	bdev = blkdev_get_by_dev(ROOT_DEV, mode, NULL);
> > +	if (IS_ERR(bdev)) {
> > +		/* In this weird case, assume it is read-only. */
> > +		pr_info("dev(%u,%u): FMODE_WRITE disallowed?!\n",
> > +			MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
> > +		return true;
> > +	}
> > +
> > +	rc = bdev_read_only(bdev);
> > +	blkdev_put(bdev, mode);
> > +
> > +	pr_info("dev(%u,%u): %s\n", MAJOR(ROOT_DEV), MINOR(ROOT_DEV),
> > +		rc ? "read-only" : "writable");
> > +
> > +	return rc;
> > +}
> > +
> > +static void check_pinning_enforcement(void)
> > +{
> > +	/*
> > +	 * If module pinning is not being enforced, allow sysctl to change
> > +	 * modes for testing.
> > +	 */
> > +	if (!rootdev_readonly()) {
> > +		if (!register_sysctl_paths(modpin_sysctl_path,
> > +					   modpin_sysctl_table))
> > +			pr_notice("sysctl registration failed!\n");
> > +		else
> > +			pr_info("module pinning can be disabled.\n");
> > +	} else
> > +		pr_info("module pinning engaged.\n");
> > +}
> > +#else
> > +static void check_pinning_enforcement(void) { }
> > +#endif
> > +
> > +
> > +static int modpin_load_module(struct file *file)
> > +{
> > +	struct dentry *module_root;
> > +
> > +	if (!file) {
> > +		if (!modpin_enforced) {
> > +			report_load_module(NULL, "old-api-pinning-ignored");
> > +			return 0;
> > +		}
> > +
> > +		report_load_module(NULL, "old-api-denied");
> > +		return -EPERM;
> > +	}
> > +
> > +	module_root = file->f_path.mnt->mnt_root;
> > +
> > +	/* First loaded module defines the root for all others. */
> > +	spin_lock(&pinned_root_spinlock);
> > +	if (!pinned_root) {
> > +		pinned_root = dget(module_root);
> > +		/*
> > +		 * Unlock now since it's only pinned_root we care about.
> > +		 * In the worst case, we will (correctly) report pinning
> > +		 * failures before we have announced that pinning is
> > +		 * enabled. This would be purely cosmetic.
> > +		 */
> > +		spin_unlock(&pinned_root_spinlock);
> > +		check_pinning_enforcement();
> > +		report_load_module(&file->f_path, "pinned");
> > +		return 0;
> > +	}
> > +	spin_unlock(&pinned_root_spinlock);
> > +
> > +	if (module_root != pinned_root) {
> > +		if (unlikely(!modpin_enforced)) {
> > +			report_load_module(&file->f_path, "pinning-ignored");
> > +			return 0;
> > +		}
> > +
> > +		report_load_module(&file->f_path, "denied");
> > +		return -EPERM;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static struct security_operations modpin_ops = {
> > +	.name	= "modpin",
> > +	.kernel_module_from_file = modpin_load_module,
> > +};
> > +
> > +static int __init modpin_init(void)
> > +{
> > +	int error;
> > +
> > +	error = register_security(&modpin_ops);
> > +
> > +	if (error)
> > +		panic("Could not register ModPin security module");
> > +
> > +	pr_info("ready to pin.\n");
> > +
> > +	return error;
> > +}
> > +security_initcall(modpin_init);
> > +
> > +module_param(modpin_enforced, int, S_IRUSR);
> > +MODULE_PARM_DESC(modpin_enforced, "Module pinning enforced (default: true)");
> > -- 
> > 1.7.9.5
> > 
> > 
> > -- 
> > Kees Cook
> > Chrome OS Security
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> > 
> 
> -- 
> James Morris
> <jmorris@namei.org>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

-- 
James Morris
<jmorris@namei.org>

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-09-24  1:28   ` James Morris
@ 2013-09-24  1:45     ` Kees Cook
  2013-10-03 20:55       ` Kees Cook
  2013-10-16 15:18       ` Kees Cook
  0 siblings, 2 replies; 23+ messages in thread
From: Kees Cook @ 2013-09-24  1:45 UTC (permalink / raw)
  To: James Morris
  Cc: LKML, James Morris, Casey Schaufler, linux-security-module,
	Rusty Russell

[+rusty]

On Mon, Sep 23, 2013 at 6:28 PM, James Morris <jmorris@namei.org> wrote:
> On Tue, 24 Sep 2013, James Morris wrote:
>
>> On Fri, 20 Sep 2013, Kees Cook wrote:
>>
>> > This LSM enforces that modules must all come from the same filesystem,
>> > with the expectation that such a filesystem is backed by a read-only
>> > device such as dm-verity or CDROM. This allows systems that have a
>> > verified or unchanging filesystem to enforce module loading restrictions
>> > without needing to sign the modules individually.
>> >
>> > Signed-off-by: Kees Cook <keescook@chromium.org>
>>
>> Are you using this for ChromeOS?

Yes. Chrome OS uses a read-only root filesystem that is backed by
dm-verity. This lets us pin all module loading to that filesystem
without needing per-module signatures.

> Also, you should CC Rusty on this.

Done! :)

-Kees

>
>
>>
>>
>> > ---
>> >  security/Kconfig         |    6 ++
>> >  security/Makefile        |    2 +
>> >  security/modpin/Kconfig  |    9 +++
>> >  security/modpin/Makefile |    1 +
>> >  security/modpin/modpin.c |  197 ++++++++++++++++++++++++++++++++++++++++++++++
>> >  5 files changed, 215 insertions(+)
>> >  create mode 100644 security/modpin/Kconfig
>> >  create mode 100644 security/modpin/Makefile
>> >  create mode 100644 security/modpin/modpin.c
>> >
>> > diff --git a/security/Kconfig b/security/Kconfig
>> > index e9c6ac7..80172fd 100644
>> > --- a/security/Kconfig
>> > +++ b/security/Kconfig
>> > @@ -121,6 +121,7 @@ source security/selinux/Kconfig
>> >  source security/smack/Kconfig
>> >  source security/tomoyo/Kconfig
>> >  source security/apparmor/Kconfig
>> > +source security/modpin/Kconfig
>> >  source security/yama/Kconfig
>> >
>> >  source security/integrity/Kconfig
>> > @@ -131,6 +132,7 @@ choice
>> >     default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
>> >     default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
>> >     default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
>> > +   default DEFAULT_SECURITY_MODPIN if SECURITY_MODPIN
>> >     default DEFAULT_SECURITY_YAMA if SECURITY_YAMA
>> >     default DEFAULT_SECURITY_DAC
>> >
>> > @@ -150,6 +152,9 @@ choice
>> >     config DEFAULT_SECURITY_APPARMOR
>> >             bool "AppArmor" if SECURITY_APPARMOR=y
>> >
>> > +   config DEFAULT_SECURITY_MODPIN
>> > +           bool "ModPin" if SECURITY_MODPIN=y
>> > +
>> >     config DEFAULT_SECURITY_YAMA
>> >             bool "Yama" if SECURITY_YAMA=y
>> >
>> > @@ -164,6 +169,7 @@ config DEFAULT_SECURITY
>> >     default "smack" if DEFAULT_SECURITY_SMACK
>> >     default "tomoyo" if DEFAULT_SECURITY_TOMOYO
>> >     default "apparmor" if DEFAULT_SECURITY_APPARMOR
>> > +   default "modpin" if DEFAULT_SECURITY_MODPIN
>> >     default "yama" if DEFAULT_SECURITY_YAMA
>> >     default "" if DEFAULT_SECURITY_DAC
>> >
>> > diff --git a/security/Makefile b/security/Makefile
>> > index c26c81e..73d0a05 100644
>> > --- a/security/Makefile
>> > +++ b/security/Makefile
>> > @@ -7,6 +7,7 @@ subdir-$(CONFIG_SECURITY_SELINUX)   += selinux
>> >  subdir-$(CONFIG_SECURITY_SMACK)            += smack
>> >  subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
>> >  subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor
>> > +subdir-$(CONFIG_SECURITY_MODPIN)   += modpin
>> >  subdir-$(CONFIG_SECURITY_YAMA)             += yama
>> >
>> >  # always enable default capabilities
>> > @@ -22,6 +23,7 @@ obj-$(CONFIG_SECURITY_SMACK)              += smack/built-in.o
>> >  obj-$(CONFIG_AUDIT)                        += lsm_audit.o
>> >  obj-$(CONFIG_SECURITY_TOMOYO)              += tomoyo/built-in.o
>> >  obj-$(CONFIG_SECURITY_APPARMOR)            += apparmor/built-in.o
>> > +obj-$(CONFIG_SECURITY_MODPIN)              += modpin/built-in.o
>> >  obj-$(CONFIG_SECURITY_YAMA)                += yama/built-in.o
>> >  obj-$(CONFIG_CGROUP_DEVICE)                += device_cgroup.o
>> >
>> > diff --git a/security/modpin/Kconfig b/security/modpin/Kconfig
>> > new file mode 100644
>> > index 0000000..5be9dd5
>> > --- /dev/null
>> > +++ b/security/modpin/Kconfig
>> > @@ -0,0 +1,9 @@
>> > +config SECURITY_MODPIN
>> > +   bool "Module filesystem origin pinning"
>> > +   depends on SECURITY
>> > +   help
>> > +     Module loading will be pinned to the first filesystem used for
>> > +     loading. Any modules that come from other filesystems will be
>> > +     rejected. This is best used on systems without an initrd that
>> > +     have a root filesystem backed by a read-only device such as
>> > +     dm-verity or a CDROM.
>> > diff --git a/security/modpin/Makefile b/security/modpin/Makefile
>> > new file mode 100644
>> > index 0000000..9080b29
>> > --- /dev/null
>> > +++ b/security/modpin/Makefile
>> > @@ -0,0 +1 @@
>> > +obj-$(CONFIG_SECURITY_MODPIN) += modpin.o
>> > diff --git a/security/modpin/modpin.c b/security/modpin/modpin.c
>> > new file mode 100644
>> > index 0000000..107b4d8
>> > --- /dev/null
>> > +++ b/security/modpin/modpin.c
>> > @@ -0,0 +1,197 @@
>> > +/*
>> > + * Module Pinning Security Module
>> > + *
>> > + * Copyright 2011-2013 Google Inc.
>> > + *
>> > + * Authors:
>> > + *      Kees Cook       <keescook@chromium.org>
>> > + *
>> > + * This software is licensed under the terms of the GNU General Public
>> > + * License version 2, as published by the Free Software Foundation, and
>> > + * may be copied, distributed, and modified under those terms.
>> > + *
>> > + * This program is distributed in the hope that it will be useful,
>> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> > + * GNU General Public License for more details.
>> > + */
>> > +
>> > +#define pr_fmt(fmt) "ModPin LSM: " fmt
>> > +
>> > +#include <linux/module.h>
>> > +#include <linux/security.h>
>> > +#include <linux/sched.h>
>> > +#include <linux/fs.h>
>> > +#include <linux/fs_struct.h>
>> > +#include <linux/mount.h>
>> > +#include <linux/path.h>
>> > +#include <linux/root_dev.h>
>> > +
>> > +static void report_load_module(struct path *path, char *operation)
>> > +{
>> > +   char *alloced = NULL;
>> > +   char *pathname; /* Pointer to either static string or "alloced". */
>> > +
>> > +   if (!path)
>> > +           pathname = "<unknown>";
>> > +   else {
>> > +           /* We will allow 11 spaces for ' (deleted)' to be appended */
>> > +           alloced = pathname = kmalloc(PATH_MAX+11, GFP_KERNEL);
>> > +           if (!pathname)
>> > +                   pathname = "<no_memory>";
>> > +           else {
>> > +                   pathname = d_path(path, pathname, PATH_MAX+11);
>> > +                   if (IS_ERR(pathname))
>> > +                           pathname = "<too_long>";
>> > +           }
>> > +   }
>> > +
>> > +   pr_notice("init_module %s module=%s pid=%d\n",
>> > +             operation, pathname, task_pid_nr(current));
>> > +
>> > +   kfree(alloced);
>> > +}
>> > +
>> > +static int modpin_enforced = 1;
>> > +static struct dentry *pinned_root;
>> > +static DEFINE_SPINLOCK(pinned_root_spinlock);
>> > +
>> > +#ifdef CONFIG_SYSCTL
>> > +static int zero;
>> > +static int one = 1;
>> > +
>> > +static struct ctl_path modpin_sysctl_path[] = {
>> > +   { .procname = "kernel", },
>> > +   { .procname = "modpin", },
>> > +   { }
>> > +};
>> > +
>> > +static struct ctl_table modpin_sysctl_table[] = {
>> > +   {
>> > +           .procname       = "enforced",
>> > +           .data           = &modpin_enforced,
>> > +           .maxlen         = sizeof(int),
>> > +           .mode           = 0644,
>> > +           .proc_handler   = proc_dointvec_minmax,
>> > +           .extra1         = &zero,
>> > +           .extra2         = &one,
>> > +   },
>> > +   { }
>> > +};
>> > +
>> > +/*
>> > + * Check if the root device is read-only (e.g. dm-verity is enabled).
>> > + * This must be called after early kernel init, since only then is the
>> > + * rootdev available.
>> > + */
>> > +static bool rootdev_readonly(void)
>> > +{
>> > +   bool rc;
>> > +   struct block_device *bdev;
>> > +   const fmode_t mode = FMODE_WRITE;
>> > +
>> > +   bdev = blkdev_get_by_dev(ROOT_DEV, mode, NULL);
>> > +   if (IS_ERR(bdev)) {
>> > +           /* In this weird case, assume it is read-only. */
>> > +           pr_info("dev(%u,%u): FMODE_WRITE disallowed?!\n",
>> > +                   MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
>> > +           return true;
>> > +   }
>> > +
>> > +   rc = bdev_read_only(bdev);
>> > +   blkdev_put(bdev, mode);
>> > +
>> > +   pr_info("dev(%u,%u): %s\n", MAJOR(ROOT_DEV), MINOR(ROOT_DEV),
>> > +           rc ? "read-only" : "writable");
>> > +
>> > +   return rc;
>> > +}
>> > +
>> > +static void check_pinning_enforcement(void)
>> > +{
>> > +   /*
>> > +    * If module pinning is not being enforced, allow sysctl to change
>> > +    * modes for testing.
>> > +    */
>> > +   if (!rootdev_readonly()) {
>> > +           if (!register_sysctl_paths(modpin_sysctl_path,
>> > +                                      modpin_sysctl_table))
>> > +                   pr_notice("sysctl registration failed!\n");
>> > +           else
>> > +                   pr_info("module pinning can be disabled.\n");
>> > +   } else
>> > +           pr_info("module pinning engaged.\n");
>> > +}
>> > +#else
>> > +static void check_pinning_enforcement(void) { }
>> > +#endif
>> > +
>> > +
>> > +static int modpin_load_module(struct file *file)
>> > +{
>> > +   struct dentry *module_root;
>> > +
>> > +   if (!file) {
>> > +           if (!modpin_enforced) {
>> > +                   report_load_module(NULL, "old-api-pinning-ignored");
>> > +                   return 0;
>> > +           }
>> > +
>> > +           report_load_module(NULL, "old-api-denied");
>> > +           return -EPERM;
>> > +   }
>> > +
>> > +   module_root = file->f_path.mnt->mnt_root;
>> > +
>> > +   /* First loaded module defines the root for all others. */
>> > +   spin_lock(&pinned_root_spinlock);
>> > +   if (!pinned_root) {
>> > +           pinned_root = dget(module_root);
>> > +           /*
>> > +            * Unlock now since it's only pinned_root we care about.
>> > +            * In the worst case, we will (correctly) report pinning
>> > +            * failures before we have announced that pinning is
>> > +            * enabled. This would be purely cosmetic.
>> > +            */
>> > +           spin_unlock(&pinned_root_spinlock);
>> > +           check_pinning_enforcement();
>> > +           report_load_module(&file->f_path, "pinned");
>> > +           return 0;
>> > +   }
>> > +   spin_unlock(&pinned_root_spinlock);
>> > +
>> > +   if (module_root != pinned_root) {
>> > +           if (unlikely(!modpin_enforced)) {
>> > +                   report_load_module(&file->f_path, "pinning-ignored");
>> > +                   return 0;
>> > +           }
>> > +
>> > +           report_load_module(&file->f_path, "denied");
>> > +           return -EPERM;
>> > +   }
>> > +
>> > +   return 0;
>> > +}
>> > +
>> > +static struct security_operations modpin_ops = {
>> > +   .name   = "modpin",
>> > +   .kernel_module_from_file = modpin_load_module,
>> > +};
>> > +
>> > +static int __init modpin_init(void)
>> > +{
>> > +   int error;
>> > +
>> > +   error = register_security(&modpin_ops);
>> > +
>> > +   if (error)
>> > +           panic("Could not register ModPin security module");
>> > +
>> > +   pr_info("ready to pin.\n");
>> > +
>> > +   return error;
>> > +}
>> > +security_initcall(modpin_init);
>> > +
>> > +module_param(modpin_enforced, int, S_IRUSR);
>> > +MODULE_PARM_DESC(modpin_enforced, "Module pinning enforced (default: true)");
>> > --
>> > 1.7.9.5
>> >
>> >
>> > --
>> > Kees Cook
>> > Chrome OS Security
>> > --
>> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> > the body of a message to majordomo@vger.kernel.org
>> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> > Please read the FAQ at  http://www.tux.org/lkml/
>> >
>>
>> --
>> James Morris
>> <jmorris@namei.org>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>
> --
> James Morris
> <jmorris@namei.org>



-- 
Kees Cook
Chrome OS Security

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-09-24  1:45     ` Kees Cook
@ 2013-10-03 20:55       ` Kees Cook
  2013-10-03 21:31         ` Tetsuo Handa
  2013-10-16 15:18       ` Kees Cook
  1 sibling, 1 reply; 23+ messages in thread
From: Kees Cook @ 2013-10-03 20:55 UTC (permalink / raw)
  To: Kees Cook
  Cc: James Morris, LKML, James Morris, Casey Schaufler,
	linux-security-module, Rusty Russell

On Mon, Sep 23, 2013 at 06:45:35PM -0700, Kees Cook wrote:
> [+rusty]
> 
> On Mon, Sep 23, 2013 at 6:28 PM, James Morris <jmorris@namei.org> wrote:
> > On Tue, 24 Sep 2013, James Morris wrote:
> >
> >> On Fri, 20 Sep 2013, Kees Cook wrote:
> >>
> >> > This LSM enforces that modules must all come from the same filesystem,
> >> > with the expectation that such a filesystem is backed by a read-only
> >> > device such as dm-verity or CDROM. This allows systems that have a
> >> > verified or unchanging filesystem to enforce module loading restrictions
> >> > without needing to sign the modules individually.
> >> >
> >> > Signed-off-by: Kees Cook <keescook@chromium.org>
> >>
> >> Are you using this for ChromeOS?
> 
> Yes. Chrome OS uses a read-only root filesystem that is backed by
> dm-verity. This lets us pin all module loading to that filesystem
> without needing per-module signatures.
> 
> > Also, you should CC Rusty on this.
> 
> Done! :)

Ping... any feedback on this? I'd like to get this landed so I can send
further patches that touch this and IMA.

Thanks,

-Kees

> 
> -Kees
> 
> >
> >
> >>
> >>
> >> > ---
> >> >  security/Kconfig         |    6 ++
> >> >  security/Makefile        |    2 +
> >> >  security/modpin/Kconfig  |    9 +++
> >> >  security/modpin/Makefile |    1 +
> >> >  security/modpin/modpin.c |  197 ++++++++++++++++++++++++++++++++++++++++++++++
> >> >  5 files changed, 215 insertions(+)
> >> >  create mode 100644 security/modpin/Kconfig
> >> >  create mode 100644 security/modpin/Makefile
> >> >  create mode 100644 security/modpin/modpin.c
> >> >
> >> > diff --git a/security/Kconfig b/security/Kconfig
> >> > index e9c6ac7..80172fd 100644
> >> > --- a/security/Kconfig
> >> > +++ b/security/Kconfig
> >> > @@ -121,6 +121,7 @@ source security/selinux/Kconfig
> >> >  source security/smack/Kconfig
> >> >  source security/tomoyo/Kconfig
> >> >  source security/apparmor/Kconfig
> >> > +source security/modpin/Kconfig
> >> >  source security/yama/Kconfig
> >> >
> >> >  source security/integrity/Kconfig
> >> > @@ -131,6 +132,7 @@ choice
> >> >     default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
> >> >     default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
> >> >     default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
> >> > +   default DEFAULT_SECURITY_MODPIN if SECURITY_MODPIN
> >> >     default DEFAULT_SECURITY_YAMA if SECURITY_YAMA
> >> >     default DEFAULT_SECURITY_DAC
> >> >
> >> > @@ -150,6 +152,9 @@ choice
> >> >     config DEFAULT_SECURITY_APPARMOR
> >> >             bool "AppArmor" if SECURITY_APPARMOR=y
> >> >
> >> > +   config DEFAULT_SECURITY_MODPIN
> >> > +           bool "ModPin" if SECURITY_MODPIN=y
> >> > +
> >> >     config DEFAULT_SECURITY_YAMA
> >> >             bool "Yama" if SECURITY_YAMA=y
> >> >
> >> > @@ -164,6 +169,7 @@ config DEFAULT_SECURITY
> >> >     default "smack" if DEFAULT_SECURITY_SMACK
> >> >     default "tomoyo" if DEFAULT_SECURITY_TOMOYO
> >> >     default "apparmor" if DEFAULT_SECURITY_APPARMOR
> >> > +   default "modpin" if DEFAULT_SECURITY_MODPIN
> >> >     default "yama" if DEFAULT_SECURITY_YAMA
> >> >     default "" if DEFAULT_SECURITY_DAC
> >> >
> >> > diff --git a/security/Makefile b/security/Makefile
> >> > index c26c81e..73d0a05 100644
> >> > --- a/security/Makefile
> >> > +++ b/security/Makefile
> >> > @@ -7,6 +7,7 @@ subdir-$(CONFIG_SECURITY_SELINUX)   += selinux
> >> >  subdir-$(CONFIG_SECURITY_SMACK)            += smack
> >> >  subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
> >> >  subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor
> >> > +subdir-$(CONFIG_SECURITY_MODPIN)   += modpin
> >> >  subdir-$(CONFIG_SECURITY_YAMA)             += yama
> >> >
> >> >  # always enable default capabilities
> >> > @@ -22,6 +23,7 @@ obj-$(CONFIG_SECURITY_SMACK)              += smack/built-in.o
> >> >  obj-$(CONFIG_AUDIT)                        += lsm_audit.o
> >> >  obj-$(CONFIG_SECURITY_TOMOYO)              += tomoyo/built-in.o
> >> >  obj-$(CONFIG_SECURITY_APPARMOR)            += apparmor/built-in.o
> >> > +obj-$(CONFIG_SECURITY_MODPIN)              += modpin/built-in.o
> >> >  obj-$(CONFIG_SECURITY_YAMA)                += yama/built-in.o
> >> >  obj-$(CONFIG_CGROUP_DEVICE)                += device_cgroup.o
> >> >
> >> > diff --git a/security/modpin/Kconfig b/security/modpin/Kconfig
> >> > new file mode 100644
> >> > index 0000000..5be9dd5
> >> > --- /dev/null
> >> > +++ b/security/modpin/Kconfig
> >> > @@ -0,0 +1,9 @@
> >> > +config SECURITY_MODPIN
> >> > +   bool "Module filesystem origin pinning"
> >> > +   depends on SECURITY
> >> > +   help
> >> > +     Module loading will be pinned to the first filesystem used for
> >> > +     loading. Any modules that come from other filesystems will be
> >> > +     rejected. This is best used on systems without an initrd that
> >> > +     have a root filesystem backed by a read-only device such as
> >> > +     dm-verity or a CDROM.
> >> > diff --git a/security/modpin/Makefile b/security/modpin/Makefile
> >> > new file mode 100644
> >> > index 0000000..9080b29
> >> > --- /dev/null
> >> > +++ b/security/modpin/Makefile
> >> > @@ -0,0 +1 @@
> >> > +obj-$(CONFIG_SECURITY_MODPIN) += modpin.o
> >> > diff --git a/security/modpin/modpin.c b/security/modpin/modpin.c
> >> > new file mode 100644
> >> > index 0000000..107b4d8
> >> > --- /dev/null
> >> > +++ b/security/modpin/modpin.c
> >> > @@ -0,0 +1,197 @@
> >> > +/*
> >> > + * Module Pinning Security Module
> >> > + *
> >> > + * Copyright 2011-2013 Google Inc.
> >> > + *
> >> > + * Authors:
> >> > + *      Kees Cook       <keescook@chromium.org>
> >> > + *
> >> > + * This software is licensed under the terms of the GNU General Public
> >> > + * License version 2, as published by the Free Software Foundation, and
> >> > + * may be copied, distributed, and modified under those terms.
> >> > + *
> >> > + * This program is distributed in the hope that it will be useful,
> >> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >> > + * GNU General Public License for more details.
> >> > + */
> >> > +
> >> > +#define pr_fmt(fmt) "ModPin LSM: " fmt
> >> > +
> >> > +#include <linux/module.h>
> >> > +#include <linux/security.h>
> >> > +#include <linux/sched.h>
> >> > +#include <linux/fs.h>
> >> > +#include <linux/fs_struct.h>
> >> > +#include <linux/mount.h>
> >> > +#include <linux/path.h>
> >> > +#include <linux/root_dev.h>
> >> > +
> >> > +static void report_load_module(struct path *path, char *operation)
> >> > +{
> >> > +   char *alloced = NULL;
> >> > +   char *pathname; /* Pointer to either static string or "alloced". */
> >> > +
> >> > +   if (!path)
> >> > +           pathname = "<unknown>";
> >> > +   else {
> >> > +           /* We will allow 11 spaces for ' (deleted)' to be appended */
> >> > +           alloced = pathname = kmalloc(PATH_MAX+11, GFP_KERNEL);
> >> > +           if (!pathname)
> >> > +                   pathname = "<no_memory>";
> >> > +           else {
> >> > +                   pathname = d_path(path, pathname, PATH_MAX+11);
> >> > +                   if (IS_ERR(pathname))
> >> > +                           pathname = "<too_long>";
> >> > +           }
> >> > +   }
> >> > +
> >> > +   pr_notice("init_module %s module=%s pid=%d\n",
> >> > +             operation, pathname, task_pid_nr(current));
> >> > +
> >> > +   kfree(alloced);
> >> > +}
> >> > +
> >> > +static int modpin_enforced = 1;
> >> > +static struct dentry *pinned_root;
> >> > +static DEFINE_SPINLOCK(pinned_root_spinlock);
> >> > +
> >> > +#ifdef CONFIG_SYSCTL
> >> > +static int zero;
> >> > +static int one = 1;
> >> > +
> >> > +static struct ctl_path modpin_sysctl_path[] = {
> >> > +   { .procname = "kernel", },
> >> > +   { .procname = "modpin", },
> >> > +   { }
> >> > +};
> >> > +
> >> > +static struct ctl_table modpin_sysctl_table[] = {
> >> > +   {
> >> > +           .procname       = "enforced",
> >> > +           .data           = &modpin_enforced,
> >> > +           .maxlen         = sizeof(int),
> >> > +           .mode           = 0644,
> >> > +           .proc_handler   = proc_dointvec_minmax,
> >> > +           .extra1         = &zero,
> >> > +           .extra2         = &one,
> >> > +   },
> >> > +   { }
> >> > +};
> >> > +
> >> > +/*
> >> > + * Check if the root device is read-only (e.g. dm-verity is enabled).
> >> > + * This must be called after early kernel init, since only then is the
> >> > + * rootdev available.
> >> > + */
> >> > +static bool rootdev_readonly(void)
> >> > +{
> >> > +   bool rc;
> >> > +   struct block_device *bdev;
> >> > +   const fmode_t mode = FMODE_WRITE;
> >> > +
> >> > +   bdev = blkdev_get_by_dev(ROOT_DEV, mode, NULL);
> >> > +   if (IS_ERR(bdev)) {
> >> > +           /* In this weird case, assume it is read-only. */
> >> > +           pr_info("dev(%u,%u): FMODE_WRITE disallowed?!\n",
> >> > +                   MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
> >> > +           return true;
> >> > +   }
> >> > +
> >> > +   rc = bdev_read_only(bdev);
> >> > +   blkdev_put(bdev, mode);
> >> > +
> >> > +   pr_info("dev(%u,%u): %s\n", MAJOR(ROOT_DEV), MINOR(ROOT_DEV),
> >> > +           rc ? "read-only" : "writable");
> >> > +
> >> > +   return rc;
> >> > +}
> >> > +
> >> > +static void check_pinning_enforcement(void)
> >> > +{
> >> > +   /*
> >> > +    * If module pinning is not being enforced, allow sysctl to change
> >> > +    * modes for testing.
> >> > +    */
> >> > +   if (!rootdev_readonly()) {
> >> > +           if (!register_sysctl_paths(modpin_sysctl_path,
> >> > +                                      modpin_sysctl_table))
> >> > +                   pr_notice("sysctl registration failed!\n");
> >> > +           else
> >> > +                   pr_info("module pinning can be disabled.\n");
> >> > +   } else
> >> > +           pr_info("module pinning engaged.\n");
> >> > +}
> >> > +#else
> >> > +static void check_pinning_enforcement(void) { }
> >> > +#endif
> >> > +
> >> > +
> >> > +static int modpin_load_module(struct file *file)
> >> > +{
> >> > +   struct dentry *module_root;
> >> > +
> >> > +   if (!file) {
> >> > +           if (!modpin_enforced) {
> >> > +                   report_load_module(NULL, "old-api-pinning-ignored");
> >> > +                   return 0;
> >> > +           }
> >> > +
> >> > +           report_load_module(NULL, "old-api-denied");
> >> > +           return -EPERM;
> >> > +   }
> >> > +
> >> > +   module_root = file->f_path.mnt->mnt_root;
> >> > +
> >> > +   /* First loaded module defines the root for all others. */
> >> > +   spin_lock(&pinned_root_spinlock);
> >> > +   if (!pinned_root) {
> >> > +           pinned_root = dget(module_root);
> >> > +           /*
> >> > +            * Unlock now since it's only pinned_root we care about.
> >> > +            * In the worst case, we will (correctly) report pinning
> >> > +            * failures before we have announced that pinning is
> >> > +            * enabled. This would be purely cosmetic.
> >> > +            */
> >> > +           spin_unlock(&pinned_root_spinlock);
> >> > +           check_pinning_enforcement();
> >> > +           report_load_module(&file->f_path, "pinned");
> >> > +           return 0;
> >> > +   }
> >> > +   spin_unlock(&pinned_root_spinlock);
> >> > +
> >> > +   if (module_root != pinned_root) {
> >> > +           if (unlikely(!modpin_enforced)) {
> >> > +                   report_load_module(&file->f_path, "pinning-ignored");
> >> > +                   return 0;
> >> > +           }
> >> > +
> >> > +           report_load_module(&file->f_path, "denied");
> >> > +           return -EPERM;
> >> > +   }
> >> > +
> >> > +   return 0;
> >> > +}
> >> > +
> >> > +static struct security_operations modpin_ops = {
> >> > +   .name   = "modpin",
> >> > +   .kernel_module_from_file = modpin_load_module,
> >> > +};
> >> > +
> >> > +static int __init modpin_init(void)
> >> > +{
> >> > +   int error;
> >> > +
> >> > +   error = register_security(&modpin_ops);
> >> > +
> >> > +   if (error)
> >> > +           panic("Could not register ModPin security module");
> >> > +
> >> > +   pr_info("ready to pin.\n");
> >> > +
> >> > +   return error;
> >> > +}
> >> > +security_initcall(modpin_init);
> >> > +
> >> > +module_param(modpin_enforced, int, S_IRUSR);
> >> > +MODULE_PARM_DESC(modpin_enforced, "Module pinning enforced (default: true)");
> >> > --
> >> > 1.7.9.5
> >> >
> >> >
> >> > --
> >> > Kees Cook
> >> > Chrome OS Security
> >> > --
> >> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> >> > the body of a message to majordomo@vger.kernel.org
> >> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >> > Please read the FAQ at  http://www.tux.org/lkml/
> >> >
> >>
> >> --
> >> James Morris
> >> <jmorris@namei.org>
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >>
> >
> > --
> > James Morris
> > <jmorris@namei.org>
> 
> 
> 
> -- 
> Kees Cook
> Chrome OS Security
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
Kees Cook                                            @outflux.net

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-10-03 20:55       ` Kees Cook
@ 2013-10-03 21:31         ` Tetsuo Handa
  2013-10-03 21:36           ` Kees Cook
  0 siblings, 1 reply; 23+ messages in thread
From: Tetsuo Handa @ 2013-10-03 21:31 UTC (permalink / raw)
  To: kees, keescook
  Cc: jmorris, linux-kernel, james.l.morris, casey,
	linux-security-module, rusty

Kees Cook wrote:
> +static int modpin_load_module(struct file *file)
> +{
> +   struct dentry *module_root;
> +
> +   if (!file) {
> +           if (!modpin_enforced) {
> +                   report_load_module(NULL, "old-api-pinning-ignored");
> +                   return 0;
> +           }
> +
> +           report_load_module(NULL, "old-api-denied");
> +           return -EPERM;
> +   }
> +
> +   module_root = file->f_path.mnt->mnt_root;
> +
> +   /* First loaded module defines the root for all others. */
> +   spin_lock(&pinned_root_spinlock);
> +   if (!pinned_root) {
> +           pinned_root = dget(module_root);
> +           /*
> +            * Unlock now since it's only pinned_root we care about.
> +            * In the worst case, we will (correctly) report pinning
> +            * failures before we have announced that pinning is
> +            * enabled. This would be purely cosmetic.
> +            */
> +           spin_unlock(&pinned_root_spinlock);
> +           check_pinning_enforcement();
> +           report_load_module(&file->f_path, "pinned");
> +           return 0;
> +   }
> +   spin_unlock(&pinned_root_spinlock);

Firstly loaded module is usually in initramfs whereas subsequently loaded
modules are usually on a hard disk partition.

This module is not meant for PC servers, is it?

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-10-03 21:31         ` Tetsuo Handa
@ 2013-10-03 21:36           ` Kees Cook
  2013-10-23  2:55             ` Lucas De Marchi
  0 siblings, 1 reply; 23+ messages in thread
From: Kees Cook @ 2013-10-03 21:36 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: keescook, jmorris, linux-kernel, james.l.morris, casey,
	linux-security-module, rusty

On Fri, Oct 04, 2013 at 06:31:42AM +0900, Tetsuo Handa wrote:
> Kees Cook wrote:
> > +static int modpin_load_module(struct file *file)
> > +{
> > +   struct dentry *module_root;
> > +
> > +   if (!file) {
> > +           if (!modpin_enforced) {
> > +                   report_load_module(NULL, "old-api-pinning-ignored");
> > +                   return 0;
> > +           }
> > +
> > +           report_load_module(NULL, "old-api-denied");
> > +           return -EPERM;
> > +   }
> > +
> > +   module_root = file->f_path.mnt->mnt_root;
> > +
> > +   /* First loaded module defines the root for all others. */
> > +   spin_lock(&pinned_root_spinlock);
> > +   if (!pinned_root) {
> > +           pinned_root = dget(module_root);
> > +           /*
> > +            * Unlock now since it's only pinned_root we care about.
> > +            * In the worst case, we will (correctly) report pinning
> > +            * failures before we have announced that pinning is
> > +            * enabled. This would be purely cosmetic.
> > +            */
> > +           spin_unlock(&pinned_root_spinlock);
> > +           check_pinning_enforcement();
> > +           report_load_module(&file->f_path, "pinned");
> > +           return 0;
> > +   }
> > +   spin_unlock(&pinned_root_spinlock);
> 
> Firstly loaded module is usually in initramfs whereas subsequently loaded
> modules are usually on a hard disk partition.
> 
> This module is not meant for PC servers, is it?

This LSM is what Chrome OS uses for the module pinning logic. We do not use
an initramfs. This LSM could also be used for devices booting entirely from
CDROM or other R/O media.

I'm open to improvements, obviously. I imagine things like delayed
activation, where the initramfs triggers pinning in some way once it is
done loading modules from its filesystem, etc. But since I don't have any
real life examples of this, I'm writing the LSM as it currently is, used
without an initramfs. :)

-Kees

-- 
Kees Cook                                            @outflux.net

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-09-24  1:45     ` Kees Cook
  2013-10-03 20:55       ` Kees Cook
@ 2013-10-16 15:18       ` Kees Cook
  2013-10-16 20:47         ` Tetsuo Handa
  1 sibling, 1 reply; 23+ messages in thread
From: Kees Cook @ 2013-10-16 15:18 UTC (permalink / raw)
  To: James Morris
  Cc: James Morris, LKML, Casey Schaufler, linux-security-module,
	Rusty Russell

Hi James,

On Mon, Sep 23, 2013 at 06:45:35PM -0700, Kees Cook wrote:
> [+rusty]
> 
> On Mon, Sep 23, 2013 at 6:28 PM, James Morris <jmorris@namei.org> wrote:
> > On Tue, 24 Sep 2013, James Morris wrote:
> >
> >> On Fri, 20 Sep 2013, Kees Cook wrote:
> >>
> >> > This LSM enforces that modules must all come from the same filesystem,
> >> > with the expectation that such a filesystem is backed by a read-only
> >> > device such as dm-verity or CDROM. This allows systems that have a
> >> > verified or unchanging filesystem to enforce module loading restrictions
> >> > without needing to sign the modules individually.
> >> >
> >> > Signed-off-by: Kees Cook <keescook@chromium.org>
> >>
> >> Are you using this for ChromeOS?
> 
> Yes. Chrome OS uses a read-only root filesystem that is backed by
> dm-verity. This lets us pin all module loading to that filesystem
> without needing per-module signatures.
> 
> > Also, you should CC Rusty on this.
> 
> Done! :)

Any update on this? It'd be nice to have it in linux-next.

Thanks,

-Kees

-- 
Kees Cook                                            @outflux.net

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-10-16 15:18       ` Kees Cook
@ 2013-10-16 20:47         ` Tetsuo Handa
  2013-10-16 21:42           ` Casey Schaufler
  0 siblings, 1 reply; 23+ messages in thread
From: Tetsuo Handa @ 2013-10-16 20:47 UTC (permalink / raw)
  To: keescook, james.l.morris
  Cc: jmorris, linux-kernel, casey, linux-security-module, rusty

Kees Cook wrote:
> Any update on this? It'd be nice to have it in linux-next.

What was the conclusion at LSS about multiple concurrent LSM support?
If we agreed to merge multiple concurrent LSM support, there will be nothing to
prevent this module from merging.

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-10-16 20:47         ` Tetsuo Handa
@ 2013-10-16 21:42           ` Casey Schaufler
  2013-10-16 22:43             ` Kees Cook
  0 siblings, 1 reply; 23+ messages in thread
From: Casey Schaufler @ 2013-10-16 21:42 UTC (permalink / raw)
  To: Tetsuo Handa, keescook, james.l.morris
  Cc: jmorris, linux-kernel, linux-security-module, rusty, Casey Schaufler

On 10/16/2013 1:47 PM, Tetsuo Handa wrote:
> Kees Cook wrote:
>> Any update on this? It'd be nice to have it in linux-next.
> What was the conclusion at LSS about multiple concurrent LSM support?
> If we agreed to merge multiple concurrent LSM support, there will be nothing to
> prevent this module from merging.
>
Yeah.

The conclusion was that it needs to be staged because it's
too much to swallow all at once. I can see that. It's going
to be a lot of work to rearrange and rebase. That's a chunk
of time I don't expect to have for a while. It looks good
to happen, but don't hold supper for me.


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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-10-16 21:42           ` Casey Schaufler
@ 2013-10-16 22:43             ` Kees Cook
  2013-10-17  0:37               ` Tetsuo Handa
  2013-10-18  2:25               ` Casey Schaufler
  0 siblings, 2 replies; 23+ messages in thread
From: Kees Cook @ 2013-10-16 22:43 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Tetsuo Handa, James Morris, James Morris, LKML,
	linux-security-module, Rusty Russell

On Wed, Oct 16, 2013 at 2:42 PM, Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 10/16/2013 1:47 PM, Tetsuo Handa wrote:
>> Kees Cook wrote:
>>> Any update on this? It'd be nice to have it in linux-next.
>> What was the conclusion at LSS about multiple concurrent LSM support?
>> If we agreed to merge multiple concurrent LSM support, there will be nothing to
>> prevent this module from merging.
>>
> Yeah.

The discussion at LSS basically centered around the catch-22 of not
being able to stack, and not having anything to stack (since Yama got
an hard-coded exception). So I sent this LSM as one I'd been waiting
for stacking on. Essentially, I'm breaking the catch-22 by sending
this. I'd like it to get into the tree so we don't have a catch-22
about stacking any more. :)

> The conclusion was that it needs to be staged because it's
> too much to swallow all at once. I can see that. It's going
> to be a lot of work to rearrange and rebase. That's a chunk
> of time I don't expect to have for a while. It looks good
> to happen, but don't hold supper for me.

Do you want me to take a stab at it? It sounds like it was desirable
to cut the current series into two halves? The core changes first, and
the userspace interface changes next?

-Kees

-- 
Kees Cook
Chrome OS Security

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-10-16 22:43             ` Kees Cook
@ 2013-10-17  0:37               ` Tetsuo Handa
  2013-10-26 13:51                 ` Tetsuo Handa
  2013-10-18  2:25               ` Casey Schaufler
  1 sibling, 1 reply; 23+ messages in thread
From: Tetsuo Handa @ 2013-10-17  0:37 UTC (permalink / raw)
  To: keescook
  Cc: james.l.morris, jmorris, linux-kernel, linux-security-module,
	rusty, casey

Kees Cook wrote:
> So I sent this LSM as one I\'d been waiting
> for stacking on. Essentially, I\'m breaking the catch-22 by sending
> this. I\'d like it to get into the tree so we don\'t have a catch-22
> about stacking any more. :)

I\'m also trying to break the catch-22 by sending KPortReserve.
I would send another one which uses only security_file_alloc/free .

> The core changes first, and the userspace interface changes next?

I welcome that approach, for none of such single function LSM modules
depends on userspace interface changes.

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-09-20 20:35 [PATCH] LSM: ModPin LSM for module loading restrictions Kees Cook
  2013-09-24  1:24 ` James Morris
@ 2013-10-17  8:02 ` James Morris
  2013-10-17 11:30   ` Jarkko Sakkinen
  2013-10-17 17:26   ` Casey Schaufler
  1 sibling, 2 replies; 23+ messages in thread
From: James Morris @ 2013-10-17  8:02 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-kernel, James Morris, Casey Schaufler, linux-security-module

This seems like a regression in terms of separating mechanism and policy.  

We have several access control systems available (SELinux, at least) which 
can implement this functionality with existing mechanisms using dynamic 
policy.

I'm concerned about the long term architectural impact of a proliferation 
of arbitrary hard-coded security policies in the kernel.  I don't 
understand the push in this direction, frankly.



On Fri, 20 Sep 2013, Kees Cook wrote:

> This LSM enforces that modules must all come from the same filesystem,
> with the expectation that such a filesystem is backed by a read-only
> device such as dm-verity or CDROM. This allows systems that have a
> verified or unchanging filesystem to enforce module loading restrictions
> without needing to sign the modules individually.
> 
> Signed-off-by: Kees Cook <keescook@chromium.org>
> ---
>  security/Kconfig         |    6 ++
>  security/Makefile        |    2 +
>  security/modpin/Kconfig  |    9 +++
>  security/modpin/Makefile |    1 +
>  security/modpin/modpin.c |  197 ++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 215 insertions(+)
>  create mode 100644 security/modpin/Kconfig
>  create mode 100644 security/modpin/Makefile
>  create mode 100644 security/modpin/modpin.c
> 
> diff --git a/security/Kconfig b/security/Kconfig
> index e9c6ac7..80172fd 100644
> --- a/security/Kconfig
> +++ b/security/Kconfig
> @@ -121,6 +121,7 @@ source security/selinux/Kconfig
>  source security/smack/Kconfig
>  source security/tomoyo/Kconfig
>  source security/apparmor/Kconfig
> +source security/modpin/Kconfig
>  source security/yama/Kconfig
>  
>  source security/integrity/Kconfig
> @@ -131,6 +132,7 @@ choice
>  	default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
>  	default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
>  	default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
> +	default DEFAULT_SECURITY_MODPIN if SECURITY_MODPIN
>  	default DEFAULT_SECURITY_YAMA if SECURITY_YAMA
>  	default DEFAULT_SECURITY_DAC
>  
> @@ -150,6 +152,9 @@ choice
>  	config DEFAULT_SECURITY_APPARMOR
>  		bool "AppArmor" if SECURITY_APPARMOR=y
>  
> +	config DEFAULT_SECURITY_MODPIN
> +		bool "ModPin" if SECURITY_MODPIN=y
> +
>  	config DEFAULT_SECURITY_YAMA
>  		bool "Yama" if SECURITY_YAMA=y
>  
> @@ -164,6 +169,7 @@ config DEFAULT_SECURITY
>  	default "smack" if DEFAULT_SECURITY_SMACK
>  	default "tomoyo" if DEFAULT_SECURITY_TOMOYO
>  	default "apparmor" if DEFAULT_SECURITY_APPARMOR
> +	default "modpin" if DEFAULT_SECURITY_MODPIN
>  	default "yama" if DEFAULT_SECURITY_YAMA
>  	default "" if DEFAULT_SECURITY_DAC
>  
> diff --git a/security/Makefile b/security/Makefile
> index c26c81e..73d0a05 100644
> --- a/security/Makefile
> +++ b/security/Makefile
> @@ -7,6 +7,7 @@ subdir-$(CONFIG_SECURITY_SELINUX)	+= selinux
>  subdir-$(CONFIG_SECURITY_SMACK)		+= smack
>  subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
>  subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
> +subdir-$(CONFIG_SECURITY_MODPIN)	+= modpin
>  subdir-$(CONFIG_SECURITY_YAMA)		+= yama
>  
>  # always enable default capabilities
> @@ -22,6 +23,7 @@ obj-$(CONFIG_SECURITY_SMACK)		+= smack/built-in.o
>  obj-$(CONFIG_AUDIT)			+= lsm_audit.o
>  obj-$(CONFIG_SECURITY_TOMOYO)		+= tomoyo/built-in.o
>  obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/built-in.o
> +obj-$(CONFIG_SECURITY_MODPIN)		+= modpin/built-in.o
>  obj-$(CONFIG_SECURITY_YAMA)		+= yama/built-in.o
>  obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
>  
> diff --git a/security/modpin/Kconfig b/security/modpin/Kconfig
> new file mode 100644
> index 0000000..5be9dd5
> --- /dev/null
> +++ b/security/modpin/Kconfig
> @@ -0,0 +1,9 @@
> +config SECURITY_MODPIN
> +	bool "Module filesystem origin pinning"
> +	depends on SECURITY
> +	help
> +	  Module loading will be pinned to the first filesystem used for
> +	  loading. Any modules that come from other filesystems will be
> +	  rejected. This is best used on systems without an initrd that
> +	  have a root filesystem backed by a read-only device such as
> +	  dm-verity or a CDROM.
> diff --git a/security/modpin/Makefile b/security/modpin/Makefile
> new file mode 100644
> index 0000000..9080b29
> --- /dev/null
> +++ b/security/modpin/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_SECURITY_MODPIN) += modpin.o
> diff --git a/security/modpin/modpin.c b/security/modpin/modpin.c
> new file mode 100644
> index 0000000..107b4d8
> --- /dev/null
> +++ b/security/modpin/modpin.c
> @@ -0,0 +1,197 @@
> +/*
> + * Module Pinning Security Module
> + *
> + * Copyright 2011-2013 Google Inc.
> + *
> + * Authors:
> + *      Kees Cook       <keescook@chromium.org>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#define pr_fmt(fmt) "ModPin LSM: " fmt
> +
> +#include <linux/module.h>
> +#include <linux/security.h>
> +#include <linux/sched.h>
> +#include <linux/fs.h>
> +#include <linux/fs_struct.h>
> +#include <linux/mount.h>
> +#include <linux/path.h>
> +#include <linux/root_dev.h>
> +
> +static void report_load_module(struct path *path, char *operation)
> +{
> +	char *alloced = NULL;
> +	char *pathname; /* Pointer to either static string or "alloced". */
> +
> +	if (!path)
> +		pathname = "<unknown>";
> +	else {
> +		/* We will allow 11 spaces for ' (deleted)' to be appended */
> +		alloced = pathname = kmalloc(PATH_MAX+11, GFP_KERNEL);
> +		if (!pathname)
> +			pathname = "<no_memory>";
> +		else {
> +			pathname = d_path(path, pathname, PATH_MAX+11);
> +			if (IS_ERR(pathname))
> +				pathname = "<too_long>";
> +		}
> +	}
> +
> +	pr_notice("init_module %s module=%s pid=%d\n",
> +		  operation, pathname, task_pid_nr(current));
> +
> +	kfree(alloced);
> +}
> +
> +static int modpin_enforced = 1;
> +static struct dentry *pinned_root;
> +static DEFINE_SPINLOCK(pinned_root_spinlock);
> +
> +#ifdef CONFIG_SYSCTL
> +static int zero;
> +static int one = 1;
> +
> +static struct ctl_path modpin_sysctl_path[] = {
> +	{ .procname = "kernel", },
> +	{ .procname = "modpin", },
> +	{ }
> +};
> +
> +static struct ctl_table modpin_sysctl_table[] = {
> +	{
> +		.procname       = "enforced",
> +		.data           = &modpin_enforced,
> +		.maxlen         = sizeof(int),
> +		.mode           = 0644,
> +		.proc_handler   = proc_dointvec_minmax,
> +		.extra1         = &zero,
> +		.extra2         = &one,
> +	},
> +	{ }
> +};
> +
> +/*
> + * Check if the root device is read-only (e.g. dm-verity is enabled).
> + * This must be called after early kernel init, since only then is the
> + * rootdev available.
> + */
> +static bool rootdev_readonly(void)
> +{
> +	bool rc;
> +	struct block_device *bdev;
> +	const fmode_t mode = FMODE_WRITE;
> +
> +	bdev = blkdev_get_by_dev(ROOT_DEV, mode, NULL);
> +	if (IS_ERR(bdev)) {
> +		/* In this weird case, assume it is read-only. */
> +		pr_info("dev(%u,%u): FMODE_WRITE disallowed?!\n",
> +			MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
> +		return true;
> +	}
> +
> +	rc = bdev_read_only(bdev);
> +	blkdev_put(bdev, mode);
> +
> +	pr_info("dev(%u,%u): %s\n", MAJOR(ROOT_DEV), MINOR(ROOT_DEV),
> +		rc ? "read-only" : "writable");
> +
> +	return rc;
> +}
> +
> +static void check_pinning_enforcement(void)
> +{
> +	/*
> +	 * If module pinning is not being enforced, allow sysctl to change
> +	 * modes for testing.
> +	 */
> +	if (!rootdev_readonly()) {
> +		if (!register_sysctl_paths(modpin_sysctl_path,
> +					   modpin_sysctl_table))
> +			pr_notice("sysctl registration failed!\n");
> +		else
> +			pr_info("module pinning can be disabled.\n");
> +	} else
> +		pr_info("module pinning engaged.\n");
> +}
> +#else
> +static void check_pinning_enforcement(void) { }
> +#endif
> +
> +
> +static int modpin_load_module(struct file *file)
> +{
> +	struct dentry *module_root;
> +
> +	if (!file) {
> +		if (!modpin_enforced) {
> +			report_load_module(NULL, "old-api-pinning-ignored");
> +			return 0;
> +		}
> +
> +		report_load_module(NULL, "old-api-denied");
> +		return -EPERM;
> +	}
> +
> +	module_root = file->f_path.mnt->mnt_root;
> +
> +	/* First loaded module defines the root for all others. */
> +	spin_lock(&pinned_root_spinlock);
> +	if (!pinned_root) {
> +		pinned_root = dget(module_root);
> +		/*
> +		 * Unlock now since it's only pinned_root we care about.
> +		 * In the worst case, we will (correctly) report pinning
> +		 * failures before we have announced that pinning is
> +		 * enabled. This would be purely cosmetic.
> +		 */
> +		spin_unlock(&pinned_root_spinlock);
> +		check_pinning_enforcement();
> +		report_load_module(&file->f_path, "pinned");
> +		return 0;
> +	}
> +	spin_unlock(&pinned_root_spinlock);
> +
> +	if (module_root != pinned_root) {
> +		if (unlikely(!modpin_enforced)) {
> +			report_load_module(&file->f_path, "pinning-ignored");
> +			return 0;
> +		}
> +
> +		report_load_module(&file->f_path, "denied");
> +		return -EPERM;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct security_operations modpin_ops = {
> +	.name	= "modpin",
> +	.kernel_module_from_file = modpin_load_module,
> +};
> +
> +static int __init modpin_init(void)
> +{
> +	int error;
> +
> +	error = register_security(&modpin_ops);
> +
> +	if (error)
> +		panic("Could not register ModPin security module");
> +
> +	pr_info("ready to pin.\n");
> +
> +	return error;
> +}
> +security_initcall(modpin_init);
> +
> +module_param(modpin_enforced, int, S_IRUSR);
> +MODULE_PARM_DESC(modpin_enforced, "Module pinning enforced (default: true)");
> -- 
> 1.7.9.5
> 
> 
> -- 
> Kees Cook
> Chrome OS Security
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 

-- 
James Morris
<jmorris@namei.org>

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-10-17  8:02 ` James Morris
@ 2013-10-17 11:30   ` Jarkko Sakkinen
  2013-10-17 21:00     ` Kees Cook
  2013-10-17 17:26   ` Casey Schaufler
  1 sibling, 1 reply; 23+ messages in thread
From: Jarkko Sakkinen @ 2013-10-17 11:30 UTC (permalink / raw)
  To: James Morris
  Cc: Kees Cook, linux-kernel, James Morris, Casey Schaufler,
	linux-security-module

On Thu, Oct 17, 2013 at 07:02:17PM +1100, James Morris wrote:
> This seems like a regression in terms of separating mechanism and policy.  
> 
> We have several access control systems available (SELinux, at least) which 
> can implement this functionality with existing mechanisms using dynamic 
> policy.
> 
> I'm concerned about the long term architectural impact of a proliferation 
> of arbitrary hard-coded security policies in the kernel.  I don't 
> understand the push in this direction, frankly.

The biggest risk in LSM stacker is really to become backdoor for very product
dilated kernel changes that are not accepted to the mainline kernel. I think
having LSM stacker would be benefical but barrier should be set very high
for "one-shot" modules.

One big benefit that I see in LSM stacker is not at least directly security
related. It would be perfect integration tool when you want for example
provide Android run-time in an OS that uses AppArmor or SMACK as its security
framework.

/Jarkko

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-10-17  8:02 ` James Morris
  2013-10-17 11:30   ` Jarkko Sakkinen
@ 2013-10-17 17:26   ` Casey Schaufler
  2013-10-17 21:09     ` Kees Cook
  2013-10-23  0:02     ` James Morris
  1 sibling, 2 replies; 23+ messages in thread
From: Casey Schaufler @ 2013-10-17 17:26 UTC (permalink / raw)
  To: James Morris, Kees Cook
  Cc: linux-kernel, James Morris, linux-security-module, Casey Schaufler

On 10/17/2013 1:02 AM, James Morris wrote:
> This seems like a regression in terms of separating mechanism and policy.  
>
> We have several access control systems available (SELinux, at least) which 
> can implement this functionality with existing mechanisms using dynamic 
> policy.

They said the same thing about Smack.

The problem there is that you have to buy into the entirety of
SELinux to implement a small bit of behavior. You have to write
a policy that takes every aspect of system behavior into account
when all you care about is loading restrictions on modules.

If you want all of SELinux you still have to define your problem
in a subject/object model. That may be possible, but in this
case at least it certainly ain't obvious.

> I'm concerned about the long term architectural impact of a proliferation 
> of arbitrary hard-coded security policies in the kernel.  I don't 
> understand the push in this direction, frankly.

The rationale is that lots of people doing little things is
likely to get us relevant security in a reasonable amount of time.
The existing LSMs reflect 20th century technologies and use cases.
They are fine for multi-user timesharing systems. We need to move
forward to support networked gaming, phones, tablets and toasters.

>
> On Fri, 20 Sep 2013, Kees Cook wrote:
>
>> ...
>> -- 
>> 1.7.9.5
>>
>>
>> -- 
>> Kees Cook
>> Chrome OS Security
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at  http://www.tux.org/lkml/
>>
>


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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-10-17 11:30   ` Jarkko Sakkinen
@ 2013-10-17 21:00     ` Kees Cook
  0 siblings, 0 replies; 23+ messages in thread
From: Kees Cook @ 2013-10-17 21:00 UTC (permalink / raw)
  To: Jarkko Sakkinen
  Cc: James Morris, LKML, James Morris, Casey Schaufler, linux-security-module

On Thu, Oct 17, 2013 at 4:30 AM, Jarkko Sakkinen
<jarkko.sakkinen@linux.intel.com> wrote:
> On Thu, Oct 17, 2013 at 07:02:17PM +1100, James Morris wrote:
>> This seems like a regression in terms of separating mechanism and policy.
>>
>> We have several access control systems available (SELinux, at least) which
>> can implement this functionality with existing mechanisms using dynamic
>> policy.
>>
>> I'm concerned about the long term architectural impact of a proliferation
>> of arbitrary hard-coded security policies in the kernel.  I don't
>> understand the push in this direction, frankly.
>
> The biggest risk in LSM stacker is really to become backdoor for very product
> dilated kernel changes that are not accepted to the mainline kernel. I think
> having LSM stacker would be benefical but barrier should be set very high
> for "one-shot" modules.
>
> One big benefit that I see in LSM stacker is not at least directly security
> related. It would be perfect integration tool when you want for example
> provide Android run-time in an OS that uses AppArmor or SMACK as its security
> framework.

I think of stacking as a way to help people do quick prototyping of
security changes without getting in the way of their distro's MAC.

-Kees

-- 
Kees Cook
Chrome OS Security

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-10-17 17:26   ` Casey Schaufler
@ 2013-10-17 21:09     ` Kees Cook
  2013-10-23  0:02     ` James Morris
  1 sibling, 0 replies; 23+ messages in thread
From: Kees Cook @ 2013-10-17 21:09 UTC (permalink / raw)
  To: Casey Schaufler; +Cc: James Morris, LKML, James Morris, linux-security-module

On Thu, Oct 17, 2013 at 10:26 AM, Casey Schaufler
<casey@schaufler-ca.com> wrote:
> On 10/17/2013 1:02 AM, James Morris wrote:
>> This seems like a regression in terms of separating mechanism and policy.
>>
>> We have several access control systems available (SELinux, at least) which
>> can implement this functionality with existing mechanisms using dynamic
>> policy.
>
> They said the same thing about Smack.
>
> The problem there is that you have to buy into the entirety of
> SELinux to implement a small bit of behavior. You have to write
> a policy that takes every aspect of system behavior into account
> when all you care about is loading restrictions on modules.
>
> If you want all of SELinux you still have to define your problem
> in a subject/object model. That may be possible, but in this
> case at least it certainly ain't obvious.
>
>> I'm concerned about the long term architectural impact of a proliferation
>> of arbitrary hard-coded security policies in the kernel.  I don't
>> understand the push in this direction, frankly.
>
> The rationale is that lots of people doing little things is
> likely to get us relevant security in a reasonable amount of time.
> The existing LSMs reflect 20th century technologies and use cases.
> They are fine for multi-user timesharing systems. We need to move
> forward to support networked gaming, phones, tablets and toasters.

I, obviously, agree with with this. At least with Chrome OS, we've
been taking an architectural approach to security. Our trust model is
based on very different ways of doing things, and this results in
needing to trust things that are not part of the traditional
subject/object model, IMO. We trust the contents of our root
filesystem, so there's no need to do things like module signing, etc.
In many ways, IMA follows similar approaches but at a different layer
(i.e. we use dm-verity).

Chrome OS has been using this LSM for about a year now. It provides
demonstrably improved security since it draws a bright line between
uid-0 and ring-0 on systems that have a verified boot path but use
kernel modules.

-Kees

-- 
Kees Cook
Chrome OS Security

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-10-16 22:43             ` Kees Cook
  2013-10-17  0:37               ` Tetsuo Handa
@ 2013-10-18  2:25               ` Casey Schaufler
  1 sibling, 0 replies; 23+ messages in thread
From: Casey Schaufler @ 2013-10-18  2:25 UTC (permalink / raw)
  To: Kees Cook
  Cc: Tetsuo Handa, James Morris, James Morris, LKML,
	linux-security-module, Rusty Russell, Casey Schaufler

On 10/16/2013 3:43 PM, Kees Cook wrote:
> On Wed, Oct 16, 2013 at 2:42 PM, Casey Schaufler <casey@schaufler-ca.com> wrote:
>> On 10/16/2013 1:47 PM, Tetsuo Handa wrote:
>>> Kees Cook wrote:
>>>> Any update on this? It'd be nice to have it in linux-next.
>>> What was the conclusion at LSS about multiple concurrent LSM support?
>>> If we agreed to merge multiple concurrent LSM support, there will be nothing to
>>> prevent this module from merging.
>>>
>> Yeah.
> The discussion at LSS basically centered around the catch-22 of not
> being able to stack, and not having anything to stack (since Yama got
> an hard-coded exception). So I sent this LSM as one I'd been waiting
> for stacking on. Essentially, I'm breaking the catch-22 by sending
> this. I'd like it to get into the tree so we don't have a catch-22
> about stacking any more. :)
>
>> The conclusion was that it needs to be staged because it's
>> too much to swallow all at once. I can see that. It's going
>> to be a lot of work to rearrange and rebase. That's a chunk
>> of time I don't expect to have for a while. It looks good
>> to happen, but don't hold supper for me.
> Do you want me to take a stab at it? It sounds like it was desirable
> to cut the current series into two halves? The core changes first, and
> the userspace interface changes next?

My read on it was a three phased approach:

First, move the cap "module" checks out of the other modules
and directly into security.c. There would be no "default" module.
If another module is loaded, call the hook it defines if the cap
check passes. Add /sys/kernel/security/lsm to make it easy to
find out what module (if any) is active.

Second, allow more than one LSM to get called if so requested.
Call them all, and return the error code of the last failure.
Refuse to load more than one module that uses an exclusive feature;
netlabel, secmark or XFRM.

Finally, put in all the gimmicks to decide who gets which of the
networking facilities.

Yes, If you've got the cycles to work with it I'd be happy for the help.


>
> -Kees
>


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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-10-17 17:26   ` Casey Schaufler
  2013-10-17 21:09     ` Kees Cook
@ 2013-10-23  0:02     ` James Morris
  2013-10-23  1:03       ` Casey Schaufler
  1 sibling, 1 reply; 23+ messages in thread
From: James Morris @ 2013-10-23  0:02 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Kees Cook, linux-kernel, James Morris, linux-security-module

On Thu, 17 Oct 2013, Casey Schaufler wrote:

> On 10/17/2013 1:02 AM, James Morris wrote:
> > This seems like a regression in terms of separating mechanism and policy.  
> >
> > We have several access control systems available (SELinux, at least) which 
> > can implement this functionality with existing mechanisms using dynamic 
> > policy.
> 
> They said the same thing about Smack.
> 

Nope.  Smack separates mechanism and policy.  The argument then was 
whether we need more than one such enhanced access control system.

The issue now is that we do have several of them (SELinux, Smack, 
AppArmor) which are policy-flexible, whether to regress back to adding 
hard-coded security policies into the kernel.

> The problem there is that you have to buy into the entirety of
> SELinux to implement a small bit of behavior. You have to write
> a policy that takes every aspect of system behavior into account
> when all you care about is loading restrictions on modules.

You always need to consider the behavior of the system as a whole when 
designing security policies.

It's a major step backwards to hard-code a series of ad-hoc policies in 
the kernel.  You still need to compose them somehow, and reason about the 
security of the system as a whole.

> The rationale is that lots of people doing little things is
> likely to get us relevant security in a reasonable amount of time.
> The existing LSMs reflect 20th century technologies and use cases.
> They are fine for multi-user timesharing systems. We need to move
> forward to support networked gaming, phones, tablets and toasters.

You keep making these grand assertions but never provide any detail, or 
any kind of evidence to back them up.  Yet there are many, many examples 
of how the current LSMs meet all of these needs in the 21st century, such 
as Smack being adopted for Tizen, digital television etc.:

http://en.wikipedia.org/wiki/Smack



- James
-- 
James Morris
<jmorris@namei.org>

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-10-23  0:02     ` James Morris
@ 2013-10-23  1:03       ` Casey Schaufler
  0 siblings, 0 replies; 23+ messages in thread
From: Casey Schaufler @ 2013-10-23  1:03 UTC (permalink / raw)
  To: James Morris
  Cc: Kees Cook, linux-kernel, James Morris, linux-security-module,
	Casey Schaufler

On 10/22/2013 5:02 PM, James Morris wrote:
> On Thu, 17 Oct 2013, Casey Schaufler wrote:
>
>> On 10/17/2013 1:02 AM, James Morris wrote:
>>> This seems like a regression in terms of separating mechanism and policy.  
>>>
>>> We have several access control systems available (SELinux, at least) which 
>>> can implement this functionality with existing mechanisms using dynamic 
>>> policy.
>> They said the same thing about Smack.
>>
> Nope.  Smack separates mechanism and policy.  The argument then was 
> whether we need more than one such enhanced access control system.
>
> The issue now is that we do have several of them (SELinux, Smack, 
> AppArmor) which are policy-flexible, whether to regress back to adding 
> hard-coded security policies into the kernel.
>
>> The problem there is that you have to buy into the entirety of
>> SELinux to implement a small bit of behavior. You have to write
>> a policy that takes every aspect of system behavior into account
>> when all you care about is loading restrictions on modules.
> You always need to consider the behavior of the system as a whole when 
> designing security policies.

This is right thinking. It's just not common thinking.

> It's a major step backwards to hard-code a series of ad-hoc policies in 
> the kernel.  You still need to compose them somehow, and reason about the 
> security of the system as a whole.

It's not like we're talking about throwing out the legacy monolithic LSMs.
And let us not forget that Fedora is using SELinux and Yama. There's a
perception of value in independent security mechanisms used in combination.

>> The rationale is that lots of people doing little things is
>> likely to get us relevant security in a reasonable amount of time.
>> The existing LSMs reflect 20th century technologies and use cases.
>> They are fine for multi-user timesharing systems. We need to move
>> forward to support networked gaming, phones, tablets and toasters.
> You keep making these grand

Cool! Most people use other, less complimentary adjectives!

> assertions but never provide any detail, or 
> any kind of evidence to back them up.

There are simple reasons for that. Between Tizen and the stacking patch
the work on a real Application+Service+Resource security model and the
implementation thereof has gotten insufficient attention. I have been
emphasizing work on enabling technology over work on what needs to be
enabled. Kees' approach to security development on CromeOS is the example
I'll hold up for the wave of the future.

> Yet there are many, many examples 
> of how the current LSMs meet all of these needs in the 21st century, such 
> as Smack being adopted for Tizen, digital television etc.:

Smack in Tizen is an example of old school distribution packaging.
Tizen is very old school in its approach. It's working out pretty
well, but Tizen is hardly a major advance in the world of OS security.

If you look at Android, their (re/miss/ab)use of the UID mechanism and
reliance on the binder to wedge an application based security policy
on top of existing mechanisms it should be pretty obvious that they
would have been better suited with new security features than with
retrofitting to existing technology.

SEAndroid is taking a refreshing approach by putting the access controls
in the middleware and by doing so enabling an appropriate implementation
on the flask architecture. I would not say that SEAndroid qualifies as an
example of adopting an LSM.

> http://en.wikipedia.org/wiki/Smack
>
>
>
> - James


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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-10-03 21:36           ` Kees Cook
@ 2013-10-23  2:55             ` Lucas De Marchi
  0 siblings, 0 replies; 23+ messages in thread
From: Lucas De Marchi @ 2013-10-23  2:55 UTC (permalink / raw)
  To: Kees Cook
  Cc: Tetsuo Handa, Kees Cook, jmorris, lkml, James Morris, casey,
	linux-security-module, Rusty Russell

Hi Kees,

On Thu, Oct 3, 2013 at 6:36 PM, Kees Cook <kees@outflux.net> wrote:
> On Fri, Oct 04, 2013 at 06:31:42AM +0900, Tetsuo Handa wrote:
>> Kees Cook wrote:
>> > +static int modpin_load_module(struct file *file)
>> > +{
>> > +   struct dentry *module_root;
>> > +
>> > +   if (!file) {
>> > +           if (!modpin_enforced) {
>> > +                   report_load_module(NULL, "old-api-pinning-ignored");
>> > +                   return 0;
>> > +           }
>> > +
>> > +           report_load_module(NULL, "old-api-denied");
>> > +           return -EPERM;
>> > +   }
>> > +
>> > +   module_root = file->f_path.mnt->mnt_root;
>> > +
>> > +   /* First loaded module defines the root for all others. */
>> > +   spin_lock(&pinned_root_spinlock);
>> > +   if (!pinned_root) {
>> > +           pinned_root = dget(module_root);
>> > +           /*
>> > +            * Unlock now since it's only pinned_root we care about.
>> > +            * In the worst case, we will (correctly) report pinning
>> > +            * failures before we have announced that pinning is
>> > +            * enabled. This would be purely cosmetic.
>> > +            */
>> > +           spin_unlock(&pinned_root_spinlock);
>> > +           check_pinning_enforcement();
>> > +           report_load_module(&file->f_path, "pinned");
>> > +           return 0;
>> > +   }
>> > +   spin_unlock(&pinned_root_spinlock);
>>
>> Firstly loaded module is usually in initramfs whereas subsequently loaded
>> modules are usually on a hard disk partition.
>>
>> This module is not meant for PC servers, is it?
>
> This LSM is what Chrome OS uses for the module pinning logic. We do not use
> an initramfs. This LSM could also be used for devices booting entirely from
> CDROM or other R/O media.
>
> I'm open to improvements, obviously. I imagine things like delayed
> activation, where the initramfs triggers pinning in some way once it is
> done loading modules from its filesystem, etc. But since I don't have any
> real life examples of this, I'm writing the LSM as it currently is, used
> without an initramfs. :)

The way you put now as well as the code are at least different from
what it's written in the commit message.  I was expecting that this
modpin would allow module loading only from a trusted partition.
Instead we are allowing to load modules from the same partition of the
first module that has been loaded, if the root is trusted. Why? What's
the relation with the root partition being trusted and the partition
where the modules reside?  What's the guarantee that the first module
to load is any more trustable than the others?

Lucas De Marchi

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-10-17  0:37               ` Tetsuo Handa
@ 2013-10-26 13:51                 ` Tetsuo Handa
  2013-11-02 19:39                   ` Casey Schaufler
  0 siblings, 1 reply; 23+ messages in thread
From: Tetsuo Handa @ 2013-10-26 13:51 UTC (permalink / raw)
  To: james.l.morris, jmorris, keescook, casey
  Cc: linux-kernel, linux-security-module, rusty

Tetsuo Handa wrote:
> I would send another one which uses only security_file_alloc/free .

I sent it to James, Casey and Kees on "Fri, 18 Oct 2013 22:56:19 +0900" and
waiting for your response. How long are we expected to remain vulnerable due to
lack of multiple concurrent LSM support?

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

* Re: [PATCH] LSM: ModPin LSM for module loading restrictions
  2013-10-26 13:51                 ` Tetsuo Handa
@ 2013-11-02 19:39                   ` Casey Schaufler
  0 siblings, 0 replies; 23+ messages in thread
From: Casey Schaufler @ 2013-11-02 19:39 UTC (permalink / raw)
  To: Tetsuo Handa, james.l.morris, jmorris, keescook
  Cc: linux-kernel, linux-security-module, rusty

On 10/26/2013 6:51 AM, Tetsuo Handa wrote:
> Tetsuo Handa wrote:
>> I would send another one which uses only security_file_alloc/free .
> I sent it to James, Casey and Kees on "Fri, 18 Oct 2013 22:56:19 +0900" and
> waiting for your response. How long are we expected to remain vulnerable due to
> lack of multiple concurrent LSM support?

Having just spent a good chunk of the past year on the technical
issues, and having participated in the LSM development process since
its inception, I'd say there's at least a year before the dust settles.
Having a wad of code that works is one thing. Breaking it into chunks
that are both useful and small enough for the community to swallow is
another. Transforming a collection of clever hacks into an infrastructure
is a third. Once that's done we can deal with the naysayers.

Fortunately, we have a wad of code that works. Nobody seems to
think that taking that code as is is a great idea. Nobody has
this as their first priority, either. We're making progress, but
we know we need to be careful. I seriously doubt we'll get more
than one shot at it.


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

end of thread, other threads:[~2013-11-02 19:45 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-09-20 20:35 [PATCH] LSM: ModPin LSM for module loading restrictions Kees Cook
2013-09-24  1:24 ` James Morris
2013-09-24  1:28   ` James Morris
2013-09-24  1:45     ` Kees Cook
2013-10-03 20:55       ` Kees Cook
2013-10-03 21:31         ` Tetsuo Handa
2013-10-03 21:36           ` Kees Cook
2013-10-23  2:55             ` Lucas De Marchi
2013-10-16 15:18       ` Kees Cook
2013-10-16 20:47         ` Tetsuo Handa
2013-10-16 21:42           ` Casey Schaufler
2013-10-16 22:43             ` Kees Cook
2013-10-17  0:37               ` Tetsuo Handa
2013-10-26 13:51                 ` Tetsuo Handa
2013-11-02 19:39                   ` Casey Schaufler
2013-10-18  2:25               ` Casey Schaufler
2013-10-17  8:02 ` James Morris
2013-10-17 11:30   ` Jarkko Sakkinen
2013-10-17 21:00     ` Kees Cook
2013-10-17 17:26   ` Casey Schaufler
2013-10-17 21:09     ` Kees Cook
2013-10-23  0:02     ` James Morris
2013-10-23  1:03       ` Casey Schaufler

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).