[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 |