~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/security/loadpin/loadpin.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Module and Firmware Pinning Security Module
  4  *
  5  * Copyright 2011-2016 Google Inc.
  6  *
  7  * Author: Kees Cook <keescook@chromium.org>
  8  */
  9 
 10 #define pr_fmt(fmt) "LoadPin: " fmt
 11 
 12 #include <linux/module.h>
 13 #include <linux/fs.h>
 14 #include <linux/kernel_read_file.h>
 15 #include <linux/lsm_hooks.h>
 16 #include <linux/mount.h>
 17 #include <linux/blkdev.h>
 18 #include <linux/path.h>
 19 #include <linux/sched.h>        /* current */
 20 #include <linux/string_helpers.h>
 21 #include <linux/dm-verity-loadpin.h>
 22 #include <uapi/linux/loadpin.h>
 23 #include <uapi/linux/lsm.h>
 24 
 25 #define VERITY_DIGEST_FILE_HEADER "# LOADPIN_TRUSTED_VERITY_ROOT_DIGESTS"
 26 
 27 static void report_load(const char *origin, struct file *file, char *operation)
 28 {
 29         char *cmdline, *pathname;
 30 
 31         pathname = kstrdup_quotable_file(file, GFP_KERNEL);
 32         cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL);
 33 
 34         pr_notice("%s %s obj=%s%s%s pid=%d cmdline=%s%s%s\n",
 35                   origin, operation,
 36                   (pathname && pathname[0] != '<') ? "\"" : "",
 37                   pathname,
 38                   (pathname && pathname[0] != '<') ? "\"" : "",
 39                   task_pid_nr(current),
 40                   cmdline ? "\"" : "", cmdline, cmdline ? "\"" : "");
 41 
 42         kfree(cmdline);
 43         kfree(pathname);
 44 }
 45 
 46 static int enforce = IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENFORCE);
 47 static char *exclude_read_files[READING_MAX_ID];
 48 static int ignore_read_file_id[READING_MAX_ID] __ro_after_init;
 49 static struct super_block *pinned_root;
 50 static DEFINE_SPINLOCK(pinned_root_spinlock);
 51 #ifdef CONFIG_SECURITY_LOADPIN_VERITY
 52 static bool deny_reading_verity_digests;
 53 #endif
 54 
 55 #ifdef CONFIG_SYSCTL
 56 static struct ctl_table loadpin_sysctl_table[] = {
 57         {
 58                 .procname       = "enforce",
 59                 .data           = &enforce,
 60                 .maxlen         = sizeof(int),
 61                 .mode           = 0644,
 62                 .proc_handler   = proc_dointvec_minmax,
 63                 .extra1         = SYSCTL_ONE,
 64                 .extra2         = SYSCTL_ONE,
 65         },
 66 };
 67 
 68 static void set_sysctl(bool is_writable)
 69 {
 70         /*
 71          * If load pinning is not enforced via a read-only block
 72          * device, allow sysctl to change modes for testing.
 73          */
 74         if (is_writable)
 75                 loadpin_sysctl_table[0].extra1 = SYSCTL_ZERO;
 76         else
 77                 loadpin_sysctl_table[0].extra1 = SYSCTL_ONE;
 78 }
 79 #else
 80 static inline void set_sysctl(bool is_writable) { }
 81 #endif
 82 
 83 static void report_writable(struct super_block *mnt_sb, bool writable)
 84 {
 85         if (mnt_sb->s_bdev) {
 86                 pr_info("%pg (%u:%u): %s\n", mnt_sb->s_bdev,
 87                         MAJOR(mnt_sb->s_bdev->bd_dev),
 88                         MINOR(mnt_sb->s_bdev->bd_dev),
 89                         writable ? "writable" : "read-only");
 90         } else
 91                 pr_info("mnt_sb lacks block device, treating as: writable\n");
 92 
 93         if (!writable)
 94                 pr_info("load pinning engaged.\n");
 95 }
 96 
 97 /*
 98  * This must be called after early kernel init, since then the rootdev
 99  * is available.
100  */
101 static bool sb_is_writable(struct super_block *mnt_sb)
102 {
103         bool writable = true;
104 
105         if (mnt_sb->s_bdev)
106                 writable = !bdev_read_only(mnt_sb->s_bdev);
107 
108         return writable;
109 }
110 
111 static void loadpin_sb_free_security(struct super_block *mnt_sb)
112 {
113         /*
114          * When unmounting the filesystem we were using for load
115          * pinning, we acknowledge the superblock release, but make sure
116          * no other modules or firmware can be loaded when we are in
117          * enforcing mode. Otherwise, allow the root to be reestablished.
118          */
119         if (!IS_ERR_OR_NULL(pinned_root) && mnt_sb == pinned_root) {
120                 if (enforce) {
121                         pinned_root = ERR_PTR(-EIO);
122                         pr_info("umount pinned fs: refusing further loads\n");
123                 } else {
124                         pinned_root = NULL;
125                 }
126         }
127 }
128 
129 static int loadpin_check(struct file *file, enum kernel_read_file_id id)
130 {
131         struct super_block *load_root;
132         const char *origin = kernel_read_file_id_str(id);
133         bool first_root_pin = false;
134         bool load_root_writable;
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 
143         /* This handles the older init_module API that has a NULL file. */
144         if (!file) {
145                 if (!enforce) {
146                         report_load(origin, NULL, "old-api-pinning-ignored");
147                         return 0;
148                 }
149 
150                 report_load(origin, NULL, "old-api-denied");
151                 return -EPERM;
152         }
153 
154         load_root = file->f_path.mnt->mnt_sb;
155         load_root_writable = sb_is_writable(load_root);
156 
157         /* First loaded module/firmware defines the root for all others. */
158         spin_lock(&pinned_root_spinlock);
159         /*
160          * pinned_root is only NULL at startup or when the pinned root has
161          * been unmounted while we are not in enforcing mode. Otherwise, it
162          * is either a valid reference, or an ERR_PTR.
163          */
164         if (!pinned_root) {
165                 pinned_root = load_root;
166                 first_root_pin = true;
167         }
168         spin_unlock(&pinned_root_spinlock);
169 
170         if (first_root_pin) {
171                 report_writable(pinned_root, load_root_writable);
172                 set_sysctl(load_root_writable);
173                 report_load(origin, file, "pinned");
174         }
175 
176         if (IS_ERR_OR_NULL(pinned_root) ||
177             ((load_root != pinned_root) && !dm_verity_loadpin_is_bdev_trusted(load_root->s_bdev))) {
178                 if (unlikely(!enforce)) {
179                         report_load(origin, file, "pinning-ignored");
180                         return 0;
181                 }
182 
183                 report_load(origin, file, "denied");
184                 return -EPERM;
185         }
186 
187         return 0;
188 }
189 
190 static int loadpin_read_file(struct file *file, enum kernel_read_file_id id,
191                              bool contents)
192 {
193         /*
194          * LoadPin only cares about the _origin_ of a file, not its
195          * contents, so we can ignore the "are full contents available"
196          * argument here.
197          */
198         return loadpin_check(file, id);
199 }
200 
201 static int loadpin_load_data(enum kernel_load_data_id id, bool contents)
202 {
203         /*
204          * LoadPin only cares about the _origin_ of a file, not its
205          * contents, so a NULL file is passed, and we can ignore the
206          * state of "contents".
207          */
208         return loadpin_check(NULL, (enum kernel_read_file_id) id);
209 }
210 
211 static const struct lsm_id loadpin_lsmid = {
212         .name = "loadpin",
213         .id = LSM_ID_LOADPIN,
214 };
215 
216 static struct security_hook_list loadpin_hooks[] __ro_after_init = {
217         LSM_HOOK_INIT(sb_free_security, loadpin_sb_free_security),
218         LSM_HOOK_INIT(kernel_read_file, loadpin_read_file),
219         LSM_HOOK_INIT(kernel_load_data, loadpin_load_data),
220 };
221 
222 static void __init parse_exclude(void)
223 {
224         int i, j;
225         char *cur;
226 
227         /*
228          * Make sure all the arrays stay within expected sizes. This
229          * is slightly weird because kernel_read_file_str[] includes
230          * READING_MAX_ID, which isn't actually meaningful here.
231          */
232         BUILD_BUG_ON(ARRAY_SIZE(exclude_read_files) !=
233                      ARRAY_SIZE(ignore_read_file_id));
234         BUILD_BUG_ON(ARRAY_SIZE(kernel_read_file_str) <
235                      ARRAY_SIZE(ignore_read_file_id));
236 
237         for (i = 0; i < ARRAY_SIZE(exclude_read_files); i++) {
238                 cur = exclude_read_files[i];
239                 if (!cur)
240                         break;
241                 if (*cur == '\0')
242                         continue;
243 
244                 for (j = 0; j < ARRAY_SIZE(ignore_read_file_id); j++) {
245                         if (strcmp(cur, kernel_read_file_str[j]) == 0) {
246                                 pr_info("excluding: %s\n",
247                                         kernel_read_file_str[j]);
248                                 ignore_read_file_id[j] = 1;
249                                 /*
250                                  * Can not break, because one read_file_str
251                                  * may map to more than on read_file_id.
252                                  */
253                         }
254                 }
255         }
256 }
257 
258 static int __init loadpin_init(void)
259 {
260         pr_info("ready to pin (currently %senforcing)\n",
261                 enforce ? "" : "not ");
262         parse_exclude();
263 #ifdef CONFIG_SYSCTL
264         if (!register_sysctl("kernel/loadpin", loadpin_sysctl_table))
265                 pr_notice("sysctl registration failed!\n");
266 #endif
267         security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks),
268                            &loadpin_lsmid);
269 
270         return 0;
271 }
272 
273 DEFINE_LSM(loadpin) = {
274         .name = "loadpin",
275         .init = loadpin_init,
276 };
277 
278 #ifdef CONFIG_SECURITY_LOADPIN_VERITY
279 
280 enum loadpin_securityfs_interface_index {
281         LOADPIN_DM_VERITY,
282 };
283 
284 static int read_trusted_verity_root_digests(unsigned int fd)
285 {
286         struct fd f;
287         void *data;
288         int rc;
289         char *p, *d;
290 
291         if (deny_reading_verity_digests)
292                 return -EPERM;
293 
294         /* The list of trusted root digests can only be set up once */
295         if (!list_empty(&dm_verity_loadpin_trusted_root_digests))
296                 return -EPERM;
297 
298         f = fdget(fd);
299         if (!f.file)
300                 return -EINVAL;
301 
302         data = kzalloc(SZ_4K, GFP_KERNEL);
303         if (!data) {
304                 rc = -ENOMEM;
305                 goto err;
306         }
307 
308         rc = kernel_read_file(f.file, 0, (void **)&data, SZ_4K - 1, NULL, READING_POLICY);
309         if (rc < 0)
310                 goto err;
311 
312         p = data;
313         p[rc] = '\0';
314         p = strim(p);
315 
316         p = strim(data);
317         while ((d = strsep(&p, "\n")) != NULL) {
318                 int len;
319                 struct dm_verity_loadpin_trusted_root_digest *trd;
320 
321                 if (d == data) {
322                         /* first line, validate header */
323                         if (strcmp(d, VERITY_DIGEST_FILE_HEADER)) {
324                                 rc = -EPROTO;
325                                 goto err;
326                         }
327 
328                         continue;
329                 }
330 
331                 len = strlen(d);
332 
333                 if (len % 2) {
334                         rc = -EPROTO;
335                         goto err;
336                 }
337 
338                 len /= 2;
339 
340                 trd = kzalloc(struct_size(trd, data, len), GFP_KERNEL);
341                 if (!trd) {
342                         rc = -ENOMEM;
343                         goto err;
344                 }
345                 trd->len = len;
346 
347                 if (hex2bin(trd->data, d, len)) {
348                         kfree(trd);
349                         rc = -EPROTO;
350                         goto err;
351                 }
352 
353                 list_add_tail(&trd->node, &dm_verity_loadpin_trusted_root_digests);
354         }
355 
356         if (list_empty(&dm_verity_loadpin_trusted_root_digests)) {
357                 rc = -EPROTO;
358                 goto err;
359         }
360 
361         kfree(data);
362         fdput(f);
363 
364         return 0;
365 
366 err:
367         kfree(data);
368 
369         /* any failure in loading/parsing invalidates the entire list */
370         {
371                 struct dm_verity_loadpin_trusted_root_digest *trd, *tmp;
372 
373                 list_for_each_entry_safe(trd, tmp, &dm_verity_loadpin_trusted_root_digests, node) {
374                         list_del(&trd->node);
375                         kfree(trd);
376                 }
377         }
378 
379         /* disallow further attempts after reading a corrupt/invalid file */
380         deny_reading_verity_digests = true;
381 
382         fdput(f);
383 
384         return rc;
385 }
386 
387 /******************************** securityfs ********************************/
388 
389 static long dm_verity_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
390 {
391         void __user *uarg = (void __user *)arg;
392         unsigned int fd;
393 
394         switch (cmd) {
395         case LOADPIN_IOC_SET_TRUSTED_VERITY_DIGESTS:
396                 if (copy_from_user(&fd, uarg, sizeof(fd)))
397                         return -EFAULT;
398 
399                 return read_trusted_verity_root_digests(fd);
400 
401         default:
402                 return -EINVAL;
403         }
404 }
405 
406 static const struct file_operations loadpin_dm_verity_ops = {
407         .unlocked_ioctl = dm_verity_ioctl,
408         .compat_ioctl = compat_ptr_ioctl,
409 };
410 
411 /**
412  * init_loadpin_securityfs - create the securityfs directory for LoadPin
413  *
414  * We can not put this method normally under the loadpin_init() code path since
415  * the security subsystem gets initialized before the vfs caches.
416  *
417  * Returns 0 if the securityfs directory creation was successful.
418  */
419 static int __init init_loadpin_securityfs(void)
420 {
421         struct dentry *loadpin_dir, *dentry;
422 
423         loadpin_dir = securityfs_create_dir("loadpin", NULL);
424         if (IS_ERR(loadpin_dir)) {
425                 pr_err("LoadPin: could not create securityfs dir: %ld\n",
426                        PTR_ERR(loadpin_dir));
427                 return PTR_ERR(loadpin_dir);
428         }
429 
430         dentry = securityfs_create_file("dm-verity", 0600, loadpin_dir,
431                                         (void *)LOADPIN_DM_VERITY, &loadpin_dm_verity_ops);
432         if (IS_ERR(dentry)) {
433                 pr_err("LoadPin: could not create securityfs entry 'dm-verity': %ld\n",
434                        PTR_ERR(dentry));
435                 return PTR_ERR(dentry);
436         }
437 
438         return 0;
439 }
440 
441 fs_initcall(init_loadpin_securityfs);
442 
443 #endif /* CONFIG_SECURITY_LOADPIN_VERITY */
444 
445 /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
446 module_param(enforce, int, 0);
447 MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
448 module_param_array_named(exclude, exclude_read_files, charp, NULL, 0);
449 MODULE_PARM_DESC(exclude, "Exclude pinning specific read file types");
450 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php