blob: 7172ad75496b8c0584de3aaf8484c4627e72a296 [file] [log] [blame]
Matthew Garrett000d3882019-08-19 17:17:39 -07001// 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 char *lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = {
20 [LOCKDOWN_NONE] = "none",
21 [LOCKDOWN_INTEGRITY_MAX] = "integrity",
22 [LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
23};
24
25static enum lockdown_reason lockdown_levels[] = {LOCKDOWN_NONE,
26 LOCKDOWN_INTEGRITY_MAX,
27 LOCKDOWN_CONFIDENTIALITY_MAX};
28
29/*
30 * Put the kernel into lock-down mode.
31 */
32static int lock_kernel_down(const char *where, enum lockdown_reason level)
33{
34 if (kernel_locked_down >= level)
35 return -EPERM;
36
37 kernel_locked_down = level;
38 pr_notice("Kernel is locked down from %s; see man kernel_lockdown.7\n",
39 where);
40 return 0;
41}
42
43static int __init lockdown_param(char *level)
44{
45 if (!level)
46 return -EINVAL;
47
48 if (strcmp(level, "integrity") == 0)
49 lock_kernel_down("command line", LOCKDOWN_INTEGRITY_MAX);
50 else if (strcmp(level, "confidentiality") == 0)
51 lock_kernel_down("command line", LOCKDOWN_CONFIDENTIALITY_MAX);
52 else
53 return -EINVAL;
54
55 return 0;
56}
57
58early_param("lockdown", lockdown_param);
59
60/**
61 * lockdown_is_locked_down - Find out if the kernel is locked down
62 * @what: Tag to use in notice generated if lockdown is in effect
63 */
64static int lockdown_is_locked_down(enum lockdown_reason what)
65{
66 if (kernel_locked_down >= what) {
67 if (lockdown_reasons[what])
68 pr_notice("Lockdown: %s is restricted; see man kernel_lockdown.7\n",
69 lockdown_reasons[what]);
70 return -EPERM;
71 }
72
73 return 0;
74}
75
76static struct security_hook_list lockdown_hooks[] __lsm_ro_after_init = {
77 LSM_HOOK_INIT(locked_down, lockdown_is_locked_down),
78};
79
80static int __init lockdown_lsm_init(void)
81{
82#if defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY)
83 lock_kernel_down("Kernel configuration", LOCKDOWN_INTEGRITY_MAX);
84#elif defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY)
85 lock_kernel_down("Kernel configuration", LOCKDOWN_CONFIDENTIALITY_MAX);
86#endif
87 security_add_hooks(lockdown_hooks, ARRAY_SIZE(lockdown_hooks),
88 "lockdown");
89 return 0;
90}
91
92static ssize_t lockdown_read(struct file *filp, char __user *buf, size_t count,
93 loff_t *ppos)
94{
95 char temp[80];
96 int i, offset = 0;
97
98 for (i = 0; i < ARRAY_SIZE(lockdown_levels); i++) {
99 enum lockdown_reason level = lockdown_levels[i];
100
101 if (lockdown_reasons[level]) {
102 const char *label = lockdown_reasons[level];
103
104 if (kernel_locked_down == level)
105 offset += sprintf(temp+offset, "[%s] ", label);
106 else
107 offset += sprintf(temp+offset, "%s ", label);
108 }
109 }
110
111 /* Convert the last space to a newline if needed. */
112 if (offset > 0)
113 temp[offset-1] = '\n';
114
115 return simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
116}
117
118static ssize_t lockdown_write(struct file *file, const char __user *buf,
119 size_t n, loff_t *ppos)
120{
121 char *state;
122 int i, len, err = -EINVAL;
123
124 state = memdup_user_nul(buf, n);
125 if (IS_ERR(state))
126 return PTR_ERR(state);
127
128 len = strlen(state);
129 if (len && state[len-1] == '\n') {
130 state[len-1] = '\0';
131 len--;
132 }
133
134 for (i = 0; i < ARRAY_SIZE(lockdown_levels); i++) {
135 enum lockdown_reason level = lockdown_levels[i];
136 const char *label = lockdown_reasons[level];
137
138 if (label && !strcmp(state, label))
139 err = lock_kernel_down("securityfs", level);
140 }
141
142 kfree(state);
143 return err ? err : n;
144}
145
146static const struct file_operations lockdown_ops = {
147 .read = lockdown_read,
148 .write = lockdown_write,
149};
150
151static int __init lockdown_secfs_init(void)
152{
153 struct dentry *dentry;
154
155 dentry = securityfs_create_file("lockdown", 0600, NULL, NULL,
156 &lockdown_ops);
157 return PTR_ERR_OR_ZERO(dentry);
158}
159
160core_initcall(lockdown_secfs_init);
161
162#ifdef CONFIG_SECURITY_LOCKDOWN_LSM_EARLY
163DEFINE_EARLY_LSM(lockdown) = {
164#else
165DEFINE_LSM(lockdown) = {
166#endif
167 .name = "lockdown",
168 .init = lockdown_lsm_init,
169};