cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

lockdown.c (4198B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Lock down the kernel
      3 *
      4 * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
      5 * Written by David Howells (dhowells@redhat.com)
      6 *
      7 * This program is free software; you can redistribute it and/or
      8 * modify it under the terms of the GNU General Public Licence
      9 * as published by the Free Software Foundation; either version
     10 * 2 of the Licence, or (at your option) any later version.
     11 */
     12
     13#include <linux/security.h>
     14#include <linux/export.h>
     15#include <linux/lsm_hooks.h>
     16
     17static enum lockdown_reason kernel_locked_down;
     18
     19static const enum lockdown_reason lockdown_levels[] = {LOCKDOWN_NONE,
     20						 LOCKDOWN_INTEGRITY_MAX,
     21						 LOCKDOWN_CONFIDENTIALITY_MAX};
     22
     23/*
     24 * Put the kernel into lock-down mode.
     25 */
     26static int lock_kernel_down(const char *where, enum lockdown_reason level)
     27{
     28	if (kernel_locked_down >= level)
     29		return -EPERM;
     30
     31	kernel_locked_down = level;
     32	pr_notice("Kernel is locked down from %s; see man kernel_lockdown.7\n",
     33		  where);
     34	return 0;
     35}
     36
     37static int __init lockdown_param(char *level)
     38{
     39	if (!level)
     40		return -EINVAL;
     41
     42	if (strcmp(level, "integrity") == 0)
     43		lock_kernel_down("command line", LOCKDOWN_INTEGRITY_MAX);
     44	else if (strcmp(level, "confidentiality") == 0)
     45		lock_kernel_down("command line", LOCKDOWN_CONFIDENTIALITY_MAX);
     46	else
     47		return -EINVAL;
     48
     49	return 0;
     50}
     51
     52early_param("lockdown", lockdown_param);
     53
     54/**
     55 * lockdown_is_locked_down - Find out if the kernel is locked down
     56 * @what: Tag to use in notice generated if lockdown is in effect
     57 */
     58static int lockdown_is_locked_down(enum lockdown_reason what)
     59{
     60	if (WARN(what >= LOCKDOWN_CONFIDENTIALITY_MAX,
     61		 "Invalid lockdown reason"))
     62		return -EPERM;
     63
     64	if (kernel_locked_down >= what) {
     65		if (lockdown_reasons[what])
     66			pr_notice("Lockdown: %s: %s is restricted; see man kernel_lockdown.7\n",
     67				  current->comm, lockdown_reasons[what]);
     68		return -EPERM;
     69	}
     70
     71	return 0;
     72}
     73
     74static struct security_hook_list lockdown_hooks[] __lsm_ro_after_init = {
     75	LSM_HOOK_INIT(locked_down, lockdown_is_locked_down),
     76};
     77
     78static int __init lockdown_lsm_init(void)
     79{
     80#if defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY)
     81	lock_kernel_down("Kernel configuration", LOCKDOWN_INTEGRITY_MAX);
     82#elif defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY)
     83	lock_kernel_down("Kernel configuration", LOCKDOWN_CONFIDENTIALITY_MAX);
     84#endif
     85	security_add_hooks(lockdown_hooks, ARRAY_SIZE(lockdown_hooks),
     86			   "lockdown");
     87	return 0;
     88}
     89
     90static ssize_t lockdown_read(struct file *filp, char __user *buf, size_t count,
     91			     loff_t *ppos)
     92{
     93	char temp[80];
     94	int i, offset = 0;
     95
     96	for (i = 0; i < ARRAY_SIZE(lockdown_levels); i++) {
     97		enum lockdown_reason level = lockdown_levels[i];
     98
     99		if (lockdown_reasons[level]) {
    100			const char *label = lockdown_reasons[level];
    101
    102			if (kernel_locked_down == level)
    103				offset += sprintf(temp+offset, "[%s] ", label);
    104			else
    105				offset += sprintf(temp+offset, "%s ", label);
    106		}
    107	}
    108
    109	/* Convert the last space to a newline if needed. */
    110	if (offset > 0)
    111		temp[offset-1] = '\n';
    112
    113	return simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
    114}
    115
    116static ssize_t lockdown_write(struct file *file, const char __user *buf,
    117			      size_t n, loff_t *ppos)
    118{
    119	char *state;
    120	int i, len, err = -EINVAL;
    121
    122	state = memdup_user_nul(buf, n);
    123	if (IS_ERR(state))
    124		return PTR_ERR(state);
    125
    126	len = strlen(state);
    127	if (len && state[len-1] == '\n') {
    128		state[len-1] = '\0';
    129		len--;
    130	}
    131
    132	for (i = 0; i < ARRAY_SIZE(lockdown_levels); i++) {
    133		enum lockdown_reason level = lockdown_levels[i];
    134		const char *label = lockdown_reasons[level];
    135
    136		if (label && !strcmp(state, label))
    137			err = lock_kernel_down("securityfs", level);
    138	}
    139
    140	kfree(state);
    141	return err ? err : n;
    142}
    143
    144static const struct file_operations lockdown_ops = {
    145	.read  = lockdown_read,
    146	.write = lockdown_write,
    147};
    148
    149static int __init lockdown_secfs_init(void)
    150{
    151	struct dentry *dentry;
    152
    153	dentry = securityfs_create_file("lockdown", 0644, NULL, NULL,
    154					&lockdown_ops);
    155	return PTR_ERR_OR_ZERO(dentry);
    156}
    157
    158core_initcall(lockdown_secfs_init);
    159
    160#ifdef CONFIG_SECURITY_LOCKDOWN_LSM_EARLY
    161DEFINE_EARLY_LSM(lockdown) = {
    162#else
    163DEFINE_LSM(lockdown) = {
    164#endif
    165	.name = "lockdown",
    166	.init = lockdown_lsm_init,
    167};