forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-05 071106ecf68c401173c58808b1cf5f68cc50d390
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,21 @@
121118 }
122119 }
123120
124
-static int loadpin_read_file(struct file *file, enum kernel_read_file_id id)
121
+static int loadpin_check(struct file *file, enum kernel_read_file_id id)
125122 {
126123 struct super_block *load_root;
127124 const char *origin = kernel_read_file_id_str(id);
128125
126
+ /* If the file id is excluded, ignore the pinning. */
127
+ if ((unsigned int)id < ARRAY_SIZE(ignore_read_file_id) &&
128
+ ignore_read_file_id[id]) {
129
+ report_load(origin, file, "pinning-excluded");
130
+ return 0;
131
+ }
132
+
129133 /* This handles the older init_module API that has a NULL file. */
130134 if (!file) {
131
- if (!enabled) {
135
+ if (!enforce) {
132136 report_load(origin, NULL, "old-api-pinning-ignored");
133137 return 0;
134138 }
....@@ -151,7 +155,7 @@
151155 * Unlock now since it's only pinned_root we care about.
152156 * In the worst case, we will (correctly) report pinning
153157 * failures before we have announced that pinning is
154
- * enabled. This would be purely cosmetic.
158
+ * enforcing. This would be purely cosmetic.
155159 */
156160 spin_unlock(&pinned_root_spinlock);
157161 check_pinning_enforcement(pinned_root);
....@@ -161,7 +165,7 @@
161165 }
162166
163167 if (IS_ERR_OR_NULL(pinned_root) || load_root != pinned_root) {
164
- if (unlikely(!enabled)) {
168
+ if (unlikely(!enforce)) {
165169 report_load(origin, file, "pinning-ignored");
166170 return 0;
167171 }
....@@ -173,9 +177,25 @@
173177 return 0;
174178 }
175179
176
-static int loadpin_load_data(enum kernel_load_data_id id)
180
+static int loadpin_read_file(struct file *file, enum kernel_read_file_id id,
181
+ bool contents)
177182 {
178
- return loadpin_read_file(NULL, (enum kernel_read_file_id) id);
183
+ /*
184
+ * LoadPin only cares about the _origin_ of a file, not its
185
+ * contents, so we can ignore the "are full contents available"
186
+ * argument here.
187
+ */
188
+ return loadpin_check(file, id);
189
+}
190
+
191
+static int loadpin_load_data(enum kernel_load_data_id id, bool contents)
192
+{
193
+ /*
194
+ * LoadPin only cares about the _origin_ of a file, not its
195
+ * contents, so a NULL file is passed, and we can ignore the
196
+ * state of "contents".
197
+ */
198
+ return loadpin_check(NULL, (enum kernel_read_file_id) id);
179199 }
180200
181201 static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = {
....@@ -184,12 +204,58 @@
184204 LSM_HOOK_INIT(kernel_load_data, loadpin_load_data),
185205 };
186206
187
-void __init loadpin_add_hooks(void)
207
+static void __init parse_exclude(void)
188208 {
189
- pr_info("ready to pin (currently %sabled)", enabled ? "en" : "dis");
190
- security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
209
+ int i, j;
210
+ char *cur;
211
+
212
+ /*
213
+ * Make sure all the arrays stay within expected sizes. This
214
+ * is slightly weird because kernel_read_file_str[] includes
215
+ * READING_MAX_ID, which isn't actually meaningful here.
216
+ */
217
+ BUILD_BUG_ON(ARRAY_SIZE(exclude_read_files) !=
218
+ ARRAY_SIZE(ignore_read_file_id));
219
+ BUILD_BUG_ON(ARRAY_SIZE(kernel_read_file_str) <
220
+ ARRAY_SIZE(ignore_read_file_id));
221
+
222
+ for (i = 0; i < ARRAY_SIZE(exclude_read_files); i++) {
223
+ cur = exclude_read_files[i];
224
+ if (!cur)
225
+ break;
226
+ if (*cur == '\0')
227
+ continue;
228
+
229
+ for (j = 0; j < ARRAY_SIZE(ignore_read_file_id); j++) {
230
+ if (strcmp(cur, kernel_read_file_str[j]) == 0) {
231
+ pr_info("excluding: %s\n",
232
+ kernel_read_file_str[j]);
233
+ ignore_read_file_id[j] = 1;
234
+ /*
235
+ * Can not break, because one read_file_str
236
+ * may map to more than on read_file_id.
237
+ */
238
+ }
239
+ }
240
+ }
191241 }
192242
243
+static int __init loadpin_init(void)
244
+{
245
+ pr_info("ready to pin (currently %senforcing)\n",
246
+ enforce ? "" : "not ");
247
+ parse_exclude();
248
+ security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
249
+ return 0;
250
+}
251
+
252
+DEFINE_LSM(loadpin) = {
253
+ .name = "loadpin",
254
+ .init = loadpin_init,
255
+};
256
+
193257 /* 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)");
258
+module_param(enforce, int, 0);
259
+MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
260
+module_param_array_named(exclude, exclude_read_files, charp, NULL, 0);
261
+MODULE_PARM_DESC(exclude, "Exclude pinning specific read file types");