diff mbox

[v6,1/3] LSM: Add /sys/kernel/security/lsm

Message ID 511ae6ef-9dc1-6e43-4a49-4055727dc099@schaufler-ca.com
State New
Headers show

Commit Message

Casey Schaufler Oct. 27, 2016, 12:01 a.m. UTC
Subject: [PATCH v6 1/3] LSM: Add /sys/kernel/security/lsm

I got tired of having to find indirect ways to 
determine what security modules are active on a system.
I have added /sys/kernel/security/lsm, which contains a
comma separated list of the active security modules. No
more groping around in /proc/filesystems, which won't
help if the module doesn't support its own filesystem.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>

---
 Documentation/security/LSM.txt |  7 +++++++
 include/linux/lsm_hooks.h      | 12 ++++--------
 security/apparmor/lsm.c        |  3 ++-
 security/commoncap.c           |  3 ++-
 security/inode.c               | 26 ++++++++++++++++++++++++--
 security/loadpin/loadpin.c     |  2 +-
 security/security.c            | 38 ++++++++++++++++++++++++++++++++++++++
 security/selinux/hooks.c       |  2 +-
 security/smack/smack_lsm.c     |  2 +-
 security/tomoyo/tomoyo.c       |  2 +-
 security/yama/yama_lsm.c       |  2 +-
 11 files changed, 82 insertions(+), 17 deletions(-)

Comments

Tetsuo Handa Nov. 1, 2016, 12:53 p.m. UTC | #1
Casey Schaufler wrote:
> diff --git a/security/security.c b/security/security.c
> index f825304..f0a802ee 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -32,6 +32,7 @@
>  /* Maximum number of letters for an LSM name string */
>  #define SECURITY_NAME_MAX	10
>  
> +char *lsm_names;
>  /* Boot-time LSM user choice */
>  static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
>  	CONFIG_DEFAULT_SECURITY;
> @@ -78,6 +79,22 @@ static int __init choose_lsm(char *str)
>  }
>  __setup("security=", choose_lsm);
>  
> +static int lsm_append(char *new, char **result)
> +{
> +	char *cp;
> +
> +	if (*result == NULL) {
> +		*result = kstrdup(new, GFP_KERNEL);
> +	} else {
> +		cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
> +		if (cp == NULL)
> +			return -ENOMEM;
> +		kfree(*result);
> +		*result = cp;
> +	}
> +	return 0;
> +}
> +

I didn't check past discussion, but how do you handle security_delete_hooks()
case (I mean, "selinux" will remain there when reading /sys/kernel/security/lsm
even after it is disabled at runtime)? I think holding module name as one of
"union security_list_options" members will avoid memory allocation handling
and simplify things.
--
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
Casey Schaufler Nov. 1, 2016, 5:25 p.m. UTC | #2
On 11/1/2016 5:53 AM, Tetsuo Handa wrote:
> Casey Schaufler wrote:
>> diff --git a/security/security.c b/security/security.c
>> index f825304..f0a802ee 100644
>> --- a/security/security.c
>> +++ b/security/security.c
>> @@ -32,6 +32,7 @@
>>  /* Maximum number of letters for an LSM name string */
>>  #define SECURITY_NAME_MAX	10
>>  
>> +char *lsm_names;
>>  /* Boot-time LSM user choice */
>>  static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
>>  	CONFIG_DEFAULT_SECURITY;
>> @@ -78,6 +79,22 @@ static int __init choose_lsm(char *str)
>>  }
>>  __setup("security=", choose_lsm);
>>  
>> +static int lsm_append(char *new, char **result)
>> +{
>> +	char *cp;
>> +
>> +	if (*result == NULL) {
>> +		*result = kstrdup(new, GFP_KERNEL);
>> +	} else {
>> +		cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
>> +		if (cp == NULL)
>> +			return -ENOMEM;
>> +		kfree(*result);
>> +		*result = cp;
>> +	}
>> +	return 0;
>> +}
>> +
> I didn't check past discussion, but how do you handle security_delete_hooks()
> case (I mean, "selinux" will remain there when reading /sys/kernel/security/lsm
> even after it is disabled at runtime)?

Paul Moore says that SELinux is going to remove the ability
to delete itself in the near future. Since that's the only
module that allows deletion I don't see that it's an issue.

> I think holding module name as one of
> "union security_list_options" members will avoid memory allocation handling
> and simplify things.

I don't see how that would simplify things, and the memory
allocation handling here is pretty basic.

> --
> 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
>

--
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
Tetsuo Handa Nov. 4, 2016, 2:11 p.m. UTC | #3
Casey Schaufler wrote:
> On 11/1/2016 5:53 AM, Tetsuo Handa wrote:
> > I didn't check past discussion, but how do you handle security_delete_hooks()
> > case (I mean, "selinux" will remain there when reading /sys/kernel/security/lsm
> > even after it is disabled at runtime)?
> 
> Paul Moore says that SELinux is going to remove the ability
> to delete itself in the near future. Since that's the only
> module that allows deletion I don't see that it's an issue.

OK.

> 
> > I think holding module name as one of
> > "union security_list_options" members will avoid memory allocation handling
> > and simplify things.
> 
> I don't see how that would simplify things, and the memory
> allocation handling here is pretty basic.

I expected we can use simple_read_from_buffer() from iteration loop,
but I found it does not work like I want. So, it did not simplify things.
--
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
diff mbox

Patch

diff --git a/Documentation/security/LSM.txt b/Documentation/security/LSM.txt
index 3db7e67..c2683f2 100644
--- a/Documentation/security/LSM.txt
+++ b/Documentation/security/LSM.txt
@@ -22,6 +22,13 @@  system, building their checks on top of the defined capability hooks.
 For more details on capabilities, see capabilities(7) in the Linux
 man-pages project.
 
+A list of the active security modules can be found by reading
+/sys/kernel/security/lsm. This is a comma separated list, and
+will always include the capability module. The list reflects the
+order in which checks are made. The capability module will always
+be first, followed by any "minor" modules (e.g. Yama) and then
+the one "major" module (e.g. SELinux) if there is one configured.
+
 Based on https://lkml.org/lkml/2007/10/26/215,
 a new LSM is accepted into the kernel when its intent (a description of
 what it tries to protect against and in what cases one would expect to
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 558adfa..132650d 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1876,6 +1876,7 @@  struct security_hook_list {
 	struct list_head		list;
 	struct list_head		*head;
 	union security_list_options	hook;
+	char				*lsm;
 };
 
 /*
@@ -1888,15 +1889,10 @@  struct security_hook_list {
 	{ .head = &security_hook_heads.HEAD, .hook = { .HEAD = HOOK } }
 
 extern struct security_hook_heads security_hook_heads;
+extern char *lsm_names;
 
-static inline void security_add_hooks(struct security_hook_list *hooks,
-				      int count)
-{
-	int i;
-
-	for (i = 0; i < count; i++)
-		list_add_tail_rcu(&hooks[i].list, hooks[i].head);
-}
+extern void security_add_hooks(struct security_hook_list *hooks, int count,
+				char *lsm);
 
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
 /*
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 41b8cb1..1d4843d 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -886,7 +886,8 @@  static int __init apparmor_init(void)
 		aa_free_root_ns();
 		goto alloc_out;
 	}
-	security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks));
+	security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks),
+				"apparmor");
 
 	/* Report that AppArmor successfully initialized */
 	apparmor_initialized = 1;
diff --git a/security/commoncap.c b/security/commoncap.c
index 8df676f..6d4d586 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -1093,7 +1093,8 @@  struct security_hook_list capability_hooks[] = {
 
 void __init capability_add_hooks(void)
 {
-	security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks));
+	security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks),
+				"capability");
 }
 
 #endif /* CONFIG_SECURITY */
diff --git a/security/inode.c b/security/inode.c
index c83db05..546e786 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -20,6 +20,7 @@ 
 #include <linux/init.h>
 #include <linux/namei.h>
 #include <linux/security.h>
+#include <linux/lsm_hooks.h>
 #include <linux/magic.h>
 
 static struct vfsmount *mount;
@@ -204,6 +205,21 @@  void securityfs_remove(struct dentry *dentry)
 }
 EXPORT_SYMBOL_GPL(securityfs_remove);
 
+#ifdef CONFIG_SECURITY
+static struct dentry *lsm_dentry;
+static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
+			loff_t *ppos)
+{
+	return simple_read_from_buffer(buf, count, ppos, lsm_names,
+		strlen(lsm_names));
+}
+
+static const struct file_operations lsm_ops = {
+	.read = lsm_read,
+	.llseek = generic_file_llseek,
+};
+#endif
+
 static int __init securityfs_init(void)
 {
 	int retval;
@@ -213,9 +229,15 @@  static int __init securityfs_init(void)
 		return retval;
 
 	retval = register_filesystem(&fs_type);
-	if (retval)
+	if (retval) {
 		sysfs_remove_mount_point(kernel_kobj, "security");
-	return retval;
+		return retval;
+	}
+#ifdef CONFIG_SECURITY
+	lsm_dentry = securityfs_create_file("lsm", S_IRUGO, NULL, NULL,
+						&lsm_ops);
+#endif
+	return 0;
 }
 
 core_initcall(securityfs_init);
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
index 89a46f1..1d82eae 100644
--- a/security/loadpin/loadpin.c
+++ b/security/loadpin/loadpin.c
@@ -182,7 +182,7 @@  static struct security_hook_list loadpin_hooks[] = {
 void __init loadpin_add_hooks(void)
 {
 	pr_info("ready to pin (currently %sabled)", enabled ? "en" : "dis");
-	security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks));
+	security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
 }
 
 /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
diff --git a/security/security.c b/security/security.c
index f825304..f0a802ee 100644
--- a/security/security.c
+++ b/security/security.c
@@ -32,6 +32,7 @@ 
 /* Maximum number of letters for an LSM name string */
 #define SECURITY_NAME_MAX	10
 
+char *lsm_names;
 /* Boot-time LSM user choice */
 static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
 	CONFIG_DEFAULT_SECURITY;
@@ -78,6 +79,22 @@  static int __init choose_lsm(char *str)
 }
 __setup("security=", choose_lsm);
 
+static int lsm_append(char *new, char **result)
+{
+	char *cp;
+
+	if (*result == NULL) {
+		*result = kstrdup(new, GFP_KERNEL);
+	} else {
+		cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
+		if (cp == NULL)
+			return -ENOMEM;
+		kfree(*result);
+		*result = cp;
+	}
+	return 0;
+}
+
 /**
  * security_module_enable - Load given security module on boot ?
  * @module: the name of the module
@@ -97,6 +114,27 @@  int __init security_module_enable(const char *module)
 	return !strcmp(module, chosen_lsm);
 }
 
+/**
+ * security_add_hooks - Add a modules hooks to the hook lists.
+ * @hooks: the hooks to add
+ * @count: the number of hooks to add
+ * @lsm: the name of the security module
+ *
+ * Each LSM has to register its hooks with the infrastructure.
+ */
+void __init security_add_hooks(struct security_hook_list *hooks, int count,
+				char *lsm)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		hooks[i].lsm = lsm;
+		list_add_tail_rcu(&hooks[i].list, hooks[i].head);
+	}
+	if (lsm_append(lsm, &lsm_names) < 0)
+		panic("%s - Cannot get early memory.\n", __func__);
+}
+
 /*
  * Hook list operation macros.
  *
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 09fd610..0d039fc 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6320,7 +6320,7 @@  static __init int selinux_init(void)
 					    0, SLAB_PANIC, NULL);
 	avc_init();
 
-	security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
+	security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");
 
 	if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
 		panic("SELinux: Unable to register AVC netcache callback\n");
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 1cb0602..7c12198 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4832,7 +4832,7 @@  static __init int smack_init(void)
 	/*
 	 * Register with LSM
 	 */
-	security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks));
+	security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack");
 
 	return 0;
 }
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index 75c9987..edc52d6 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -542,7 +542,7 @@  static int __init tomoyo_init(void)
 	if (!security_module_enable("tomoyo"))
 		return 0;
 	/* register ourselves with the security framework */
-	security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks));
+	security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), "tomoyo");
 	printk(KERN_INFO "TOMOYO Linux initialized\n");
 	cred->security = &tomoyo_kernel_domain;
 	tomoyo_mm_init();
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 0309f21..f8ee60e 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -471,6 +471,6 @@  static inline void yama_init_sysctl(void) { }
 void __init yama_add_hooks(void)
 {
 	pr_info("Yama: becoming mindful.\n");
-	security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks));
+	security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks), "yama");
 	yama_init_sysctl();
 }