linux/security/loadpin/loadpin.c
<<
>>
Prefs
   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/lsm_hooks.h>
  15#include <linux/mount.h>
  16#include <linux/path.h>
  17#include <linux/sched.h>        /* current */
  18#include <linux/string_helpers.h>
  19
  20static void report_load(const char *origin, struct file *file, char *operation)
  21{
  22        char *cmdline, *pathname;
  23
  24        pathname = kstrdup_quotable_file(file, GFP_KERNEL);
  25        cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL);
  26
  27        pr_notice("%s %s obj=%s%s%s pid=%d cmdline=%s%s%s\n",
  28                  origin, operation,
  29                  (pathname && pathname[0] != '<') ? "\"" : "",
  30                  pathname,
  31                  (pathname && pathname[0] != '<') ? "\"" : "",
  32                  task_pid_nr(current),
  33                  cmdline ? "\"" : "", cmdline, cmdline ? "\"" : "");
  34
  35        kfree(cmdline);
  36        kfree(pathname);
  37}
  38
  39static int enforce = IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENFORCE);
  40static struct super_block *pinned_root;
  41static DEFINE_SPINLOCK(pinned_root_spinlock);
  42
  43#ifdef CONFIG_SYSCTL
  44static int zero;
  45static int one = 1;
  46
  47static struct ctl_path loadpin_sysctl_path[] = {
  48        { .procname = "kernel", },
  49        { .procname = "loadpin", },
  50        { }
  51};
  52
  53static struct ctl_table loadpin_sysctl_table[] = {
  54        {
  55                .procname       = "enforce",
  56                .data           = &enforce,
  57                .maxlen         = sizeof(int),
  58                .mode           = 0644,
  59                .proc_handler   = proc_dointvec_minmax,
  60                .extra1         = &zero,
  61                .extra2         = &one,
  62        },
  63        { }
  64};
  65
  66/*
  67 * This must be called after early kernel init, since then the rootdev
  68 * is available.
  69 */
  70static void check_pinning_enforcement(struct super_block *mnt_sb)
  71{
  72        bool ro = false;
  73
  74        /*
  75         * If load pinning is not enforced via a read-only block
  76         * device, allow sysctl to change modes for testing.
  77         */
  78        if (mnt_sb->s_bdev) {
  79                char bdev[BDEVNAME_SIZE];
  80
  81                ro = bdev_read_only(mnt_sb->s_bdev);
  82                bdevname(mnt_sb->s_bdev, bdev);
  83                pr_info("%s (%u:%u): %s\n", bdev,
  84                        MAJOR(mnt_sb->s_bdev->bd_dev),
  85                        MINOR(mnt_sb->s_bdev->bd_dev),
  86                        ro ? "read-only" : "writable");
  87        } else
  88                pr_info("mnt_sb lacks block device, treating as: writable\n");
  89
  90        if (!ro) {
  91                if (!register_sysctl_paths(loadpin_sysctl_path,
  92                                           loadpin_sysctl_table))
  93                        pr_notice("sysctl registration failed!\n");
  94                else
  95                        pr_info("enforcement can be disabled.\n");
  96        } else
  97                pr_info("load pinning engaged.\n");
  98}
  99#else
 100static void check_pinning_enforcement(struct super_block *mnt_sb)
 101{
 102        pr_info("load pinning engaged.\n");
 103}
 104#endif
 105
 106static void loadpin_sb_free_security(struct super_block *mnt_sb)
 107{
 108        /*
 109         * When unmounting the filesystem we were using for load
 110         * pinning, we acknowledge the superblock release, but make sure
 111         * no other modules or firmware can be loaded.
 112         */
 113        if (!IS_ERR_OR_NULL(pinned_root) && mnt_sb == pinned_root) {
 114                pinned_root = ERR_PTR(-EIO);
 115                pr_info("umount pinned fs: refusing further loads\n");
 116        }
 117}
 118
 119static int loadpin_read_file(struct file *file, enum kernel_read_file_id id)
 120{
 121        struct super_block *load_root;
 122        const char *origin = kernel_read_file_id_str(id);
 123
 124        /* This handles the older init_module API that has a NULL file. */
 125        if (!file) {
 126                if (!enforce) {
 127                        report_load(origin, NULL, "old-api-pinning-ignored");
 128                        return 0;
 129                }
 130
 131                report_load(origin, NULL, "old-api-denied");
 132                return -EPERM;
 133        }
 134
 135        load_root = file->f_path.mnt->mnt_sb;
 136
 137        /* First loaded module/firmware defines the root for all others. */
 138        spin_lock(&pinned_root_spinlock);
 139        /*
 140         * pinned_root is only NULL at startup. Otherwise, it is either
 141         * a valid reference, or an ERR_PTR.
 142         */
 143        if (!pinned_root) {
 144                pinned_root = load_root;
 145                /*
 146                 * Unlock now since it's only pinned_root we care about.
 147                 * In the worst case, we will (correctly) report pinning
 148                 * failures before we have announced that pinning is
 149                 * enforcing. This would be purely cosmetic.
 150                 */
 151                spin_unlock(&pinned_root_spinlock);
 152                check_pinning_enforcement(pinned_root);
 153                report_load(origin, file, "pinned");
 154        } else {
 155                spin_unlock(&pinned_root_spinlock);
 156        }
 157
 158        if (IS_ERR_OR_NULL(pinned_root) || load_root != pinned_root) {
 159                if (unlikely(!enforce)) {
 160                        report_load(origin, file, "pinning-ignored");
 161                        return 0;
 162                }
 163
 164                report_load(origin, file, "denied");
 165                return -EPERM;
 166        }
 167
 168        return 0;
 169}
 170
 171static int loadpin_load_data(enum kernel_load_data_id id)
 172{
 173        return loadpin_read_file(NULL, (enum kernel_read_file_id) id);
 174}
 175
 176static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = {
 177        LSM_HOOK_INIT(sb_free_security, loadpin_sb_free_security),
 178        LSM_HOOK_INIT(kernel_read_file, loadpin_read_file),
 179        LSM_HOOK_INIT(kernel_load_data, loadpin_load_data),
 180};
 181
 182static int __init loadpin_init(void)
 183{
 184        pr_info("ready to pin (currently %senforcing)\n",
 185                enforce ? "" : "not ");
 186        security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
 187        return 0;
 188}
 189
 190DEFINE_LSM(loadpin) = {
 191        .name = "loadpin",
 192        .init = loadpin_init,
 193};
 194
 195/* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
 196module_param(enforce, int, 0);
 197MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
 198