.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* ----------------------------------------------------------------------- * |
---|
2 | 3 | * |
---|
3 | 4 | * Copyright 2000-2008 H. Peter Anvin - All Rights Reserved |
---|
4 | 5 | * Copyright 2009 Intel Corporation; author: H. Peter Anvin |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License as published by |
---|
8 | | - * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, |
---|
9 | | - * USA; either version 2 of the License, or (at your option) any later |
---|
10 | | - * version; incorporated herein by reference. |
---|
11 | 6 | * |
---|
12 | 7 | * ----------------------------------------------------------------------- */ |
---|
13 | 8 | |
---|
.. | .. |
---|
39 | 34 | #include <linux/notifier.h> |
---|
40 | 35 | #include <linux/uaccess.h> |
---|
41 | 36 | #include <linux/gfp.h> |
---|
| 37 | +#include <linux/security.h> |
---|
42 | 38 | |
---|
43 | 39 | #include <asm/cpufeature.h> |
---|
44 | 40 | #include <asm/msr.h> |
---|
45 | 41 | |
---|
46 | 42 | static struct class *msr_class; |
---|
47 | 43 | static enum cpuhp_state cpuhp_msr_state; |
---|
| 44 | + |
---|
| 45 | +enum allow_write_msrs { |
---|
| 46 | + MSR_WRITES_ON, |
---|
| 47 | + MSR_WRITES_OFF, |
---|
| 48 | + MSR_WRITES_DEFAULT, |
---|
| 49 | +}; |
---|
| 50 | + |
---|
| 51 | +static enum allow_write_msrs allow_writes = MSR_WRITES_DEFAULT; |
---|
48 | 52 | |
---|
49 | 53 | static ssize_t msr_read(struct file *file, char __user *buf, |
---|
50 | 54 | size_t count, loff_t *ppos) |
---|
.. | .. |
---|
74 | 78 | return bytes ? bytes : err; |
---|
75 | 79 | } |
---|
76 | 80 | |
---|
| 81 | +static int filter_write(u32 reg) |
---|
| 82 | +{ |
---|
| 83 | + /* |
---|
| 84 | + * MSRs writes usually happen all at once, and can easily saturate kmsg. |
---|
| 85 | + * Only allow one message every 30 seconds. |
---|
| 86 | + * |
---|
| 87 | + * It's possible to be smarter here and do it (for example) per-MSR, but |
---|
| 88 | + * it would certainly be more complex, and this is enough at least to |
---|
| 89 | + * avoid saturating the ring buffer. |
---|
| 90 | + */ |
---|
| 91 | + static DEFINE_RATELIMIT_STATE(fw_rs, 30 * HZ, 1); |
---|
| 92 | + |
---|
| 93 | + switch (allow_writes) { |
---|
| 94 | + case MSR_WRITES_ON: return 0; |
---|
| 95 | + case MSR_WRITES_OFF: return -EPERM; |
---|
| 96 | + default: break; |
---|
| 97 | + } |
---|
| 98 | + |
---|
| 99 | + if (!__ratelimit(&fw_rs)) |
---|
| 100 | + return 0; |
---|
| 101 | + |
---|
| 102 | + if (reg == MSR_IA32_ENERGY_PERF_BIAS) |
---|
| 103 | + return 0; |
---|
| 104 | + |
---|
| 105 | + pr_err("Write to unrecognized MSR 0x%x by %s (pid: %d). Please report to x86@kernel.org.\n", |
---|
| 106 | + reg, current->comm, current->pid); |
---|
| 107 | + |
---|
| 108 | + return 0; |
---|
| 109 | +} |
---|
| 110 | + |
---|
77 | 111 | static ssize_t msr_write(struct file *file, const char __user *buf, |
---|
78 | 112 | size_t count, loff_t *ppos) |
---|
79 | 113 | { |
---|
.. | .. |
---|
84 | 118 | int err = 0; |
---|
85 | 119 | ssize_t bytes = 0; |
---|
86 | 120 | |
---|
| 121 | + err = security_locked_down(LOCKDOWN_MSR); |
---|
| 122 | + if (err) |
---|
| 123 | + return err; |
---|
| 124 | + |
---|
| 125 | + err = filter_write(reg); |
---|
| 126 | + if (err) |
---|
| 127 | + return err; |
---|
| 128 | + |
---|
87 | 129 | if (count % 8) |
---|
88 | 130 | return -EINVAL; /* Invalid chunk size */ |
---|
89 | 131 | |
---|
.. | .. |
---|
92 | 134 | err = -EFAULT; |
---|
93 | 135 | break; |
---|
94 | 136 | } |
---|
| 137 | + |
---|
| 138 | + add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); |
---|
| 139 | + |
---|
95 | 140 | err = wrmsr_safe_on_cpu(cpu, reg, data[0], data[1]); |
---|
96 | 141 | if (err) |
---|
97 | 142 | break; |
---|
| 143 | + |
---|
98 | 144 | tmp += 2; |
---|
99 | 145 | bytes += 8; |
---|
100 | 146 | } |
---|
.. | .. |
---|
115 | 161 | err = -EBADF; |
---|
116 | 162 | break; |
---|
117 | 163 | } |
---|
118 | | - if (copy_from_user(®s, uregs, sizeof regs)) { |
---|
| 164 | + if (copy_from_user(®s, uregs, sizeof(regs))) { |
---|
119 | 165 | err = -EFAULT; |
---|
120 | 166 | break; |
---|
121 | 167 | } |
---|
122 | 168 | err = rdmsr_safe_regs_on_cpu(cpu, regs); |
---|
123 | 169 | if (err) |
---|
124 | 170 | break; |
---|
125 | | - if (copy_to_user(uregs, ®s, sizeof regs)) |
---|
| 171 | + if (copy_to_user(uregs, ®s, sizeof(regs))) |
---|
126 | 172 | err = -EFAULT; |
---|
127 | 173 | break; |
---|
128 | 174 | |
---|
.. | .. |
---|
131 | 177 | err = -EBADF; |
---|
132 | 178 | break; |
---|
133 | 179 | } |
---|
134 | | - if (copy_from_user(®s, uregs, sizeof regs)) { |
---|
| 180 | + if (copy_from_user(®s, uregs, sizeof(regs))) { |
---|
135 | 181 | err = -EFAULT; |
---|
136 | 182 | break; |
---|
137 | 183 | } |
---|
| 184 | + err = security_locked_down(LOCKDOWN_MSR); |
---|
| 185 | + if (err) |
---|
| 186 | + break; |
---|
| 187 | + |
---|
| 188 | + err = filter_write(regs[1]); |
---|
| 189 | + if (err) |
---|
| 190 | + return err; |
---|
| 191 | + |
---|
| 192 | + add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); |
---|
| 193 | + |
---|
138 | 194 | err = wrmsr_safe_regs_on_cpu(cpu, regs); |
---|
139 | 195 | if (err) |
---|
140 | 196 | break; |
---|
141 | | - if (copy_to_user(uregs, ®s, sizeof regs)) |
---|
| 197 | + if (copy_to_user(uregs, ®s, sizeof(regs))) |
---|
142 | 198 | err = -EFAULT; |
---|
143 | 199 | break; |
---|
144 | 200 | |
---|
.. | .. |
---|
239 | 295 | } |
---|
240 | 296 | module_exit(msr_exit) |
---|
241 | 297 | |
---|
| 298 | +static int set_allow_writes(const char *val, const struct kernel_param *cp) |
---|
| 299 | +{ |
---|
| 300 | + /* val is NUL-terminated, see kernfs_fop_write() */ |
---|
| 301 | + char *s = strstrip((char *)val); |
---|
| 302 | + |
---|
| 303 | + if (!strcmp(s, "on")) |
---|
| 304 | + allow_writes = MSR_WRITES_ON; |
---|
| 305 | + else if (!strcmp(s, "off")) |
---|
| 306 | + allow_writes = MSR_WRITES_OFF; |
---|
| 307 | + else |
---|
| 308 | + allow_writes = MSR_WRITES_DEFAULT; |
---|
| 309 | + |
---|
| 310 | + return 0; |
---|
| 311 | +} |
---|
| 312 | + |
---|
| 313 | +static int get_allow_writes(char *buf, const struct kernel_param *kp) |
---|
| 314 | +{ |
---|
| 315 | + const char *res; |
---|
| 316 | + |
---|
| 317 | + switch (allow_writes) { |
---|
| 318 | + case MSR_WRITES_ON: res = "on"; break; |
---|
| 319 | + case MSR_WRITES_OFF: res = "off"; break; |
---|
| 320 | + default: res = "default"; break; |
---|
| 321 | + } |
---|
| 322 | + |
---|
| 323 | + return sprintf(buf, "%s\n", res); |
---|
| 324 | +} |
---|
| 325 | + |
---|
| 326 | +static const struct kernel_param_ops allow_writes_ops = { |
---|
| 327 | + .set = set_allow_writes, |
---|
| 328 | + .get = get_allow_writes |
---|
| 329 | +}; |
---|
| 330 | + |
---|
| 331 | +module_param_cb(allow_writes, &allow_writes_ops, NULL, 0600); |
---|
| 332 | + |
---|
242 | 333 | MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>"); |
---|
243 | 334 | MODULE_DESCRIPTION("x86 generic MSR driver"); |
---|
244 | 335 | MODULE_LICENSE("GPL"); |
---|