summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/admin-guide/kernel-parameters.txt9
-rw-r--r--include/linux/security.h3
-rw-r--r--security/Kconfig11
-rw-r--r--security/Makefile2
-rw-r--r--security/lockdown/Kconfig46
-rw-r--r--security/lockdown/Makefile1
-rw-r--r--security/lockdown/lockdown.c169
7 files changed, 236 insertions, 5 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 138f6664b2e2..0f28350f1ee6 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2244,6 +2244,15 @@
2244 lockd.nlm_udpport=M [NFS] Assign UDP port. 2244 lockd.nlm_udpport=M [NFS] Assign UDP port.
2245 Format: <integer> 2245 Format: <integer>
2246 2246
2247 lockdown= [SECURITY]
2248 { integrity | confidentiality }
2249 Enable the kernel lockdown feature. If set to
2250 integrity, kernel features that allow userland to
2251 modify the running kernel are disabled. If set to
2252 confidentiality, kernel features that allow userland
2253 to extract confidential information from the kernel
2254 are also disabled.
2255
2247 locktorture.nreaders_stress= [KNL] 2256 locktorture.nreaders_stress= [KNL]
2248 Set the number of locking read-acquisition kthreads. 2257 Set the number of locking read-acquisition kthreads.
2249 Defaults to being automatically set based on the 2258 Defaults to being automatically set based on the
diff --git a/include/linux/security.h b/include/linux/security.h
index 04cf48fab15d..74787335d9ce 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -97,6 +97,9 @@ enum lsm_event {
97 * potentially a moving target. It is easy to misuse this information 97 * potentially a moving target. It is easy to misuse this information
98 * in a way that could break userspace. Please be careful not to do 98 * in a way that could break userspace. Please be careful not to do
99 * so. 99 * so.
100 *
101 * If you add to this, remember to extend lockdown_reasons in
102 * security/lockdown/lockdown.c.
100 */ 103 */
101enum lockdown_reason { 104enum lockdown_reason {
102 LOCKDOWN_NONE, 105 LOCKDOWN_NONE,
diff --git a/security/Kconfig b/security/Kconfig
index 466cc1f8ffed..7c62d446e209 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -237,6 +237,7 @@ source "security/apparmor/Kconfig"
237source "security/loadpin/Kconfig" 237source "security/loadpin/Kconfig"
238source "security/yama/Kconfig" 238source "security/yama/Kconfig"
239source "security/safesetid/Kconfig" 239source "security/safesetid/Kconfig"
240source "security/lockdown/Kconfig"
240 241
241source "security/integrity/Kconfig" 242source "security/integrity/Kconfig"
242 243
@@ -276,11 +277,11 @@ endchoice
276 277
277config LSM 278config LSM
278 string "Ordered list of enabled LSMs" 279 string "Ordered list of enabled LSMs"
279 default "yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor" if DEFAULT_SECURITY_SMACK 280 default "lockdown,yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor" if DEFAULT_SECURITY_SMACK
280 default "yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" if DEFAULT_SECURITY_APPARMOR 281 default "lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" if DEFAULT_SECURITY_APPARMOR
281 default "yama,loadpin,safesetid,integrity,tomoyo" if DEFAULT_SECURITY_TOMOYO 282 default "lockdown,yama,loadpin,safesetid,integrity,tomoyo" if DEFAULT_SECURITY_TOMOYO
282 default "yama,loadpin,safesetid,integrity" if DEFAULT_SECURITY_DAC 283 default "lockdown,yama,loadpin,safesetid,integrity" if DEFAULT_SECURITY_DAC
283 default "yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor" 284 default "lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor"
284 help 285 help
285 A comma-separated list of LSMs, in initialization order. 286 A comma-separated list of LSMs, in initialization order.
286 Any LSMs left off this list will be ignored. This can be 287 Any LSMs left off this list will be ignored. This can be
diff --git a/security/Makefile b/security/Makefile
index c598b904938f..be1dd9d2cb2f 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -11,6 +11,7 @@ subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor
11subdir-$(CONFIG_SECURITY_YAMA) += yama 11subdir-$(CONFIG_SECURITY_YAMA) += yama
12subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin 12subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin
13subdir-$(CONFIG_SECURITY_SAFESETID) += safesetid 13subdir-$(CONFIG_SECURITY_SAFESETID) += safesetid
14subdir-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown
14 15
15# always enable default capabilities 16# always enable default capabilities
16obj-y += commoncap.o 17obj-y += commoncap.o
@@ -27,6 +28,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/
27obj-$(CONFIG_SECURITY_YAMA) += yama/ 28obj-$(CONFIG_SECURITY_YAMA) += yama/
28obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ 29obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/
29obj-$(CONFIG_SECURITY_SAFESETID) += safesetid/ 30obj-$(CONFIG_SECURITY_SAFESETID) += safesetid/
31obj-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown/
30obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o 32obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
31 33
32# Object integrity file lists 34# Object integrity file lists
diff --git a/security/lockdown/Kconfig b/security/lockdown/Kconfig
new file mode 100644
index 000000000000..7a1d213227a4
--- /dev/null
+++ b/security/lockdown/Kconfig
@@ -0,0 +1,46 @@
1config SECURITY_LOCKDOWN_LSM
2 bool "Basic module for enforcing kernel lockdown"
3 depends on SECURITY
4 help
5 Build support for an LSM that enforces a coarse kernel lockdown
6 behaviour.
7
8config SECURITY_LOCKDOWN_LSM_EARLY
9 bool "Enable lockdown LSM early in init"
10 depends on SECURITY_LOCKDOWN_LSM
11 help
12 Enable the lockdown LSM early in boot. This is necessary in order
13 to ensure that lockdown enforcement can be carried out on kernel
14 boot parameters that are otherwise parsed before the security
15 subsystem is fully initialised. If enabled, lockdown will
16 unconditionally be called before any other LSMs.
17
18choice
19 prompt "Kernel default lockdown mode"
20 default LOCK_DOWN_KERNEL_FORCE_NONE
21 depends on SECURITY_LOCKDOWN_LSM
22 help
23 The kernel can be configured to default to differing levels of
24 lockdown.
25
26config LOCK_DOWN_KERNEL_FORCE_NONE
27 bool "None"
28 help
29 No lockdown functionality is enabled by default. Lockdown may be
30 enabled via the kernel commandline or /sys/kernel/security/lockdown.
31
32config LOCK_DOWN_KERNEL_FORCE_INTEGRITY
33 bool "Integrity"
34 help
35 The kernel runs in integrity mode by default. Features that allow
36 the kernel to be modified at runtime are disabled.
37
38config LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY
39 bool "Confidentiality"
40 help
41 The kernel runs in confidentiality mode by default. Features that
42 allow the kernel to be modified at runtime or that permit userland
43 code to read confidential material held inside the kernel are
44 disabled.
45
46endchoice
diff --git a/security/lockdown/Makefile b/security/lockdown/Makefile
new file mode 100644
index 000000000000..e3634b9017e7
--- /dev/null
+++ b/security/lockdown/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown.o
diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
new file mode 100644
index 000000000000..7172ad75496b
--- /dev/null
+++ b/security/lockdown/lockdown.c
@@ -0,0 +1,169 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Lock down the kernel
3 *
4 * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12
13#include <linux/security.h>
14#include <linux/export.h>
15#include <linux/lsm_hooks.h>
16
17static enum lockdown_reason kernel_locked_down;
18
19static char *lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = {
20 [LOCKDOWN_NONE] = "none",
21 [LOCKDOWN_INTEGRITY_MAX] = "integrity",
22 [LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
23};
24
25static enum lockdown_reason lockdown_levels[] = {LOCKDOWN_NONE,
26 LOCKDOWN_INTEGRITY_MAX,
27 LOCKDOWN_CONFIDENTIALITY_MAX};
28
29/*
30 * Put the kernel into lock-down mode.
31 */
32static int lock_kernel_down(const char *where, enum lockdown_reason level)
33{
34 if (kernel_locked_down >= level)
35 return -EPERM;
36
37 kernel_locked_down = level;
38 pr_notice("Kernel is locked down from %s; see man kernel_lockdown.7\n",
39 where);
40 return 0;
41}
42
43static int __init lockdown_param(char *level)
44{
45 if (!level)
46 return -EINVAL;
47
48 if (strcmp(level, "integrity") == 0)
49 lock_kernel_down("command line", LOCKDOWN_INTEGRITY_MAX);
50 else if (strcmp(level, "confidentiality") == 0)
51 lock_kernel_down("command line", LOCKDOWN_CONFIDENTIALITY_MAX);
52 else
53 return -EINVAL;
54
55 return 0;
56}
57
58early_param("lockdown", lockdown_param);
59
60/**
61 * lockdown_is_locked_down - Find out if the kernel is locked down
62 * @what: Tag to use in notice generated if lockdown is in effect
63 */
64static int lockdown_is_locked_down(enum lockdown_reason what)
65{
66 if (kernel_locked_down >= what) {
67 if (lockdown_reasons[what])
68 pr_notice("Lockdown: %s is restricted; see man kernel_lockdown.7\n",
69 lockdown_reasons[what]);
70 return -EPERM;
71 }
72
73 return 0;
74}
75
76static struct security_hook_list lockdown_hooks[] __lsm_ro_after_init = {
77 LSM_HOOK_INIT(locked_down, lockdown_is_locked_down),
78};
79
80static int __init lockdown_lsm_init(void)
81{
82#if defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY)
83 lock_kernel_down("Kernel configuration", LOCKDOWN_INTEGRITY_MAX);
84#elif defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY)
85 lock_kernel_down("Kernel configuration", LOCKDOWN_CONFIDENTIALITY_MAX);
86#endif
87 security_add_hooks(lockdown_hooks, ARRAY_SIZE(lockdown_hooks),
88 "lockdown");
89 return 0;
90}
91
92static ssize_t lockdown_read(struct file *filp, char __user *buf, size_t count,
93 loff_t *ppos)
94{
95 char temp[80];
96 int i, offset = 0;
97
98 for (i = 0; i < ARRAY_SIZE(lockdown_levels); i++) {
99 enum lockdown_reason level = lockdown_levels[i];
100
101 if (lockdown_reasons[level]) {
102 const char *label = lockdown_reasons[level];
103
104 if (kernel_locked_down == level)
105 offset += sprintf(temp+offset, "[%s] ", label);
106 else
107 offset += sprintf(temp+offset, "%s ", label);
108 }
109 }
110
111 /* Convert the last space to a newline if needed. */
112 if (offset > 0)
113 temp[offset-1] = '\n';
114
115 return simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
116}
117
118static ssize_t lockdown_write(struct file *file, const char __user *buf,
119 size_t n, loff_t *ppos)
120{
121 char *state;
122 int i, len, err = -EINVAL;
123
124 state = memdup_user_nul(buf, n);
125 if (IS_ERR(state))
126 return PTR_ERR(state);
127
128 len = strlen(state);
129 if (len && state[len-1] == '\n') {
130 state[len-1] = '\0';
131 len--;
132 }
133
134 for (i = 0; i < ARRAY_SIZE(lockdown_levels); i++) {
135 enum lockdown_reason level = lockdown_levels[i];
136 const char *label = lockdown_reasons[level];
137
138 if (label && !strcmp(state, label))
139 err = lock_kernel_down("securityfs", level);
140 }
141
142 kfree(state);
143 return err ? err : n;
144}
145
146static const struct file_operations lockdown_ops = {
147 .read = lockdown_read,
148 .write = lockdown_write,
149};
150
151static int __init lockdown_secfs_init(void)
152{
153 struct dentry *dentry;
154
155 dentry = securityfs_create_file("lockdown", 0600, NULL, NULL,
156 &lockdown_ops);
157 return PTR_ERR_OR_ZERO(dentry);
158}
159
160core_initcall(lockdown_secfs_init);
161
162#ifdef CONFIG_SECURITY_LOCKDOWN_LSM_EARLY
163DEFINE_EARLY_LSM(lockdown) = {
164#else
165DEFINE_LSM(lockdown) = {
166#endif
167 .name = "lockdown",
168 .init = lockdown_lsm_init,
169};