diff mbox

[Utopic,SRU] x86: kvm: use alternatives for VMCALL vs. VMMCALL if kernel text is read-only

Message ID 1417037064-3973-2-git-send-email-chris.j.arges@canonical.com
State New
Headers show

Commit Message

Chris J Arges Nov. 26, 2014, 9:24 p.m. UTC
From: Paolo Bonzini <pbonzini@redhat.com>

BugLink: http://bugs.launchpad.net/bugs/1379340

On x86_64, kernel text mappings are mapped read-only with CONFIG_DEBUG_RODATA.
In that case, KVM will fail to patch VMCALL instructions to VMMCALL
as required on AMD processors.

The failure mode is currently a divide-by-zero exception, which obviously
is a KVM bug that has to be fixed.  However, picking the right instruction
between VMCALL and VMMCALL will be faster and will help if you cannot upgrade
the hypervisor.

Reported-by: Chris Webb <chris@arachsys.com>
Tested-by: Chris Webb <chris@arachsys.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: x86@kernel.org
Acked-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit c1118b3602c2329671ad5ec8bdf8e374323d6343)
Signed-off-by: Chris J Arges <chris.j.arges@canonical.com>

Conflicts:
	arch/x86/include/asm/cpufeature.h
---
 arch/x86/include/asm/cpufeature.h |  1 +
 arch/x86/include/asm/kvm_para.h   | 10 ++++++++--
 arch/x86/kernel/cpu/amd.c         |  7 +++++++
 3 files changed, 16 insertions(+), 2 deletions(-)

Comments

Stefan Bader Nov. 27, 2014, 9:41 a.m. UTC | #1
On 26.11.2014 22:24, Chris J Arges wrote:
> From: Paolo Bonzini <pbonzini@redhat.com>
> 
> BugLink: http://bugs.launchpad.net/bugs/1379340
> 
> On x86_64, kernel text mappings are mapped read-only with CONFIG_DEBUG_RODATA.
> In that case, KVM will fail to patch VMCALL instructions to VMMCALL
> as required on AMD processors.
> 
> The failure mode is currently a divide-by-zero exception, which obviously
> is a KVM bug that has to be fixed.  However, picking the right instruction
> between VMCALL and VMMCALL will be faster and will help if you cannot upgrade
> the hypervisor.
> 
> Reported-by: Chris Webb <chris@arachsys.com>
> Tested-by: Chris Webb <chris@arachsys.com>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: "H. Peter Anvin" <hpa@zytor.com>
> Cc: x86@kernel.org
> Acked-by: Borislav Petkov <bp@suse.de>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> (cherry picked from commit c1118b3602c2329671ad5ec8bdf8e374323d6343)

Nitpick: in the emails sent to stable you say only v3.17 does cherry-pick and
provide backports for older kernels. So would this and the Trusty one not be
"backported"?

Also in the bug report I saw you could reproduce this but the final comment
sounds not like you did actively verify the solution. You surely did that,
didn't you?

-Stefan

> Signed-off-by: Chris J Arges <chris.j.arges@canonical.com>
> 
> Conflicts:
> 	arch/x86/include/asm/cpufeature.h
> ---
>  arch/x86/include/asm/cpufeature.h |  1 +
>  arch/x86/include/asm/kvm_para.h   | 10 ++++++++--
>  arch/x86/kernel/cpu/amd.c         |  7 +++++++
>  3 files changed, 16 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
> index e265ff9..51f7550 100644
> --- a/arch/x86/include/asm/cpufeature.h
> +++ b/arch/x86/include/asm/cpufeature.h
> @@ -203,6 +203,7 @@
>  #define X86_FEATURE_DECODEASSISTS (8*32+12) /* AMD Decode Assists support */
>  #define X86_FEATURE_PAUSEFILTER (8*32+13) /* AMD filtered pause intercept */
>  #define X86_FEATURE_PFTHRESHOLD (8*32+14) /* AMD pause filter threshold */
> +#define X86_FEATURE_VMMCALL     ( 8*32+15) /* Prefer vmmcall to vmcall */
>  
>  
>  /* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */
> diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h
> index c7678e4..e62cf89 100644
> --- a/arch/x86/include/asm/kvm_para.h
> +++ b/arch/x86/include/asm/kvm_para.h
> @@ -2,6 +2,7 @@
>  #define _ASM_X86_KVM_PARA_H
>  
>  #include <asm/processor.h>
> +#include <asm/alternative.h>
>  #include <uapi/asm/kvm_para.h>
>  
>  extern void kvmclock_init(void);
> @@ -16,10 +17,15 @@ static inline bool kvm_check_and_clear_guest_paused(void)
>  }
>  #endif /* CONFIG_KVM_GUEST */
>  
> -/* This instruction is vmcall.  On non-VT architectures, it will generate a
> - * trap that we will then rewrite to the appropriate instruction.
> +#ifdef CONFIG_DEBUG_RODATA
> +#define KVM_HYPERCALL \
> +        ALTERNATIVE(".byte 0x0f,0x01,0xc1", ".byte 0x0f,0x01,0xd9", X86_FEATURE_VMMCALL)
> +#else
> +/* On AMD processors, vmcall will generate a trap that we will
> + * then rewrite to the appropriate instruction.
>   */
>  #define KVM_HYPERCALL ".byte 0x0f,0x01,0xc1"
> +#endif
>  
>  /* For KVM hypercalls, a three-byte sequence of either the vmcall or the vmmcall
>   * instruction.  The hypervisor may replace it with something else but only the
> diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
> index ce8b8ff..edefaca 100644
> --- a/arch/x86/kernel/cpu/amd.c
> +++ b/arch/x86/kernel/cpu/amd.c
> @@ -506,6 +506,13 @@ static void early_init_amd(struct cpuinfo_x86 *c)
>  	}
>  #endif
>  
> +	/*
> +	 * This is only needed to tell the kernel whether to use VMCALL
> +	 * and VMMCALL.  VMMCALL is never executed except under virt, so
> +	 * we can set it unconditionally.
> +	 */
> +	set_cpu_cap(c, X86_FEATURE_VMMCALL);
> +
>  	/* F16h erratum 793, CVE-2013-6885 */
>  	if (c->x86 == 0x16 && c->x86_model <= 0xf)
>  		msr_set_bit(MSR_AMD64_LS_CFG, 15);
>
Andy Whitcroft Nov. 27, 2014, 11:38 a.m. UTC | #2
On Wed, Nov 26, 2014 at 03:24:24PM -0600, Chris J Arges wrote:
> From: Paolo Bonzini <pbonzini@redhat.com>
> 
> BugLink: http://bugs.launchpad.net/bugs/1379340
> 
> On x86_64, kernel text mappings are mapped read-only with CONFIG_DEBUG_RODATA.
> In that case, KVM will fail to patch VMCALL instructions to VMMCALL
> as required on AMD processors.
> 
> The failure mode is currently a divide-by-zero exception, which obviously
> is a KVM bug that has to be fixed.  However, picking the right instruction
> between VMCALL and VMMCALL will be faster and will help if you cannot upgrade
> the hypervisor.
> 
> Reported-by: Chris Webb <chris@arachsys.com>
> Tested-by: Chris Webb <chris@arachsys.com>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: "H. Peter Anvin" <hpa@zytor.com>
> Cc: x86@kernel.org
> Acked-by: Borislav Petkov <bp@suse.de>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> (cherry picked from commit c1118b3602c2329671ad5ec8bdf8e374323d6343)

This is definatly "backported from" as there is a minor spacing change in
the context.  That said it is a very minor context change so the working
payload is unchanged.  Applier should fix that to backported though.

> Signed-off-by: Chris J Arges <chris.j.arges@canonical.com>
> 
> Conflicts:
> 	arch/x86/include/asm/cpufeature.h
> ---
>  arch/x86/include/asm/cpufeature.h |  1 +
>  arch/x86/include/asm/kvm_para.h   | 10 ++++++++--
>  arch/x86/kernel/cpu/amd.c         |  7 +++++++
>  3 files changed, 16 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
> index e265ff9..51f7550 100644
> --- a/arch/x86/include/asm/cpufeature.h
> +++ b/arch/x86/include/asm/cpufeature.h
> @@ -203,6 +203,7 @@
>  #define X86_FEATURE_DECODEASSISTS (8*32+12) /* AMD Decode Assists support */
>  #define X86_FEATURE_PAUSEFILTER (8*32+13) /* AMD filtered pause intercept */
>  #define X86_FEATURE_PFTHRESHOLD (8*32+14) /* AMD pause filter threshold */
> +#define X86_FEATURE_VMMCALL     ( 8*32+15) /* Prefer vmmcall to vmcall */
>  
>  
>  /* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */
> diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h
> index c7678e4..e62cf89 100644
> --- a/arch/x86/include/asm/kvm_para.h
> +++ b/arch/x86/include/asm/kvm_para.h
> @@ -2,6 +2,7 @@
>  #define _ASM_X86_KVM_PARA_H
>  
>  #include <asm/processor.h>
> +#include <asm/alternative.h>
>  #include <uapi/asm/kvm_para.h>
>  
>  extern void kvmclock_init(void);
> @@ -16,10 +17,15 @@ static inline bool kvm_check_and_clear_guest_paused(void)
>  }
>  #endif /* CONFIG_KVM_GUEST */
>  
> -/* This instruction is vmcall.  On non-VT architectures, it will generate a
> - * trap that we will then rewrite to the appropriate instruction.
> +#ifdef CONFIG_DEBUG_RODATA
> +#define KVM_HYPERCALL \
> +        ALTERNATIVE(".byte 0x0f,0x01,0xc1", ".byte 0x0f,0x01,0xd9", X86_FEATURE_VMMCALL)
> +#else
> +/* On AMD processors, vmcall will generate a trap that we will
> + * then rewrite to the appropriate instruction.
>   */
>  #define KVM_HYPERCALL ".byte 0x0f,0x01,0xc1"
> +#endif
>  
>  /* For KVM hypercalls, a three-byte sequence of either the vmcall or the vmmcall
>   * instruction.  The hypervisor may replace it with something else but only the
> diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
> index ce8b8ff..edefaca 100644
> --- a/arch/x86/kernel/cpu/amd.c
> +++ b/arch/x86/kernel/cpu/amd.c
> @@ -506,6 +506,13 @@ static void early_init_amd(struct cpuinfo_x86 *c)
>  	}
>  #endif
>  
> +	/*
> +	 * This is only needed to tell the kernel whether to use VMCALL
> +	 * and VMMCALL.  VMMCALL is never executed except under virt, so
> +	 * we can set it unconditionally.
> +	 */
> +	set_cpu_cap(c, X86_FEATURE_VMMCALL);
> +
>  	/* F16h erratum 793, CVE-2013-6885 */
>  	if (c->x86 == 0x16 && c->x86_model <= 0xf)
>  		msr_set_bit(MSR_AMD64_LS_CFG, 15);
> -- 

Looks to do waht is claimed, can really only affect KVM and should be
trivially testable if soneone has AMD and Intel h/w to test.  Therefore:

Acked-by: Andy Whitcroft <apw@canonical.com>

-apw
Andy Whitcroft Nov. 27, 2014, 11:43 a.m. UTC | #3
Applied to Utopic.

I changed this to be marked as a backport on application.

-apw
diff mbox

Patch

diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index e265ff9..51f7550 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -203,6 +203,7 @@ 
 #define X86_FEATURE_DECODEASSISTS (8*32+12) /* AMD Decode Assists support */
 #define X86_FEATURE_PAUSEFILTER (8*32+13) /* AMD filtered pause intercept */
 #define X86_FEATURE_PFTHRESHOLD (8*32+14) /* AMD pause filter threshold */
+#define X86_FEATURE_VMMCALL     ( 8*32+15) /* Prefer vmmcall to vmcall */
 
 
 /* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */
diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h
index c7678e4..e62cf89 100644
--- a/arch/x86/include/asm/kvm_para.h
+++ b/arch/x86/include/asm/kvm_para.h
@@ -2,6 +2,7 @@ 
 #define _ASM_X86_KVM_PARA_H
 
 #include <asm/processor.h>
+#include <asm/alternative.h>
 #include <uapi/asm/kvm_para.h>
 
 extern void kvmclock_init(void);
@@ -16,10 +17,15 @@  static inline bool kvm_check_and_clear_guest_paused(void)
 }
 #endif /* CONFIG_KVM_GUEST */
 
-/* This instruction is vmcall.  On non-VT architectures, it will generate a
- * trap that we will then rewrite to the appropriate instruction.
+#ifdef CONFIG_DEBUG_RODATA
+#define KVM_HYPERCALL \
+        ALTERNATIVE(".byte 0x0f,0x01,0xc1", ".byte 0x0f,0x01,0xd9", X86_FEATURE_VMMCALL)
+#else
+/* On AMD processors, vmcall will generate a trap that we will
+ * then rewrite to the appropriate instruction.
  */
 #define KVM_HYPERCALL ".byte 0x0f,0x01,0xc1"
+#endif
 
 /* For KVM hypercalls, a three-byte sequence of either the vmcall or the vmmcall
  * instruction.  The hypervisor may replace it with something else but only the
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index ce8b8ff..edefaca 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -506,6 +506,13 @@  static void early_init_amd(struct cpuinfo_x86 *c)
 	}
 #endif
 
+	/*
+	 * This is only needed to tell the kernel whether to use VMCALL
+	 * and VMMCALL.  VMMCALL is never executed except under virt, so
+	 * we can set it unconditionally.
+	 */
+	set_cpu_cap(c, X86_FEATURE_VMMCALL);
+
 	/* F16h erratum 793, CVE-2013-6885 */
 	if (c->x86 == 0x16 && c->x86_model <= 0xf)
 		msr_set_bit(MSR_AMD64_LS_CFG, 15);