From: Kees Cook Date: Fri, 8 Feb 2013 01:01:21 +0000 (-0800) Subject: CHERRY-PICK: CHROMIUM: msr: whitelist the i915 thermal control for wrmsr X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=707220d357ec1ca1c94e51a0f49ccfe5f44596b6;p=people%2Faperard%2Flinux-chromebook.git CHERRY-PICK: CHROMIUM: msr: whitelist the i915 thermal control for wrmsr Deny all userspace MSR writes except those explicitly whitelisted for i915 thermal controls. Without this, processes with CAP_SYS_RAWIO can run arbitrary kernel code via MSR writing. BUG=chromium-os:38756 TEST=link build, wrmsr works only on i915 thermal registers Signed-off-by: Kees Cook Reviewed-on: https://gerrit.chromium.org/gerrit/42910 Reviewed-by: Mandeep Singh Baines Change-Id: Iaba154c76d48414633a4df8d07fe94b2a5e81a90 (cherry picked from ToT commit 3b16706f52c471365ed9a391c4803fd7cfcb0c0d) Signed-off-by: Kees Cook Reviewed-on: https://gerrit.chromium.org/gerrit/43573 Reviewed-by: Sameer Nanda Reviewed-by: Mandeep Singh Baines --- diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c index 8563b64e18cf7..d475a901c2704 100644 --- a/arch/x86/kernel/msr.c +++ b/arch/x86/kernel/msr.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -93,6 +94,28 @@ static ssize_t msr_read(struct file *file, char __user *buf, return bytes ? bytes : err; } +/* + * TODO(keescook): This check should just return -EPERM for all registers. + * crosbug.com/38756 + */ +static int msr_write_allowed(u32 reg) +{ + switch (reg) { + case 0x19a: + case 0x610: + case 0x64c: + /* Allowed: i915 thermal controls. */ + return 0; + default: + break; + } + + /* Everything else: denied. */ + printk_ratelimited(KERN_ERR "msr: write denied: register 0x%x " \ + "not whitelisted by driver.\n", reg); + return -EPERM; +} + static ssize_t msr_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { @@ -105,6 +128,9 @@ static ssize_t msr_write(struct file *file, const char __user *buf, if (count % 8) return -EINVAL; /* Invalid chunk size */ + err = msr_write_allowed(reg); + if (err) + return err; for (; count; count -= 8) { if (copy_from_user(&data, tmp, 8)) { @@ -154,6 +180,9 @@ static long msr_ioctl(struct file *file, unsigned int ioc, unsigned long arg) err = -EFAULT; break; } + err = msr_write_allowed(regs[1]); + if (err) + break; err = wrmsr_safe_regs_on_cpu(cpu, regs); if (err) break;