[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH RFC v2 3/4] HVM x86 deprivileged mode: Trap handlers for deprivileged mode



Added trap handlers to catch exceptions such as a page fault, general
protection fault, etc. These handlers will crash the domain as such exceptions
would indicate that either there is a bug in deprivileged mode or it has been
compromised by an attacker.

On calling a domain_crash() whilst in deprivileged mode, we need to restore
the host's context so that we do not have guest-defined registers and values
in use after this point due to lazy loading of these values in the SVM and VMX
implementations.

Signed-off-by: Ben Catterall <Ben.Catterall@xxxxxxxxxx>

Changed since v1
----------------
 * Changed to domain_crash(), domain_crash_synchronous was used previously.
 * Updated to perform a HVM context switch on crashing a domain
 * Updated hvm_deprivileged_check_trap() to return a testable error
   code and return based on this.
---
 xen/arch/x86/hvm/deprivileged.c    | 54 ++++++++++++++++++++++++++++++++++++++
 xen/arch/x86/traps.c               | 48 +++++++++++++++++++++++++++++++++
 xen/arch/x86/x86_64/traps.c        |  1 -
 xen/include/xen/hvm/deprivileged.h | 23 ++++++++++++++++
 4 files changed, 125 insertions(+), 1 deletion(-)

diff --git a/xen/arch/x86/hvm/deprivileged.c b/xen/arch/x86/hvm/deprivileged.c
index 994c19e..01efbe1 100644
--- a/xen/arch/x86/hvm/deprivileged.c
+++ b/xen/arch/x86/hvm/deprivileged.c
@@ -615,3 +615,57 @@ void hvm_deprivileged_finish_user_mode(void)
 
     hvm_deprivileged_finish_user_mode_asm();
 }
+
+/* Check if we are in deprivileged mode */
+int is_hvm_deprivileged_vcpu(void)
+{
+    struct vcpu *v = get_current();
+
+    if( is_hvm_vcpu(v) && (v->arch.hvm_vcpu.depriv_user_mode) )
+        return 1;
+
+    return 0;
+}
+
+/*
+ * Crash the domain. This should not be called if there are any memory
+ * allocations which will be freed by code following its invocation in the
+ * current execution context (current stack). This is because it causes a
+ * permanent 'context switch' and the current stack will be cloberred so
+ * any allocations made which are not freed by other paths will leak.
+ * This function should only be used after deprivileged mode has been
+ * successfully switched into, otherwise, the normal domain_crash function
+ * should be used.
+ *
+ * The domain which is crashed is that of the current vcpu.
+ *
+ * To crash the domain, we need to return to our privileged stack as we may 
have
+ * memory allocations which need to be cleaned up. Then, after we have returned
+ * to this stack, we can then crash the domain. We set a flag which we check
+ * when returning.
+ */
+void hvm_deprivileged_crash_domain(const char *reason)
+{
+    struct vcpu *vcpu = get_current();
+
+    vcpu->arch.hvm_vcpu.depriv_destroy = 1;
+
+    printk(XENLOG_ERR "HVM Deprivileged Mode: Crashing domain. Reason: %s\n",
+           reason);
+
+    /*
+     * Restore the processor's state. We need to do the privileged return
+     * path to undo any allocations that got us to this state
+     */
+    hvm_deprivileged_finish_user_mode();
+    /* DOES NOT RETURN */
+}
+
+/* Handle a trap event */
+int hvm_deprivileged_check_trap(const char* func_name)
+{
+    if( is_hvm_deprivileged_vcpu() )
+        hvm_deprivileged_crash_domain(func_name);
+
+    return 0;
+}
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 9f5a6c6..df89aa9 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -74,6 +74,7 @@
 #include <asm/vpmu.h>
 #include <public/arch-x86/cpuid.h>
 #include <xsm/xsm.h>
+#include <xen/hvm/deprivileged.h>
 
 /*
  * opt_nmi: one of 'ignore', 'dom0', or 'fatal'.
@@ -500,6 +501,12 @@ static void do_guest_trap(
     struct trap_bounce *tb;
     const struct trap_info *ti;
 
+    /* If we take the trap whilst in HVM deprivileged mode
+     * then we should crash the domain.
+     */
+    if( hvm_deprivileged_check_trap(__FUNCTION__) )
+        return;
+
     trace_pv_trap(trapnr, regs->eip, use_error_code, regs->error_code);
 
     tb = &v->arch.pv_vcpu.trap_bounce;
@@ -616,6 +623,11 @@ static void do_trap(struct cpu_user_regs *regs, int 
use_error_code)
     unsigned long fixup;
 
     DEBUGGER_trap_entry(trapnr, regs);
+    /* If we take the trap whilst in HVM deprivileged mode
+     * then we should crash the domain.
+     */
+    if( hvm_deprivileged_check_trap(__FUNCTION__) )
+        return;
 
     if ( guest_mode(regs) )
     {
@@ -1070,6 +1082,13 @@ void do_invalid_op(struct cpu_user_regs *regs)
 
     DEBUGGER_trap_entry(TRAP_invalid_op, regs);
 
+    /*
+     * If we take the trap whilst in HVM deprivileged mode
+     * then we should crash the domain.
+     */
+    if( hvm_deprivileged_check_trap(__func__) )
+        return;
+
     if ( likely(guest_mode(regs)) )
     {
         if ( !emulate_invalid_rdtscp(regs) &&
@@ -1159,6 +1178,12 @@ void do_int3(struct cpu_user_regs *regs)
 {
     DEBUGGER_trap_entry(TRAP_int3, regs);
 
+    /* If we take the trap whilst in HVM deprivileged mode
+     * then we should crash the domain.
+     */
+    if( hvm_deprivileged_check_trap(__func__) )
+        return;
+
     if ( !guest_mode(regs) )
     {
         debugger_trap_fatal(TRAP_int3, regs);
@@ -1495,9 +1520,14 @@ void do_page_fault(struct cpu_user_regs *regs)
 
     perfc_incr(page_faults);
 
+    /* If we get a page fault whilst in HVM deprivileged mode */
+    if( hvm_deprivileged_check_trap(__func__) )
+        return;
+
     if ( unlikely(fixup_page_fault(addr, regs) != 0) )
         return;
 
+
     if ( unlikely(!guest_mode(regs)) )
     {
         pf_type = spurious_page_fault(addr, regs);
@@ -3225,6 +3255,12 @@ void do_general_protection(struct cpu_user_regs *regs)
 
     DEBUGGER_trap_entry(TRAP_gp_fault, regs);
 
+    /* If we take the trap whilst in HVM deprivileged mode
+     * then we should crash the domain.
+     */
+    if( hvm_deprivileged_check_trap(__func__) )
+        return;
+
     if ( regs->error_code & 1 )
         goto hardware_gp;
 
@@ -3490,6 +3526,12 @@ void do_device_not_available(struct cpu_user_regs *regs)
 
     BUG_ON(!guest_mode(regs));
 
+    /* If we take the trap whilst in HVM deprivileged mode
+     * then we should crash the domain.
+     */
+    if( hvm_deprivileged_check_trap(__func__) )
+        return;
+
     vcpu_restore_fpu_lazy(curr);
 
     if ( curr->arch.pv_vcpu.ctrlreg[0] & X86_CR0_TS )
@@ -3531,6 +3573,12 @@ void do_debug(struct cpu_user_regs *regs)
 
     DEBUGGER_trap_entry(TRAP_debug, regs);
 
+    /* If we take the trap whilst in HVM deprivileged mode
+     * then we should crash the domain.
+     */
+    if( hvm_deprivileged_check_trap(__func__) )
+        return;
+
     if ( !guest_mode(regs) )
     {
         if ( regs->eflags & X86_EFLAGS_TF )
diff --git a/xen/arch/x86/x86_64/traps.c b/xen/arch/x86/x86_64/traps.c
index c7e6077..3bbfc9c 100644
--- a/xen/arch/x86/x86_64/traps.c
+++ b/xen/arch/x86/x86_64/traps.c
@@ -26,7 +26,6 @@
 #include <public/callback.h>
 #include <asm/hvm/svm/svm.h>
 
-
 static void print_xen_info(void)
 {
     char taint_str[TAINT_STRING_MAX_LEN];
diff --git a/xen/include/xen/hvm/deprivileged.h 
b/xen/include/xen/hvm/deprivileged.h
index 2571108..9c08adf 100644
--- a/xen/include/xen/hvm/deprivileged.h
+++ b/xen/include/xen/hvm/deprivileged.h
@@ -106,9 +106,32 @@ void hvm_deprivileged_setup_stacks(unsigned long 
stack_ptr);
 /* Use to restore the stacks for deprivileged mode */
 void hvm_deprivileged_restore_stacks(void);
 
+/* Check if we are in deprivileged mode */
+int is_hvm_deprivileged_vcpu(void);
+
 /* The ring 3 code */
 void hvm_deprivileged_ring3(void);
 
+/*
+ * Crash the domain. This should not be called if there are any memory
+ * allocations which will be freed by code following its invocation in the
+ * current execution context (current stack). This is because it causes a
+ * permanent 'context switch' and the current stack will be cloberred so
+ * any allocations made which are not freed by other paths will leak.
+ * This function should only be used after deprivileged mode has been
+ * successfully switched into, otherwise, the normal domain_crash function
+ * should be used.
+ *
+ * The domain which is crashed is that of the current vcpu.
+ */
+void hvm_deprivileged_crash_domain(const char *reason);
+
+/*
+ * Call when inside a trap that should cause a domain crash if in user mode
+ * e.g. an invalid_op is trapped whilst in user mode.
+ */
+int hvm_deprivileged_check_trap(const char* func_name);
+
 /* The segments where the user mode .text and .data are stored */
 extern unsigned long __hvm_deprivileged_text_start[];
 extern unsigned long __hvm_deprivileged_text_end[];
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.