|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH for-4.22] x86/kexec: Check for a good per-cpu area before accessing IDTs
Prior to commit 9c20d3c5915d ("x86/IDT: Make idt_tables[] be per_cpu(idt)"),
the global idt_tables[] was always safe to use for CPUs in any state.
However, not-yet-onlined CPUs (e.g. MADT with more entries than exist in
practice) or offlined CPUs (e.g. xen-hptool) have their per-cpu pointer
poisoned to detect incorrect uses. machine_kexec() trips over the posion when
clobbering #MC entry paths.
This fixes a fatal #GP (non-canonical memory reference) when trying to enter
the crash kernel.
Fixes: 9c20d3c5915d ("x86/IDT: Make idt_tables[] be per_cpu(idt)")
Reported-by: Lin Liu <Lin.Liu01@xxxxxxxxxx>
Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
---
CC: Jan Beulich <jbeulich@xxxxxxxx>
CC: Roger Pau Monné <roger.pau@xxxxxxxxxx>
CC: Teddy Astie <teddy.astie@xxxxxxxxxx>
CC: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>
CC: Lin Liu <Lin.Liu01@xxxxxxxxxx>
The fix here is a bit ugly. nmi_shootdown_cpus() uses the cpu_online_map but
this is wrong too; it misses parked CPUs, which do want to be captured.
For 4.22. This is the minimal fix to stop systems crashing, but more work is
needed to make this path fully robust.
---
xen/arch/x86/machine_kexec.c | 8 +++++++-
xen/common/percpu.c | 1 -
xen/include/xen/percpu.h | 1 +
3 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/xen/arch/x86/machine_kexec.c b/xen/arch/x86/machine_kexec.c
index f921eec5aae6..0f5437cb65cc 100644
--- a/xen/arch/x86/machine_kexec.c
+++ b/xen/arch/x86/machine_kexec.c
@@ -18,6 +18,7 @@
#include <xen/domain_page.h>
#include <xen/elfstructs.h>
#include <xen/kexec.h>
+#include <xen/percpu.h>
#include <xen/types.h>
#include <asm/fixmap.h>
@@ -171,7 +172,12 @@ void machine_kexec(struct kexec_image *image)
*/
for ( i = 0; i < nr_cpu_ids; i++ )
{
- idt_entry_t *idt = per_cpu(idt, i);
+ idt_entry_t *idt;
+
+ if ( __per_cpu_offset[i] == INVALID_PERCPU_AREA )
+ continue;
+
+ idt = per_cpu(idt, i);
if ( !idt )
continue;
diff --git a/xen/common/percpu.c b/xen/common/percpu.c
index cdd70acbeaf3..f180f37253ed 100644
--- a/xen/common/percpu.c
+++ b/xen/common/percpu.c
@@ -13,7 +13,6 @@
#define PERCPU_ORDER get_order_from_bytes(__per_cpu_data_end - __per_cpu_start)
-extern char __per_cpu_start[];
extern const char __per_cpu_data_end[];
unsigned long __read_mostly __per_cpu_offset[NR_CPUS];
diff --git a/xen/include/xen/percpu.h b/xen/include/xen/percpu.h
index fcf2095bd543..30609f49f0b3 100644
--- a/xen/include/xen/percpu.h
+++ b/xen/include/xen/percpu.h
@@ -43,6 +43,7 @@
#endif
extern unsigned long __per_cpu_offset[];
+extern char __per_cpu_start[];
#define per_cpu(var, cpu) \
(*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))
base-commit: 6a21252a742ec021a814e124b88d273da37065db
--
2.39.5
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |