hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/security/loadpin/loadpin.c
....@@ -1,26 +1,20 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Module and Firmware Pinning Security Module
34 *
45 * Copyright 2011-2016 Google Inc.
56 *
67 * Author: Kees Cook <keescook@chromium.org>
7
- *
8
- * This software is licensed under the terms of the GNU General Public
9
- * License version 2, as published by the Free Software Foundation, and
10
- * may be copied, distributed, and modified under those terms.
11
- *
12
- * This program is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- * GNU General Public License for more details.
168 */
179
1810 #define pr_fmt(fmt) "LoadPin: " fmt
1911
2012 #include <linux/module.h>
2113 #include <linux/fs.h>
14
+#include <linux/kernel_read_file.h>
2215 #include <linux/lsm_hooks.h>
2316 #include <linux/mount.h>
17
+#include <linux/blkdev.h>
2418 #include <linux/path.h>
2519 #include <linux/sched.h> /* current */
2620 #include <linux/string_helpers.h>
....@@ -44,13 +38,13 @@
4438 kfree(pathname);
4539 }
4640
47
-static int enabled = IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENABLED);
41
+static int enforce = IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENFORCE);
42
+static char *exclude_read_files[READING_MAX_ID];
43
+static int ignore_read_file_id[READING_MAX_ID] __ro_after_init;
4844 static struct super_block *pinned_root;
4945 static DEFINE_SPINLOCK(pinned_root_spinlock);
5046
5147 #ifdef CONFIG_SYSCTL
52
-static int zero;
53
-static int one = 1;
5448
5549 static struct ctl_path loadpin_sysctl_path[] = {
5650 { .procname = "kernel", },
....@@ -60,13 +54,13 @@
6054
6155 static struct ctl_table loadpin_sysctl_table[] = {
6256 {
63
- .procname = "enabled",
64
- .data = &enabled,
57
+ .procname = "enforce",
58
+ .data = &enforce,
6559 .maxlen = sizeof(int),
6660 .mode = 0644,
6761 .proc_handler = proc_dointvec_minmax,
68
- .extra1 = &zero,
69
- .extra2 = &one,
62
+ .extra1 = SYSCTL_ZERO,
63
+ .extra2 = SYSCTL_ONE,
7064 },
7165 { }
7266 };
....@@ -84,8 +78,11 @@
8478 * device, allow sysctl to change modes for testing.
8579 */
8680 if (mnt_sb->s_bdev) {
81
+ char bdev[BDEVNAME_SIZE];
82
+
8783 ro = bdev_read_only(mnt_sb->s_bdev);
88
- pr_info("dev(%u,%u): %s\n",
84
+ bdevname(mnt_sb->s_bdev, bdev);
85
+ pr_info("%s (%u:%u): %s\n", bdev,
8986 MAJOR(mnt_sb->s_bdev->bd_dev),
9087 MINOR(mnt_sb->s_bdev->bd_dev),
9188 ro ? "read-only" : "writable");
....@@ -97,7 +94,7 @@
9794 loadpin_sysctl_table))
9895 pr_notice("sysctl registration failed!\n");
9996 else
100
- pr_info("load pinning can be disabled.\n");
97
+ pr_info("enforcement can be disabled.\n");
10198 } else
10299 pr_info("load pinning engaged.\n");
103100 }
....@@ -121,14 +118,31 @@
121118 }
122119 }
123120
124
-static int loadpin_read_file(struct file *file, enum kernel_read_file_id id)
121
+static int loadpin_read_file(struct file *file, enum kernel_read_file_id id,
122
+ bool contents)
125123 {
126124 struct super_block *load_root;
127125 const char *origin = kernel_read_file_id_str(id);
128126
127
+ /*
128
+ * If we will not know that we'll be seeing the full contents
129
+ * then we cannot trust a load will be complete and unchanged
130
+ * off disk. Treat all contents=false hooks as if there were
131
+ * no associated file struct.
132
+ */
133
+ if (!contents)
134
+ file = NULL;
135
+
136
+ /* If the file id is excluded, ignore the pinning. */
137
+ if ((unsigned int)id < ARRAY_SIZE(ignore_read_file_id) &&
138
+ ignore_read_file_id[id]) {
139
+ report_load(origin, file, "pinning-excluded");
140
+ return 0;
141
+ }
142
+
129143 /* This handles the older init_module API that has a NULL file. */
130144 if (!file) {
131
- if (!enabled) {
145
+ if (!enforce) {
132146 report_load(origin, NULL, "old-api-pinning-ignored");
133147 return 0;
134148 }
....@@ -151,7 +165,7 @@
151165 * Unlock now since it's only pinned_root we care about.
152166 * In the worst case, we will (correctly) report pinning
153167 * failures before we have announced that pinning is
154
- * enabled. This would be purely cosmetic.
168
+ * enforcing. This would be purely cosmetic.
155169 */
156170 spin_unlock(&pinned_root_spinlock);
157171 check_pinning_enforcement(pinned_root);
....@@ -161,7 +175,7 @@
161175 }
162176
163177 if (IS_ERR_OR_NULL(pinned_root) || load_root != pinned_root) {
164
- if (unlikely(!enabled)) {
178
+ if (unlikely(!enforce)) {
165179 report_load(origin, file, "pinning-ignored");
166180 return 0;
167181 }
....@@ -173,9 +187,9 @@
173187 return 0;
174188 }
175189
176
-static int loadpin_load_data(enum kernel_load_data_id id)
190
+static int loadpin_load_data(enum kernel_load_data_id id, bool contents)
177191 {
178
- return loadpin_read_file(NULL, (enum kernel_read_file_id) id);
192
+ return loadpin_read_file(NULL, (enum kernel_read_file_id) id, contents);
179193 }
180194
181195 static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = {
....@@ -184,12 +198,58 @@
184198 LSM_HOOK_INIT(kernel_load_data, loadpin_load_data),
185199 };
186200
187
-void __init loadpin_add_hooks(void)
201
+static void __init parse_exclude(void)
188202 {
189
- pr_info("ready to pin (currently %sabled)", enabled ? "en" : "dis");
190
- security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
203
+ int i, j;
204
+ char *cur;
205
+
206
+ /*
207
+ * Make sure all the arrays stay within expected sizes. This
208
+ * is slightly weird because kernel_read_file_str[] includes
209
+ * READING_MAX_ID, which isn't actually meaningful here.
210
+ */
211
+ BUILD_BUG_ON(ARRAY_SIZE(exclude_read_files) !=
212
+ ARRAY_SIZE(ignore_read_file_id));
213
+ BUILD_BUG_ON(ARRAY_SIZE(kernel_read_file_str) <
214
+ ARRAY_SIZE(ignore_read_file_id));
215
+
216
+ for (i = 0; i < ARRAY_SIZE(exclude_read_files); i++) {
217
+ cur = exclude_read_files[i];
218
+ if (!cur)
219
+ break;
220
+ if (*cur == '\0')
221
+ continue;
222
+
223
+ for (j = 0; j < ARRAY_SIZE(ignore_read_file_id); j++) {
224
+ if (strcmp(cur, kernel_read_file_str[j]) == 0) {
225
+ pr_info("excluding: %s\n",
226
+ kernel_read_file_str[j]);
227
+ ignore_read_file_id[j] = 1;
228
+ /*
229
+ * Can not break, because one read_file_str
230
+ * may map to more than on read_file_id.
231
+ */
232
+ }
233
+ }
234
+ }
191235 }
192236
237
+static int __init loadpin_init(void)
238
+{
239
+ pr_info("ready to pin (currently %senforcing)\n",
240
+ enforce ? "" : "not ");
241
+ parse_exclude();
242
+ security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
243
+ return 0;
244
+}
245
+
246
+DEFINE_LSM(loadpin) = {
247
+ .name = "loadpin",
248
+ .init = loadpin_init,
249
+};
250
+
193251 /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
194
-module_param(enabled, int, 0);
195
-MODULE_PARM_DESC(enabled, "Pin module/firmware loading (default: true)");
252
+module_param(enforce, int, 0);
253
+MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
254
+module_param_array_named(exclude, exclude_read_files, charp, NULL, 0);
255
+MODULE_PARM_DESC(exclude, "Exclude pinning specific read file types");