All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Stephan Bärwolf" <stephan.baerwolf@tu-ilmenau.de>
To: Marcelo Tosatti <mtosatti@redhat.com>
Cc: kvm@vger.kernel.org
Subject: [PATCH 2/2] KVM: fix missing "illegal instruction"-trap in protected modes
Date: Thu, 12 Jan 2012 16:43:04 +0100	[thread overview]
Message-ID: <4F0EFF88.3040706@tu-ilmenau.de> (raw)
In-Reply-To: <20120112104756.GB31635@amt.cnet>

[-- Attachment #1: Type: text/plain, Size: 7054 bytes --]

>From d62ca9897e9970d777aec1d399318b0df44489bd Mon Sep 17 00:00:00 2001
From: Stephan Baerwolf <stephan.baerwolf@tu-ilmenau.de>
Date: Sun, 8 Jan 2012 02:03:47 +0000
Subject: [PATCH 2/2] KVM: fix missing "illegal instruction"-trap in
protected modes

On hosts without this patch, 32bit guests will crash
(and 64bit guests may behave in a wrong way) for
example by simply executing following nasm-demo-application:

    [bits 32]
    global _start
    SECTION .text
    _start: syscall

(I tested it with winxp and linux - both always crashed)

    Disassembly of section .text:

    00000000 <_start>:
       0:   0f 05                   syscall

The reason seems a missing "invalid opcode"-trap (int6) for the
syscall opcode "0f05", which is not available on Intel CPUs
within non-longmodes, as also on some AMD CPUs within legacy-mode.
(depending on CPU vendor, MSR_EFER and cpuid)

Because previous mentioned OSs may not engage corresponding
syscall target-registers (STAR, LSTAR, CSTAR), they remain
NULL and (non trapping) syscalls are leading to multiple
faults and finally crashs.

Depending on the architecture (AMD or Intel) pretended by
guests, various checks according to vendor's documentation
are implemented to overcome the current issue and behave
like the CPUs physical counterparts.

(Therefore using Intel's "Intel 64 and IA-32 Architecture Software
Developers Manual" http://www.intel.com/content/dam/doc/manual/
64-ia-32-architectures-software-developer-manual-325462.pdf
and AMD's "AMD64 Architecture Programmer's Manual Volume 3:
General-Purpose and System Instructions"
http://support.amd.com/us/Processor_TechDocs/APM_V3_24594.pdf )

Screenshots of an i686 testing VM (CORE i5 host) before
and after applying this patch are available under:

http://matrixstorm.com/software/linux/kvm/20111229/before.jpg
http://matrixstorm.com/software/linux/kvm/20111229/after.jpg

Cc: <stable@vger.kernel.org>
Signed-off-by: Stephan Baerwolf <stephan.baerwolf@tu-ilmenau.de>
---
 arch/x86/include/asm/kvm_emulate.h |   15 +++++++
 arch/x86/kvm/emulate.c             |   80
++++++++++++++++++++++++++++++++++-
 2 files changed, 92 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/kvm_emulate.h
b/arch/x86/include/asm/kvm_emulate.h
index b172bf4..f0da4d9 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -301,6 +301,21 @@ struct x86_emulate_ctxt {
 #define X86EMUL_MODE_PROT     (X86EMUL_MODE_PROT16|X86EMUL_MODE_PROT32| \
                    X86EMUL_MODE_PROT64)
 
+/* CPUID vendors */
+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx 0x68747541
+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx 0x444d4163
+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_edx 0x69746e65
+
+#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx 0x69444d41
+#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx 0x21726574
+#define X86EMUL_CPUID_VENDOR_AMDisbetterI_edx 0x74656273
+
+#define X86EMUL_CPUID_VENDOR_GenuineIntel_ebx 0x756e6547
+#define X86EMUL_CPUID_VENDOR_GenuineIntel_ecx 0x6c65746e
+#define X86EMUL_CPUID_VENDOR_GenuineIntel_edx 0x49656e69
+
+
+
 enum x86_intercept_stage {
     X86_ICTP_NONE = 0,   /* Allow zero-init to not match anything */
     X86_ICPT_PRE_EXCEPT,
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index f1e3be1..29140ae 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1877,6 +1877,82 @@ setup_syscalls_segments(struct x86_emulate_ctxt
*ctxt,
     ss->p = 1;
 }
 
+static bool em_syscall_isenabled(struct x86_emulate_ctxt *ctxt)
+{
+    struct x86_emulate_ops *ops = ctxt->ops;
+    u64 efer = 0;
+
+    /* NO check for lock-prefix here - done in x86_emulate_instruction()*/
+
+    ops->get_msr(ctxt, MSR_EFER, &efer);
+   
+    /* we assume EFER_SCE is unset in REAL and VM86 so with this we     */
+    /* should speedup the #UD case                                      */
+    if ((efer & EFER_SCE) == 0)
+        return false;
+
+    /* syscall should always be enabled in longmode - so only become    */
+    /* vendorspecific (cpuid) if other modes are active...              */
+    if (ctxt->mode != X86EMUL_MODE_PROT64) {
+      bool vendor;
+      u32 eax, ebx, ecx, edx;
+
+      /* syscall is not available in real mode - #UD without cpuid...   */
+      if ((ctxt->mode == X86EMUL_MODE_REAL) ||
+          (ctxt->mode == X86EMUL_MODE_VM86))
+          return false;
+
+      /* getting the cpu-vendor                                         */
+      eax = 0x00000000;
+      ecx = 0x00000000;
+      if (likely(ops->get_cpuid)) {
+          vendor = ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx);
+      }  else vendor = false;
+
+      if (likely(vendor)) {
+       
+        /* Intel ("GenuineIntel")                                       */
+        /* remark: Intel CPUs only support "syscall" in 64bit longmode  */
+        /*         Also an 64bit guest with a 32bit compat-app running  */
+        /*         will #UD !!                                          */
+        /*         While this behaviour can be fixed (by emulating)     */
+        /*         into an AMD response - CPUs of AMD can't behave like */
+        /*         Intel, because without an hardware-raised #UD there  */
+        /*         is no call in em.-mode (see x86_emulate_instruction) */
+        if ((ebx==X86EMUL_CPUID_VENDOR_GenuineIntel_ebx) &&
+            (ecx==X86EMUL_CPUID_VENDOR_GenuineIntel_ecx) &&
+            (edx==X86EMUL_CPUID_VENDOR_GenuineIntel_edx))
+            return false;
+       
+        /* end "Intel" */
+
+       
+        /* AMD ("AuthenticAMD" / "AMDisbetter!")                        */
+        if (((ebx==X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx) &&
+             (ecx==X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx) &&
+             (edx==X86EMUL_CPUID_VENDOR_AuthenticAMD_edx)) ||
+            ((ebx==X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx) &&
+             (ecx==X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx) &&
+             (edx==X86EMUL_CPUID_VENDOR_AMDisbetterI_edx))) {
+
+        goto __em_syscall_enabled_noprotest;
+        } /* end "AMD" */
+
+      } /* end vendor is true */
+     
+     
+      /* default:  (not Intel, not AMD ...)                             */
+      /* this code wasn't able to process vendor                        */
+      /* so apply  Intels stricter rules...                             */
+      pr_err_ratelimited("kvm: %i: unknown vcpu vendor - assuming intel\n",
+                  current->tgid);
+      return false;
+    } /* end "not longmode" */
+
+__em_syscall_enabled_noprotest:
+    return true;
+}
+
 static int em_syscall(struct x86_emulate_ctxt *ctxt)
 {
     struct x86_emulate_ops *ops = ctxt->ops;
@@ -1885,9 +1961,7 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt)
     u16 cs_sel, ss_sel;
     u64 efer = 0;
 
-    /* syscall is not available in real mode */
-    if (ctxt->mode == X86EMUL_MODE_REAL ||
-        ctxt->mode == X86EMUL_MODE_VM86)
+    if (!(em_syscall_isenabled(ctxt)))
         return emulate_ud(ctxt);
 
     ops->get_msr(ctxt, MSR_EFER, &efer);
-- 
1.7.3.4



[-- Attachment #2: 0002-KVM-fix-missing-illegal-instruction-trap-in-protecte.patch --]
[-- Type: text/x-patch, Size: 6781 bytes --]

>From d62ca9897e9970d777aec1d399318b0df44489bd Mon Sep 17 00:00:00 2001
From: Stephan Baerwolf <stephan.baerwolf@tu-ilmenau.de>
Date: Sun, 8 Jan 2012 02:03:47 +0000
Subject: [PATCH 2/2] KVM: fix missing "illegal instruction"-trap in protected modes

On hosts without this patch, 32bit guests will crash
(and 64bit guests may behave in a wrong way) for
example by simply executing following nasm-demo-application:

	[bits 32]
	global _start
	SECTION .text
	_start: syscall

(I tested it with winxp and linux - both always crashed)

	Disassembly of section .text:

	00000000 <_start>:
	   0:   0f 05                   syscall

The reason seems a missing "invalid opcode"-trap (int6) for the
syscall opcode "0f05", which is not available on Intel CPUs
within non-longmodes, as also on some AMD CPUs within legacy-mode.
(depending on CPU vendor, MSR_EFER and cpuid)

Because previous mentioned OSs may not engage corresponding
syscall target-registers (STAR, LSTAR, CSTAR), they remain
NULL and (non trapping) syscalls are leading to multiple
faults and finally crashs.

Depending on the architecture (AMD or Intel) pretended by
guests, various checks according to vendor's documentation
are implemented to overcome the current issue and behave
like the CPUs physical counterparts.

(Therefore using Intel's "Intel 64 and IA-32 Architecture Software
Developers Manual" http://www.intel.com/content/dam/doc/manual/
64-ia-32-architectures-software-developer-manual-325462.pdf
and AMD's "AMD64 Architecture Programmer's Manual Volume 3:
General-Purpose and System Instructions"
http://support.amd.com/us/Processor_TechDocs/APM_V3_24594.pdf )

Screenshots of an i686 testing VM (CORE i5 host) before
and after applying this patch are available under:

http://matrixstorm.com/software/linux/kvm/20111229/before.jpg
http://matrixstorm.com/software/linux/kvm/20111229/after.jpg

Cc: <stable@vger.kernel.org>
Signed-off-by: Stephan Baerwolf <stephan.baerwolf@tu-ilmenau.de>
---
 arch/x86/include/asm/kvm_emulate.h |   15 +++++++
 arch/x86/kvm/emulate.c             |   80 ++++++++++++++++++++++++++++++++++-
 2 files changed, 92 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index b172bf4..f0da4d9 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -301,6 +301,21 @@ struct x86_emulate_ctxt {
 #define X86EMUL_MODE_PROT     (X86EMUL_MODE_PROT16|X86EMUL_MODE_PROT32| \
 			       X86EMUL_MODE_PROT64)
 
+/* CPUID vendors */
+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx 0x68747541
+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx 0x444d4163
+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_edx 0x69746e65
+
+#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx 0x69444d41
+#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx 0x21726574
+#define X86EMUL_CPUID_VENDOR_AMDisbetterI_edx 0x74656273
+
+#define X86EMUL_CPUID_VENDOR_GenuineIntel_ebx 0x756e6547
+#define X86EMUL_CPUID_VENDOR_GenuineIntel_ecx 0x6c65746e
+#define X86EMUL_CPUID_VENDOR_GenuineIntel_edx 0x49656e69
+
+
+
 enum x86_intercept_stage {
 	X86_ICTP_NONE = 0,   /* Allow zero-init to not match anything */
 	X86_ICPT_PRE_EXCEPT,
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index f1e3be1..29140ae 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1877,6 +1877,82 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
 	ss->p = 1;
 }
 
+static bool em_syscall_isenabled(struct x86_emulate_ctxt *ctxt)
+{
+	struct x86_emulate_ops *ops = ctxt->ops;
+	u64 efer = 0;
+
+	/* NO check for lock-prefix here - done in x86_emulate_instruction()*/
+
+	ops->get_msr(ctxt, MSR_EFER, &efer);
+	
+	/* we assume EFER_SCE is unset in REAL and VM86 so with this we     */
+	/* should speedup the #UD case                                      */
+	if ((efer & EFER_SCE) == 0)
+		return false;
+
+	/* syscall should always be enabled in longmode - so only become    */
+	/* vendorspecific (cpuid) if other modes are active...              */
+	if (ctxt->mode != X86EMUL_MODE_PROT64) {
+	  bool vendor;
+	  u32 eax, ebx, ecx, edx;
+
+	  /* syscall is not available in real mode - #UD without cpuid...   */
+	  if ((ctxt->mode == X86EMUL_MODE_REAL) ||
+	      (ctxt->mode == X86EMUL_MODE_VM86))
+		  return false;
+
+	  /* getting the cpu-vendor                                         */
+	  eax = 0x00000000;
+	  ecx = 0x00000000;
+	  if (likely(ops->get_cpuid)) {
+	  	vendor = ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx);
+	  }  else vendor = false;
+
+	  if (likely(vendor)) {
+	    
+	    /* Intel ("GenuineIntel")                                       */
+	    /* remark: Intel CPUs only support "syscall" in 64bit longmode  */
+	    /*         Also an 64bit guest with a 32bit compat-app running  */
+	    /*         will #UD !!                                          */
+	    /*         While this behaviour can be fixed (by emulating)     */
+	    /*         into an AMD response - CPUs of AMD can't behave like */
+	    /*         Intel, because without an hardware-raised #UD there  */
+	    /*         is no call in em.-mode (see x86_emulate_instruction) */
+	    if ((ebx==X86EMUL_CPUID_VENDOR_GenuineIntel_ebx) &&
+	        (ecx==X86EMUL_CPUID_VENDOR_GenuineIntel_ecx) &&
+	        (edx==X86EMUL_CPUID_VENDOR_GenuineIntel_edx)) 
+			return false;
+		
+	    /* end "Intel" */
+
+	    
+	    /* AMD ("AuthenticAMD" / "AMDisbetter!")                        */
+	    if (((ebx==X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx) &&
+	         (ecx==X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx) &&
+	         (edx==X86EMUL_CPUID_VENDOR_AuthenticAMD_edx)) ||
+	        ((ebx==X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx) &&
+	         (ecx==X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx) &&
+	         (edx==X86EMUL_CPUID_VENDOR_AMDisbetterI_edx))) {
+
+		goto __em_syscall_enabled_noprotest;
+	    } /* end "AMD" */
+
+	  } /* end vendor is true */
+	  
+	  
+	  /* default:  (not Intel, not AMD ...)                             */
+	  /* this code wasn't able to process vendor                        */
+	  /* so apply  Intels stricter rules...                             */
+	  pr_err_ratelimited("kvm: %i: unknown vcpu vendor - assuming intel\n",
+			      current->tgid);
+	  return false;
+	} /* end "not longmode" */
+
+__em_syscall_enabled_noprotest:
+	return true;
+}
+
 static int em_syscall(struct x86_emulate_ctxt *ctxt)
 {
 	struct x86_emulate_ops *ops = ctxt->ops;
@@ -1885,9 +1961,7 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt)
 	u16 cs_sel, ss_sel;
 	u64 efer = 0;
 
-	/* syscall is not available in real mode */
-	if (ctxt->mode == X86EMUL_MODE_REAL ||
-	    ctxt->mode == X86EMUL_MODE_VM86)
+	if (!(em_syscall_isenabled(ctxt)))
 		return emulate_ud(ctxt);
 
 	ops->get_msr(ctxt, MSR_EFER, &efer);
-- 
1.7.3.4


      parent reply	other threads:[~2012-01-12 15:44 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-12-29  1:59 KVM guest-kernel panics double fault Stephan Bärwolf
2011-12-29 10:04 ` Avi Kivity
2012-01-08  2:31   ` Stephan Bärwolf
2012-01-08 10:21     ` Avi Kivity
2012-01-10 10:11       ` Stephan Bärwolf
2012-01-10 10:31         ` Avi Kivity
2012-01-10 12:17           ` Stephan Bärwolf
2012-01-10 12:34             ` Avi Kivity
2012-01-10 12:48               ` Stephan Bärwolf
2012-01-10 14:26                 ` [PATCH 0/2] " Stephan Bärwolf
2012-01-10 14:26                 ` [PATCH 1/2] KVM: extend "struct x86_emulate_ops" with "get_cpuid" Stephan Bärwolf
2012-01-10 14:26                 ` [PATCH 2/2] KVM: fix missing "illegal instruction"-trap in protected modes Stephan Bärwolf
2012-01-11 19:09                   ` Marcelo Tosatti
2012-01-11 20:01                     ` Stephan Bärwolf
2012-01-11 21:21                       ` Marcelo Tosatti
2012-01-11 22:19                         ` Stephan Bärwolf
2012-01-12 10:47                           ` Marcelo Tosatti
2012-01-12 15:43                             ` [PATCH 0/2] KVM guest-kernel panics double fault Stephan Bärwolf
2012-01-12 15:56                               ` Jan Kiszka
2012-01-13 10:13                                 ` Marcelo Tosatti
2012-01-15 19:44                                   ` Stephan Bärwolf
2012-01-16  9:58                                     ` Marcelo Tosatti
2012-01-16 11:24                                       ` Stephan Bärwolf
2012-01-12 15:43                             ` [PATCH 1/2] KVM: extend "struct x86_emulate_ops" with "get_cpuid" Stephan Bärwolf
2012-01-12 15:43                             ` Stephan Bärwolf [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4F0EFF88.3040706@tu-ilmenau.de \
    --to=stephan.baerwolf@tu-ilmenau.de \
    --cc=kvm@vger.kernel.org \
    --cc=mtosatti@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.