Filter MSR writes from user-space by default, and print a syslog entry if

they happen outside the allowed set of MSRs, which is a single one for now,
 MSR_IA32_ENERGY_PERF_BIAS.
 
 The plan is to eventually disable MSR writes by default (they can still be
 enabled via allow_writes=on).
 
 Signed-off-by: Ingo Molnar <mingo@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAl8oWVwRHG1pbmdvQGtl
 cm5lbC5vcmcACgkQEnMQ0APhK1j61Q/+KDteLFjfVaJIEe0yfZ8YWjAPb1HRDg1u
 ia8wyZael5hHpLOQSOhkaTwbvF8dMSLK3oky8ZO2oA5gv99jyB+OZxOGS6mvMcGM
 aI9chECEghlvUKy1i+NNHSK4W9p4SSu0eK57EkX1VRalZmntTVEX7nlw7oI6nacW
 8iP7MIqYWdF1QI6n5gDh0i/62/ictOjG2yemooPNh1I5E5Cw+MhOqTZ7gL+nu1M6
 e2+oqo9i3+1yBAN3RH4M8tCwrtTwoVnmQlgPAqT5u2eOATu1b8cTOs2/aC6dfcGg
 3u1hcbXuQKRE4DuT7QhDJN1cQZt/GMdymTkR7xIlVqzmNPkM+DCiWPujVMU7r2ia
 z1Chwxd1gmDrX3g6XPrcXneGrasLkHIRAwYS8EN2wZyNIpb71Y9/uWZVJPza6OO2
 Gdxz/y1vCYUu43FSy+gCCirWW+h/HFc4BEzikvB+splQPSiJWJw/Nol+xkBnPds7
 LjQTpKSXd1nDtDyTsz0nZAp7EEft78Ez2mj4zYNgqZDBXLEiRPES47VEO3Ls9SS4
 t7AtIY1GtdUlFIPrA0mrbcggf/gYxJCFofxR2J7gzyH3DFXIlfw9HbS4+r4xv9RP
 v2wJUwN35y5SJRNymztanArTNPkGXOlcJ3s7nYQk13UQ0hWTtW3e86pMPsi5C3ui
 6DjHG8GXWh4=
 =X+M1
 -----END PGP SIGNATURE-----

Merge tag 'x86-misc-2020-08-03' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 MSR filtering from Ingo Molnar:
 "Filter MSR writes from user-space by default, and print a syslog entry
  if they happen outside the allowed set of MSRs, which is a single one
  for now, MSR_IA32_ENERGY_PERF_BIAS.

  The plan is to eventually disable MSR writes by default (they can
  still be enabled via allow_writes=on)"

* tag 'x86-misc-2020-08-03' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/msr: Filter MSR writes
This commit is contained in:
Linus Torvalds 2020-08-03 17:23:49 -07:00
commit c813e8c9df

View file

@ -42,6 +42,14 @@
static struct class *msr_class;
static enum cpuhp_state cpuhp_msr_state;
enum allow_write_msrs {
MSR_WRITES_ON,
MSR_WRITES_OFF,
MSR_WRITES_DEFAULT,
};
static enum allow_write_msrs allow_writes = MSR_WRITES_DEFAULT;
static ssize_t msr_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
@ -70,6 +78,24 @@ static ssize_t msr_read(struct file *file, char __user *buf,
return bytes ? bytes : err;
}
static int filter_write(u32 reg)
{
switch (allow_writes) {
case MSR_WRITES_ON: return 0;
case MSR_WRITES_OFF: return -EPERM;
default: break;
}
if (reg == MSR_IA32_ENERGY_PERF_BIAS)
return 0;
pr_err_ratelimited("Write to unrecognized MSR 0x%x by %s\n"
"Please report to x86@kernel.org\n",
reg, current->comm);
return 0;
}
static ssize_t msr_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
@ -84,6 +110,10 @@ static ssize_t msr_write(struct file *file, const char __user *buf,
if (err)
return err;
err = filter_write(reg);
if (err)
return err;
if (count % 8)
return -EINVAL; /* Invalid chunk size */
@ -92,9 +122,13 @@ static ssize_t msr_write(struct file *file, const char __user *buf,
err = -EFAULT;
break;
}
add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
err = wrmsr_safe_on_cpu(cpu, reg, data[0], data[1]);
if (err)
break;
tmp += 2;
bytes += 8;
}
@ -242,6 +276,41 @@ static void __exit msr_exit(void)
}
module_exit(msr_exit)
static int set_allow_writes(const char *val, const struct kernel_param *cp)
{
/* val is NUL-terminated, see kernfs_fop_write() */
char *s = strstrip((char *)val);
if (!strcmp(s, "on"))
allow_writes = MSR_WRITES_ON;
else if (!strcmp(s, "off"))
allow_writes = MSR_WRITES_OFF;
else
allow_writes = MSR_WRITES_DEFAULT;
return 0;
}
static int get_allow_writes(char *buf, const struct kernel_param *kp)
{
const char *res;
switch (allow_writes) {
case MSR_WRITES_ON: res = "on"; break;
case MSR_WRITES_OFF: res = "off"; break;
default: res = "default"; break;
}
return sprintf(buf, "%s\n", res);
}
static const struct kernel_param_ops allow_writes_ops = {
.set = set_allow_writes,
.get = get_allow_writes
};
module_param_cb(allow_writes, &allow_writes_ops, NULL, 0600);
MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>");
MODULE_DESCRIPTION("x86 generic MSR driver");
MODULE_LICENSE("GPL");