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