|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH RFC v3 3/6] 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.
Changed since v2
----------------
* Coding style: Added space after if, for, etc.
* hvm_deprivileged_user_mode() now returns a value to indicate success or
failure.
---
xen/arch/x86/hvm/deprivileged.c | 70 +++++++++++++++++++++++++++++++++++++-
xen/arch/x86/traps.c | 55 ++++++++++++++++++++++++++++++
xen/include/xen/hvm/deprivileged.h | 25 +++++++++++++-
3 files changed, 148 insertions(+), 2 deletions(-)
diff --git a/xen/arch/x86/hvm/deprivileged.c b/xen/arch/x86/hvm/deprivileged.c
index 5574c50..68c40ad 100644
--- a/xen/arch/x86/hvm/deprivileged.c
+++ b/xen/arch/x86/hvm/deprivileged.c
@@ -560,7 +560,7 @@ void hvm_deprivileged_destroy_vcpu(struct vcpu *vcpu)
* This method is then jumped into to restore execution context after
* exiting user mode.
*/
-void hvm_deprivileged_user_mode(void)
+int hvm_deprivileged_user_mode(void)
{
struct vcpu *vcpu = get_current();
@@ -576,6 +576,20 @@ void hvm_deprivileged_user_mode(void)
vcpu->arch.hvm_vcpu.depriv_user_mode = 0;
vcpu->arch.hvm_vcpu.depriv_rsp = 0;
+
+ /*
+ * If we need to crash the domain at this point. We will return up the call
+ * stack, undoing any allocations and then the event testers in the exit
+ * assembly stubs will test for the SOFTIRQ_TIMER event generated by a
+ * domain_crash and will crash the domain for us.
+ */
+ if ( vcpu->arch.hvm_vcpu.depriv_destroy )
+ {
+ domain_crash(vcpu->domain);
+ return 1;
+ }
+
+ return 0;
}
/*
@@ -639,3 +653,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..f14a845 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,13 @@ 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(__func__) )
+ return;
+
trace_pv_trap(trapnr, regs->eip, use_error_code, regs->error_code);
tb = &v->arch.pv_vcpu.trap_bounce;
@@ -617,6 +625,13 @@ static void do_trap(struct cpu_user_regs *regs, int
use_error_code)
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(__func__) )
+ return;
+
if ( guest_mode(regs) )
{
do_guest_trap(trapnr, regs, use_error_code);
@@ -1070,6 +1085,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 +1181,13 @@ 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 +1524,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 +3259,13 @@ 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 +3531,13 @@ 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 +3579,13 @@ 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/include/xen/hvm/deprivileged.h
b/xen/include/xen/hvm/deprivileged.h
index 5915224..b6e575d 100644
--- a/xen/include/xen/hvm/deprivileged.h
+++ b/xen/include/xen/hvm/deprivileged.h
@@ -84,7 +84,7 @@ int hvm_deprivileged_prepare_vcpu(struct vcpu *vcpu);
void hvm_deprivileged_destroy_vcpu(struct vcpu *vcpu);
/* Called to perform a user mode operation. */
-void hvm_deprivileged_user_mode(void);
+int hvm_deprivileged_user_mode(void);
/* Called when the user mode operation has completed */
void hvm_deprivileged_finish_user_mode(void);
@@ -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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |