209 lines
5.9 KiB
Diff
209 lines
5.9 KiB
Diff
From: Matthew Garrett <mjg59@srcf.ucam.org>
|
|
Date: Fri, 9 Aug 2013 17:58:15 -0400
|
|
Subject: [01/18] Add BSD-style securelevel support
|
|
Origin: https://github.com/mjg59/linux/commit/058b8ddfe86dc90268f6dbe0ffed29ec46f1fafa
|
|
|
|
Provide a coarse-grained runtime configuration option for restricting
|
|
userspace's ability to modify the running kernel.
|
|
|
|
Signed-off-by: Matthew Garrett <mjg59@srcf.ucam.org>
|
|
---
|
|
Documentation/security/securelevel.txt | 23 +++++++
|
|
include/linux/security.h | 8 +++
|
|
security/Kconfig | 8 +++
|
|
security/Makefile | 1 +
|
|
security/securelevel.c | 116 +++++++++++++++++++++++++++++++++
|
|
5 files changed, 156 insertions(+)
|
|
create mode 100644 Documentation/security/securelevel.txt
|
|
create mode 100644 security/securelevel.c
|
|
|
|
--- /dev/null
|
|
+++ b/Documentation/security/securelevel.txt
|
|
@@ -0,0 +1,23 @@
|
|
+Linux securelevel interface
|
|
+---------------------------
|
|
+
|
|
+The Linux securelevel interface (inspired by the BSD securelevel interface)
|
|
+is a runtime mechanism for configuring coarse-grained kernel-level security
|
|
+restrictions. It provides a runtime configuration variable at
|
|
+/sys/kernel/security/securelevel which can be written to by root. The
|
|
+following values are supported:
|
|
+
|
|
+-1: Permanently insecure mode. This level is equivalent to level 0, but once
|
|
+ set cannot be changed.
|
|
+
|
|
+0: Insecure mode (default). This level imposes no additional kernel
|
|
+ restrictions.
|
|
+
|
|
+1: Secure mode. If set, userspace will be unable to perform direct access
|
|
+ to PCI devices, port IO access, access system memory directly via
|
|
+ /dev/mem and /dev/kmem, perform kexec_load(), use the userspace
|
|
+ software suspend mechanism, insert new ACPI code at runtime via the
|
|
+ custom_method interface or modify CPU MSRs (on x86). Certain drivers
|
|
+ may also limit additional interfaces.
|
|
+
|
|
+Once the securelevel value is increased, it may not be decreased.
|
|
--- a/include/linux/security.h
|
|
+++ b/include/linux/security.h
|
|
@@ -1589,6 +1589,14 @@ static inline void security_audit_rule_f
|
|
#endif /* CONFIG_SECURITY */
|
|
#endif /* CONFIG_AUDIT */
|
|
|
|
+#ifdef CONFIG_SECURITY_SECURELEVEL
|
|
+extern int get_securelevel(void);
|
|
+extern int set_securelevel(int new_securelevel);
|
|
+#else
|
|
+static inline int get_securelevel(void) { return 0; }
|
|
+static inline int set_securelevel(int new_securelevel) { return 0; }
|
|
+#endif /* CONFIG_SECURELEVEL */
|
|
+
|
|
#ifdef CONFIG_SECURITYFS
|
|
|
|
extern struct dentry *securityfs_create_file(const char *name, umode_t mode,
|
|
--- a/security/Kconfig
|
|
+++ b/security/Kconfig
|
|
@@ -93,6 +93,14 @@ config SECURITY_PATH
|
|
implement pathname based access controls.
|
|
If you are unsure how to answer this question, answer N.
|
|
|
|
+config SECURITY_SECURELEVEL
|
|
+ bool "Securelevel kernel restriction interface"
|
|
+ depends on SECURITY
|
|
+ help
|
|
+ This enables support for adding a set of additional kernel security
|
|
+ restrictions at runtime. See Documentation/security/securelevel.txt
|
|
+ for further information.
|
|
+
|
|
config INTEL_TXT
|
|
bool "Enable Intel(R) Trusted Execution Technology (Intel(R) TXT)"
|
|
depends on HAVE_INTEL_TXT
|
|
--- a/security/Makefile
|
|
+++ b/security/Makefile
|
|
@@ -16,6 +16,7 @@ obj-$(CONFIG_MMU) += min_addr.o
|
|
# Object file lists
|
|
obj-$(CONFIG_SECURITY) += security.o
|
|
obj-$(CONFIG_SECURITYFS) += inode.o
|
|
+obj-$(CONFIG_SECURITY_SECURELEVEL) += securelevel.o
|
|
obj-$(CONFIG_SECURITY_SELINUX) += selinux/
|
|
obj-$(CONFIG_SECURITY_SMACK) += smack/
|
|
obj-$(CONFIG_AUDIT) += lsm_audit.o
|
|
--- /dev/null
|
|
+++ b/security/securelevel.c
|
|
@@ -0,0 +1,116 @@
|
|
+/*
|
|
+ * securelevel.c - support for generic kernel lockdown
|
|
+ *
|
|
+ * Copyright Nebula, Inc <mjg59@srcf.ucam.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
+ * published by the Free Software Foundation.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/fs.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/security.h>
|
|
+#include <linux/uaccess.h>
|
|
+
|
|
+static int securelevel;
|
|
+
|
|
+static DEFINE_SPINLOCK(securelevel_lock);
|
|
+
|
|
+#define MAX_SECURELEVEL 1
|
|
+
|
|
+int get_securelevel(void)
|
|
+{
|
|
+ return securelevel;
|
|
+}
|
|
+EXPORT_SYMBOL(get_securelevel);
|
|
+
|
|
+int set_securelevel(int new_securelevel)
|
|
+{
|
|
+ int ret = 0;
|
|
+
|
|
+ spin_lock(&securelevel_lock);
|
|
+
|
|
+ if ((securelevel == -1) || (new_securelevel < securelevel) ||
|
|
+ (new_securelevel > MAX_SECURELEVEL)) {
|
|
+ ret = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ securelevel = new_securelevel;
|
|
+out:
|
|
+ spin_unlock(&securelevel_lock);
|
|
+ return ret;
|
|
+}
|
|
+EXPORT_SYMBOL(set_securelevel);
|
|
+
|
|
+static ssize_t securelevel_read(struct file *filp, char __user *buf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ char tmpbuf[12];
|
|
+ ssize_t length;
|
|
+
|
|
+ length = scnprintf(tmpbuf, sizeof(tmpbuf), "%d", securelevel);
|
|
+ return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
|
|
+}
|
|
+
|
|
+static ssize_t securelevel_write(struct file *file, const char __user *buf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ char *page = NULL;
|
|
+ ssize_t length;
|
|
+ int new_securelevel;
|
|
+
|
|
+ length = -ENOMEM;
|
|
+ if (count >= PAGE_SIZE)
|
|
+ goto out;
|
|
+
|
|
+ length = -EINVAL;
|
|
+ if (*ppos != 0)
|
|
+ goto out;
|
|
+
|
|
+ length = -ENOMEM;
|
|
+ page = (char *)get_zeroed_page(GFP_KERNEL);
|
|
+ if (!page)
|
|
+ goto out;
|
|
+
|
|
+ length = -EFAULT;
|
|
+ if (copy_from_user(page, buf, count))
|
|
+ goto out;
|
|
+
|
|
+ length = -EINVAL;
|
|
+ if (sscanf(page, "%d", &new_securelevel) != 1)
|
|
+ goto out;
|
|
+
|
|
+ length = set_securelevel(new_securelevel);
|
|
+ if (length)
|
|
+ goto out;
|
|
+
|
|
+ length = count;
|
|
+out:
|
|
+ free_page((unsigned long) page);
|
|
+ return length;
|
|
+}
|
|
+
|
|
+static const struct file_operations securelevel_fops = {
|
|
+ .read = securelevel_read,
|
|
+ .write = securelevel_write,
|
|
+ .llseek = generic_file_llseek,
|
|
+};
|
|
+
|
|
+static __init int setup_securelevel(void)
|
|
+{
|
|
+ struct dentry *securelevel_file;
|
|
+
|
|
+ securelevel_file = securityfs_create_file("securelevel",
|
|
+ S_IWUSR | S_IRUGO,
|
|
+ NULL, NULL,
|
|
+ &securelevel_fops);
|
|
+
|
|
+ if (IS_ERR(securelevel_file))
|
|
+ return PTR_ERR(securelevel_file);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+late_initcall(setup_securelevel);
|