Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBorislav Petkov <bp@suse.de>2018-01-12 21:55:29 +0100
committerBorislav Petkov <bp@suse.de>2018-01-12 21:55:40 +0100
commitf1b5a9fc9ab8cdc78f1557d57e2f25de726539d1 (patch)
tree4b21e15eaf19052f1cd0258c818c4fd5921307af
parent08a3e10a4d8d624031155f8eac892ba439d75757 (diff)
x86/virt, x86/platform: Merge 'struct x86_hyper' into 'struct
x86_platform' and 'struct x86_init' (bsc#1068032 CVE-2017-5754).
-rw-r--r--patches.arch/24-x86-virt-x86-platform-merge-struct-x86_hyper-into-struct-x86_platform-and-struct-x86_init.patch373
-rw-r--r--series.conf1
2 files changed, 374 insertions, 0 deletions
diff --git a/patches.arch/24-x86-virt-x86-platform-merge-struct-x86_hyper-into-struct-x86_platform-and-struct-x86_init.patch b/patches.arch/24-x86-virt-x86-platform-merge-struct-x86_hyper-into-struct-x86_platform-and-struct-x86_init.patch
new file mode 100644
index 0000000000..e9b197fb92
--- /dev/null
+++ b/patches.arch/24-x86-virt-x86-platform-merge-struct-x86_hyper-into-struct-x86_platform-and-struct-x86_init.patch
@@ -0,0 +1,373 @@
+From: Juergen Gross <jgross@suse.com>
+Date: Thu, 9 Nov 2017 14:27:35 +0100
+Subject: x86/virt, x86/platform: Merge 'struct x86_hyper' into 'struct
+ x86_platform' and 'struct x86_init'
+Git-commit: f72e38e8ec8869ac0ba5a75d7d2f897d98a1454e
+Patch-mainline: v4.15-rc1
+References: bsc#1068032 CVE-2017-5754
+
+Instead of x86_hyper being either NULL on bare metal or a pointer to a
+struct hypervisor_x86 in case of the kernel running as a guest merge
+the struct into x86_platform and x86_init.
+
+This will remove the need for wrappers making it hard to find out what
+is being called. With dummy functions added for all callbacks testing
+for a NULL function pointer can be removed, too.
+
+Suggested-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Acked-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: akataria@vmware.com
+Cc: boris.ostrovsky@oracle.com
+Cc: devel@linuxdriverproject.org
+Cc: haiyangz@microsoft.com
+Cc: kvm@vger.kernel.org
+Cc: kys@microsoft.com
+Cc: pbonzini@redhat.com
+Cc: rkrcmar@redhat.com
+Cc: rusty@rustcorp.com.au
+Cc: sthemmin@microsoft.com
+Cc: virtualization@lists.linux-foundation.org
+Cc: xen-devel@lists.xenproject.org
+Link: http://lkml.kernel.org/r/20171109132739.23465-2-jgross@suse.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Acked-by: Borislav Petkov <bp@suse.de>
+---
+ arch/x86/include/asm/hypervisor.h | 25 +++-------------
+ arch/x86/include/asm/x86_init.h | 24 ++++++++++++++++
+ arch/x86/kernel/apic/apic.c | 2 -
+ arch/x86/kernel/cpu/hypervisor.c | 56 ++++++++++++++++++--------------------
+ arch/x86/kernel/cpu/mshyperv.c | 2 -
+ arch/x86/kernel/cpu/vmware.c | 4 +-
+ arch/x86/kernel/kvm.c | 2 -
+ arch/x86/kernel/x86_init.c | 9 ++++++
+ arch/x86/mm/init.c | 2 -
+ arch/x86/xen/enlighten_hvm.c | 8 ++---
+ arch/x86/xen/enlighten_pv.c | 2 -
+ include/linux/hypervisor.h | 8 ++++-
+ 12 files changed, 82 insertions(+), 62 deletions(-)
+
+--- a/arch/x86/include/asm/hypervisor.h
++++ b/arch/x86/include/asm/hypervisor.h
+@@ -23,6 +23,7 @@
+ #ifdef CONFIG_HYPERVISOR_GUEST
+
+ #include <asm/kvm_para.h>
++#include <asm/x86_init.h>
+ #include <asm/xen/hypervisor.h>
+
+ /*
+@@ -35,17 +36,11 @@ struct hypervisor_x86 {
+ /* Detection routine */
+ uint32_t (*detect)(void);
+
+- /* Platform setup (run once per boot) */
+- void (*init_platform)(void);
++ /* init time callbacks */
++ struct x86_hyper_init init;
+
+- /* X2APIC detection (run once per boot) */
+- bool (*x2apic_available)(void);
+-
+- /* pin current vcpu to specified physical cpu (run rarely) */
+- void (*pin_vcpu)(int);
+-
+- /* called during init_mem_mapping() to setup early mappings. */
+- void (*init_mem_mapping)(void);
++ /* runtime callbacks */
++ struct x86_hyper_runtime runtime;
+ };
+
+ extern const struct hypervisor_x86 *x86_hyper;
+@@ -58,17 +53,7 @@ extern const struct hypervisor_x86 x86_h
+ extern const struct hypervisor_x86 x86_hyper_kvm;
+
+ extern void init_hypervisor_platform(void);
+-extern bool hypervisor_x2apic_available(void);
+-extern void hypervisor_pin_vcpu(int cpu);
+-
+-static inline void hypervisor_init_mem_mapping(void)
+-{
+- if (x86_hyper && x86_hyper->init_mem_mapping)
+- x86_hyper->init_mem_mapping();
+-}
+ #else
+ static inline void init_hypervisor_platform(void) { }
+-static inline bool hypervisor_x2apic_available(void) { return false; }
+-static inline void hypervisor_init_mem_mapping(void) { }
+ #endif /* CONFIG_HYPERVISOR_GUEST */
+ #endif /* _ASM_X86_HYPERVISOR_H */
+--- a/arch/x86/include/asm/x86_init.h
++++ b/arch/x86/include/asm/x86_init.h
+@@ -114,6 +114,18 @@ struct x86_init_pci {
+ };
+
+ /**
++ * struct x86_hyper_init - x86 hypervisor init functions
++ * @init_platform: platform setup
++ * @x2apic_available: X2APIC detection
++ * @init_mem_mapping: setup early mappings during init_mem_mapping()
++ */
++struct x86_hyper_init {
++ void (*init_platform)(void);
++ bool (*x2apic_available)(void);
++ void (*init_mem_mapping)(void);
++};
++
++/**
+ * struct x86_init_ops - functions for platform specific setup
+ *
+ */
+@@ -126,6 +138,7 @@ struct x86_init_ops {
+ struct x86_init_timers timers;
+ struct x86_init_iommu iommu;
+ struct x86_init_pci pci;
++ struct x86_hyper_init hyper;
+ };
+
+ /**
+@@ -199,6 +212,15 @@ struct x86_legacy_features {
+ };
+
+ /**
++ * struct x86_hyper_runtime - x86 hypervisor specific runtime callbacks
++ *
++ * @pin_vcpu: pin current vcpu to specified physical cpu (run rarely)
++ */
++struct x86_hyper_runtime {
++ void (*pin_vcpu)(int cpu);
++};
++
++/**
+ * struct x86_platform_ops - platform specific runtime functions
+ * @calibrate_cpu: calibrate CPU
+ * @calibrate_tsc: calibrate TSC, if different from CPU
+@@ -217,6 +239,7 @@ struct x86_legacy_features {
+ * possible in x86_early_init_platform_quirks() by
+ * only using the current x86_hardware_subarch
+ * semantics.
++ * @hyper: x86 hypervisor specific runtime callbacks
+ */
+ struct x86_platform_ops {
+ unsigned long (*calibrate_cpu)(void);
+@@ -232,6 +255,7 @@ struct x86_platform_ops {
+ void (*apic_post_init)(void);
+ struct x86_legacy_features legacy;
+ void (*set_legacy_features)(void);
++ struct x86_hyper_runtime hyper;
+ };
+
+ struct pci_dev;
+--- a/arch/x86/kernel/apic/apic.c
++++ b/arch/x86/kernel/apic/apic.c
+@@ -1573,7 +1573,7 @@ static __init void try_to_enable_x2apic(
+ * under KVM
+ */
+ if (max_physical_apicid > 255 ||
+- !hypervisor_x2apic_available()) {
++ !x86_init.hyper.x2apic_available()) {
+ pr_info("x2apic: IRQ remapping doesn't support X2APIC mode\n");
+ x2apic_disable();
+ return;
+--- a/arch/x86/kernel/cpu/hypervisor.c
++++ b/arch/x86/kernel/cpu/hypervisor.c
+@@ -44,51 +44,49 @@ static const __initconst struct hypervis
+ const struct hypervisor_x86 *x86_hyper;
+ EXPORT_SYMBOL(x86_hyper);
+
+-static inline void __init
++static inline const struct hypervisor_x86 * __init
+ detect_hypervisor_vendor(void)
+ {
+- const struct hypervisor_x86 *h, * const *p;
++ const struct hypervisor_x86 *h = NULL, * const *p;
+ uint32_t pri, max_pri = 0;
+
+ for (p = hypervisors; p < hypervisors + ARRAY_SIZE(hypervisors); p++) {
+- h = *p;
+- pri = h->detect();
+- if (pri != 0 && pri > max_pri) {
++ pri = (*p)->detect();
++ if (pri > max_pri) {
+ max_pri = pri;
+- x86_hyper = h;
++ h = *p;
+ }
+ }
+
+- if (max_pri)
+- pr_info("Hypervisor detected: %s\n", x86_hyper->name);
+-}
+-
+-void __init init_hypervisor_platform(void)
+-{
+-
+- detect_hypervisor_vendor();
++ if (h)
++ pr_info("Hypervisor detected: %s\n", h->name);
+
+- if (!x86_hyper)
+- return;
+-
+- if (x86_hyper->init_platform)
+- x86_hyper->init_platform();
++ return h;
+ }
+
+-bool __init hypervisor_x2apic_available(void)
++static void __init copy_array(const void *src, void *target, unsigned int size)
+ {
+- return x86_hyper &&
+- x86_hyper->x2apic_available &&
+- x86_hyper->x2apic_available();
++ unsigned int i, n = size / sizeof(void *);
++ const void * const *from = (const void * const *)src;
++ const void **to = (const void **)target;
++
++ for (i = 0; i < n; i++)
++ if (from[i])
++ to[i] = from[i];
+ }
+
+-void hypervisor_pin_vcpu(int cpu)
++void __init init_hypervisor_platform(void)
+ {
+- if (!x86_hyper)
++ const struct hypervisor_x86 *h;
++
++ h = detect_hypervisor_vendor();
++
++ if (!h)
+ return;
+
+- if (x86_hyper->pin_vcpu)
+- x86_hyper->pin_vcpu(cpu);
+- else
+- WARN_ONCE(1, "vcpu pinning requested but not supported!\n");
++ copy_array(&h->init, &x86_init.hyper, sizeof(h->init));
++ copy_array(&h->runtime, &x86_platform.hyper, sizeof(h->runtime));
++
++ x86_hyper = h;
++ x86_init.hyper.init_platform();
+ }
+--- a/arch/x86/kernel/cpu/mshyperv.c
++++ b/arch/x86/kernel/cpu/mshyperv.c
+@@ -262,6 +262,6 @@ static void __init ms_hyperv_init_platfo
+ const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
+ .name = "Microsoft Hyper-V",
+ .detect = ms_hyperv_platform,
+- .init_platform = ms_hyperv_init_platform,
++ .init.init_platform = ms_hyperv_init_platform,
+ };
+ EXPORT_SYMBOL(x86_hyper_ms_hyperv);
+--- a/arch/x86/kernel/cpu/vmware.c
++++ b/arch/x86/kernel/cpu/vmware.c
+@@ -208,7 +208,7 @@ static bool __init vmware_legacy_x2apic_
+ const __refconst struct hypervisor_x86 x86_hyper_vmware = {
+ .name = "VMware",
+ .detect = vmware_platform,
+- .init_platform = vmware_platform_setup,
+- .x2apic_available = vmware_legacy_x2apic_available,
++ .init.init_platform = vmware_platform_setup,
++ .init.x2apic_available = vmware_legacy_x2apic_available,
+ };
+ EXPORT_SYMBOL(x86_hyper_vmware);
+--- a/arch/x86/kernel/kvm.c
++++ b/arch/x86/kernel/kvm.c
+@@ -569,7 +569,7 @@ static uint32_t __init kvm_detect(void)
+ const struct hypervisor_x86 x86_hyper_kvm __refconst = {
+ .name = "KVM",
+ .detect = kvm_detect,
+- .x2apic_available = kvm_para_available,
++ .init.x2apic_available = kvm_para_available,
+ };
+ EXPORT_SYMBOL_GPL(x86_hyper_kvm);
+
+--- a/arch/x86/kernel/x86_init.c
++++ b/arch/x86/kernel/x86_init.c
+@@ -28,6 +28,8 @@ void x86_init_noop(void) { }
+ void __init x86_init_uint_noop(unsigned int unused) { }
+ int __init iommu_init_noop(void) { return 0; }
+ void iommu_shutdown_noop(void) { }
++bool __init bool_x86_init_noop(void) { return false; }
++void x86_op_int_noop(int cpu) { }
+
+ /*
+ * The platform setup functions are preset with the default functions
+@@ -81,6 +83,12 @@ struct x86_init_ops x86_init __initdata
+ .init_irq = x86_default_pci_init_irq,
+ .fixup_irqs = x86_default_pci_fixup_irqs,
+ },
++
++ .hyper = {
++ .init_platform = x86_init_noop,
++ .x2apic_available = bool_x86_init_noop,
++ .init_mem_mapping = x86_init_noop,
++ },
+ };
+
+ struct x86_cpuinit_ops x86_cpuinit = {
+@@ -101,6 +109,7 @@ struct x86_platform_ops x86_platform __r
+ .get_nmi_reason = default_get_nmi_reason,
+ .save_sched_clock_state = tsc_save_sched_clock_state,
+ .restore_sched_clock_state = tsc_restore_sched_clock_state,
++ .hyper.pin_vcpu = x86_op_int_noop,
+ };
+
+ EXPORT_SYMBOL_GPL(x86_platform);
+--- a/arch/x86/mm/init.c
++++ b/arch/x86/mm/init.c
+@@ -637,7 +637,7 @@ void __init init_mem_mapping(void)
+ load_cr3(swapper_pg_dir);
+ __flush_tlb_all();
+
+- hypervisor_init_mem_mapping();
++ x86_init.hyper.init_mem_mapping();
+
+ early_memtest(0, max_pfn_mapped << PAGE_SHIFT);
+ }
+--- a/arch/x86/xen/enlighten_hvm.c
++++ b/arch/x86/xen/enlighten_hvm.c
+@@ -238,9 +238,9 @@ static uint32_t __init xen_platform_hvm(
+ const struct hypervisor_x86 x86_hyper_xen_hvm = {
+ .name = "Xen HVM",
+ .detect = xen_platform_hvm,
+- .init_platform = xen_hvm_guest_init,
+- .pin_vcpu = xen_pin_vcpu,
+- .x2apic_available = xen_x2apic_para_available,
+- .init_mem_mapping = xen_hvm_init_mem_mapping,
++ .init.init_platform = xen_hvm_guest_init,
++ .init.x2apic_available = xen_x2apic_para_available,
++ .init.init_mem_mapping = xen_hvm_init_mem_mapping,
++ .runtime.pin_vcpu = xen_pin_vcpu,
+ };
+ EXPORT_SYMBOL(x86_hyper_xen_hvm);
+--- a/arch/x86/xen/enlighten_pv.c
++++ b/arch/x86/xen/enlighten_pv.c
+@@ -1521,6 +1521,6 @@ static uint32_t __init xen_platform_pv(v
+ const struct hypervisor_x86 x86_hyper_xen_pv = {
+ .name = "Xen PV",
+ .detect = xen_platform_pv,
+- .pin_vcpu = xen_pin_vcpu,
++ .runtime.pin_vcpu = xen_pin_vcpu,
+ };
+ EXPORT_SYMBOL(x86_hyper_xen_pv);
+--- a/include/linux/hypervisor.h
++++ b/include/linux/hypervisor.h
+@@ -6,8 +6,12 @@
+ * Juergen Gross <jgross@suse.com>
+ */
+
+-#ifdef CONFIG_HYPERVISOR_GUEST
+-#include <asm/hypervisor.h>
++#ifdef CONFIG_X86
++#include <asm/x86_init.h>
++static inline void hypervisor_pin_vcpu(int cpu)
++{
++ x86_platform.hyper.pin_vcpu(cpu);
++}
+ #else
+ static inline void hypervisor_pin_vcpu(int cpu)
+ {
diff --git a/series.conf b/series.conf
index 55851734db..4241f8f8ad 100644
--- a/series.conf
+++ b/series.conf
@@ -7395,6 +7395,7 @@
patches.arch/21-x86-entry-clean-up-the-sysenter_stack-code.patch
patches.arch/22-x86-entry-64-make-cpu_entry_area-tss-read-only.patch
patches.arch/23-x86-paravirt-dont-patch-flush_tlb_single.patch
+ patches.arch/24-x86-virt-x86-platform-merge-struct-x86_hyper-into-struct-x86_platform-and-struct-x86_init.patch
########################################################
# Staging tree patches