| From c9fc3f778a6a215ace14ee556067c73982b6d40f Mon Sep 17 00:00:00 2001 |
| From: Borislav Petkov <borislav.petkov@amd.com> |
| Date: Thu, 21 Jun 2012 14:07:16 +0200 |
| Subject: x86, microcode: Sanitize per-cpu microcode reloading interface |
| |
| From: Borislav Petkov <borislav.petkov@amd.com> |
| |
| commit c9fc3f778a6a215ace14ee556067c73982b6d40f upstream. |
| |
| Microcode reloading in a per-core manner is a very bad idea for both |
| major x86 vendors. And the thing is, we have such interface with which |
| we can end up with different microcode versions applied on different |
| cores of an otherwise homogeneous wrt (family,model,stepping) system. |
| |
| So turn off the possibility of doing that per core and allow it only |
| system-wide. |
| |
| This is a minimal fix which we'd like to see in stable too thus the |
| more-or-less arbitrary decision to allow system-wide reloading only on |
| the BSP: |
| |
| $ echo 1 > /sys/devices/system/cpu/cpu0/microcode/reload |
| ... |
| |
| and disable the interface on the other cores: |
| |
| $ echo 1 > /sys/devices/system/cpu/cpu23/microcode/reload |
| -bash: echo: write error: Invalid argument |
| |
| Also, allowing the reload only from one CPU (the BSP in |
| that case) doesn't allow the reload procedure to degenerate |
| into an O(n^2) deal when triggering reloads from all |
| /sys/devices/system/cpu/cpuX/microcode/reload sysfs nodes |
| simultaneously. |
| |
| A more generic fix will follow. |
| |
| Cc: Henrique de Moraes Holschuh <hmh@hmh.eng.br> |
| Cc: Peter Zijlstra <peterz@infradead.org> |
| Signed-off-by: Borislav Petkov <borislav.petkov@amd.com> |
| Link: http://lkml.kernel.org/r/1340280437-7718-2-git-send-email-bp@amd64.org |
| Signed-off-by: H. Peter Anvin <hpa@zytor.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/kernel/microcode_core.c | 26 +++++++++++++++++++------- |
| 1 file changed, 19 insertions(+), 7 deletions(-) |
| |
| --- a/arch/x86/kernel/microcode_core.c |
| +++ b/arch/x86/kernel/microcode_core.c |
| @@ -298,19 +298,31 @@ static ssize_t reload_store(struct devic |
| const char *buf, size_t size) |
| { |
| unsigned long val; |
| - int cpu = dev->id; |
| - ssize_t ret = 0; |
| + int cpu; |
| + ssize_t ret = 0, tmp_ret; |
| + |
| + /* allow reload only from the BSP */ |
| + if (boot_cpu_data.cpu_index != dev->id) |
| + return -EINVAL; |
| |
| ret = kstrtoul(buf, 0, &val); |
| if (ret) |
| return ret; |
| |
| - if (val == 1) { |
| - get_online_cpus(); |
| - if (cpu_online(cpu)) |
| - ret = reload_for_cpu(cpu); |
| - put_online_cpus(); |
| + if (val != 1) |
| + return size; |
| + |
| + get_online_cpus(); |
| + for_each_online_cpu(cpu) { |
| + tmp_ret = reload_for_cpu(cpu); |
| + if (tmp_ret != 0) |
| + pr_warn("Error reloading microcode on CPU %d\n", cpu); |
| + |
| + /* save retval of the first encountered reload error */ |
| + if (!ret) |
| + ret = tmp_ret; |
| } |
| + put_online_cpus(); |
| |
| if (!ret) |
| ret = size; |