From: Kyle Hale Date: Wed, 18 May 2011 23:14:43 +0000 (-0500) Subject: added ability to inject an env variable into guest user process X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=commitdiff_plain;h=dc6b47d05e37e6c3738e1bc6165ec4a107717d2b;hp=f08319bfe39e47f1d2e003b48087affa7190c997;p=palacios.git added ability to inject an env variable into guest user process --- diff --git a/Kconfig b/Kconfig index 4241627..3c98783 100644 --- a/Kconfig +++ b/Kconfig @@ -178,14 +178,41 @@ config INSPECTOR help Enable inspection framework for vm internal state -config SYSCALL_HIJACK - bool "Enable System Call Interposition" +config SW_INTERRUPTS + bool "Enable interception and hooking of software interrupts" depends on EXPERIMENTAL default n help + This feature will cause the VMM to intercept the execution + of software interrupts (i.e. the INTn instruction) and enable + any INT vector to be hooked + +config SWINTR_PASSTHROUGH + bool "Hook all unhandled sofware interrupts for passthrough" + depends on SW_INTERRUPTS + default n + help + If enabled, this will cause all software interrupts + (INT instruction vectors) to be hooked for passthrough. + May reduce performance but useful for debugging. + +config SYSCALL_HIJACK + bool "Enable System Call Hijacking" + depends on SW_INTERRUPTS + default n + help Enable the VMM to hijack system calls executed by the guest. - If enabled, the VMM will intercept software interrupt (INT) instructions, - Fast-System Call instructions (SYSENTER, SYSCALL), and the LIDT instruction + If enabled, the VMM will hook execution of INT 80 + (support for Fast-System Calls coming soon) + +config SYSCALL_PASSTHROUGH + bool "Hook all unhandled system calls for passthrough" + depends on SYSCALL_HIJACK + default n + help + If enabled, this option will cause all system calls + that are not explicitly hooked to be hooked for + passthrough. This is useful for debugging. config HIJACK_SYSCALL_MSR bool "Intercept Syscall-related MSR reads & writes" @@ -427,13 +454,14 @@ config DEBUG_VNET Enable the Vnet debug in Palacios config DEBUG_SYSCALL_HIJACK - bool "Enable Syscall hijack Debug in Palacios" + bool "Enable Syscall Hijack Debug in Palacios" default n - depends on EXPERIMENTAL && SYSCALL_HIJACK && DEBUG_ON + depends on DEBUG_ON && SYSCALL_HIJACK help Enable Debugging printouts for syscall hijacking code in Palacios + endmenu diff --git a/palacios/include/palacios/vm_guest.h b/palacios/include/palacios/vm_guest.h index 5d4527f..b427f5a 100644 --- a/palacios/include/palacios/vm_guest.h +++ b/palacios/include/palacios/vm_guest.h @@ -50,6 +50,10 @@ struct v3_sym_core_state; #endif +#ifdef CONFIG_SYSCALL_HIJACK +#include +#endif + #include @@ -90,6 +94,11 @@ struct guest_info { /* This structure is how we get exceptions for the guest */ struct v3_excp_state excp_state; +#ifdef CONFIG_SYSCALL_HIJACK + struct v3_syscall_hook_map sc_hook_map; + struct v3_execve_varchunk var_dump; +#endif + v3_cpu_mode_t cpu_mode; v3_mem_mode_t mem_mode; diff --git a/palacios/include/palacios/vm_guest_mem.h b/palacios/include/palacios/vm_guest_mem.h index db6a6a0..6d983ae 100644 --- a/palacios/include/palacios/vm_guest_mem.h +++ b/palacios/include/palacios/vm_guest_mem.h @@ -99,6 +99,9 @@ int v3_hva_to_gva(struct guest_info * guest_info, addr_t host_va, addr_t * gues +// KCH +// Check if pte for this gva has certain permissions +int v3_gva_can_access(struct guest_info * core, addr_t gva); diff --git a/palacios/include/palacios/vmm_intr.h b/palacios/include/palacios/vmm_intr.h index 8a63383..62c8667 100644 --- a/palacios/include/palacios/vmm_intr.h +++ b/palacios/include/palacios/vmm_intr.h @@ -41,6 +41,13 @@ struct v3_irq_hook { void * priv_data; }; +// KCH +struct v3_swintr_hook { + int (*handler)(struct guest_info * core, uint8_t vector, void * priv_data); + void * priv_data; +}; + + #define MAX_IRQ 256 @@ -58,9 +65,10 @@ struct v3_intr_core_state { uint_t irq_started; uint_t irq_vector; - // KCH - uint_t sw_intr_pending; - uint_t sw_intr_vector; + // KCH: for injecting SW Interrupts + uint_t swintr_posted; + uint_t swintr_vector; + struct v3_swintr_hook * swintr_hooks[256]; uint8_t virq_map[MAX_IRQ / 8]; @@ -83,7 +91,6 @@ int v3_lower_virq(struct guest_info * info, int irq); int v3_raise_irq(struct v3_vm_info * vm, int irq); int v3_lower_irq(struct v3_vm_info * vm, int irq); -int v3_signal_sw_intr(struct guest_info * core, int vec); struct intr_ctrl_ops { @@ -99,7 +106,6 @@ struct intr_router_ops { void v3_clear_pending_intr(struct guest_info * core); - void * v3_register_intr_controller(struct guest_info * info, struct intr_ctrl_ops * ops, void * priv_data); void * v3_register_intr_router(struct v3_vm_info * vm, struct intr_router_ops * ops, void * priv_data); @@ -118,7 +124,6 @@ int v3_injecting_intr(struct guest_info * info, uint_t intr_num, v3_intr_type_t */ - int v3_hook_irq(struct v3_vm_info * vm, uint_t irq, int (*handler)(struct v3_vm_info * vm, struct v3_interrupt * intr, void * priv_data), @@ -127,6 +132,16 @@ int v3_hook_irq(struct v3_vm_info * vm, int v3_hook_passthrough_irq(struct v3_vm_info * vm, uint_t irq); +int v3_hook_swintr(struct guest_info * core, + uint8_t vector, + int (*handler)(struct guest_info * core, uint8_t vector, void * priv_data), + void * priv_data); + +int v3_hook_passthrough_swintr(struct guest_info * core, uint8_t vector); + + +int v3_signal_swintr(struct guest_info * core, int vec); +int v3_handle_swintr(struct guest_info * core); #endif // !__V3VEE__ diff --git a/palacios/src/palacios/Makefile b/palacios/src/palacios/Makefile index 6a24b89..3bb87a6 100644 --- a/palacios/src/palacios/Makefile +++ b/palacios/src/palacios/Makefile @@ -75,6 +75,8 @@ obj-$(CONFIG_SYMBIOTIC) += vmm_symbiotic.o vmm_symspy.o obj-$(CONFIG_SYMCALL) += vmm_symcall.o obj-$(CONFIG_SYMMOD) += vmm_symmod.o -obj-$(CONFIG_SYSCALL_HIJACK) += vmm_syscall_hijack.o +obj-$(CONFIG_SYSCALL_HIJACK) += vmm_syscall_hijack.o +obj-$(CONFIG_SYSCALL_HIJACK) += linux_32_syscalls.o +obj-$(CONFIG_SYSCALL_HIJACK) += linux_64_syscalls.o obj-y += mmu/ diff --git a/palacios/src/palacios/svm.c b/palacios/src/palacios/svm.c index 59af9a7..6f160c7 100644 --- a/palacios/src/palacios/svm.c +++ b/palacios/src/palacios/svm.c @@ -135,9 +135,8 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * core) { ctrl_area->instrs.PAUSE = 1; ctrl_area->instrs.shutdown_evts = 1; - /* KCH: intercept writes to IDTR and SW Interrupts (INT) */ -#ifdef CONFIG_SYSCALL_HIJACK - ctrl_area->instrs.WR_IDTR = 0; + /* KCH: intercept SW Interrupts (INT instr) */ +#ifdef CONFIG_SW_INTERRUPTS ctrl_area->instrs.INTn = 1; #endif @@ -230,7 +229,7 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * core) { core); #ifdef CONFIG_HIJACK_MSR - /* KCH: for syscall interposition */ + /* KCH: for syscall hijacking */ v3_hook_msr(core->vm_info, STAR_MSR, &v3_handle_star_read, &v3_handle_star_write, @@ -445,15 +444,20 @@ static int update_irq_entry_state(struct guest_info * info) { guest_ctrl->EVENTINJ.type = SVM_INJECTION_NMI; break; case V3_SOFTWARE_INTR: { - PrintDebug("KCH: Caught an injected software interrupt\n"); - PrintDebug("\ttype: %d, vector: %d\n", SVM_INJECTION_SOFT_INTR, info->intr_core_state.sw_intr_vector); +#ifdef CONFIG_DEBUG_INTERRUPTS + PrintDebug("Caught an injected software interrupt\n"); + PrintDebug("\ttype: %d, vector: %d\n", SVM_INJECTION_SOFT_INTR, info->intr_core_state.swintr_vector); +#endif guest_ctrl->EVENTINJ.type = SVM_INJECTION_SOFT_INTR; - guest_ctrl->EVENTINJ.vector = info->intr_core_state.sw_intr_vector; + guest_ctrl->EVENTINJ.vector = info->intr_core_state.swintr_vector; guest_ctrl->EVENTINJ.valid = 1; - // clear out stuff? - info->intr_core_state.sw_intr_pending = 0; - info->intr_core_state.sw_intr_vector = 0; + /* reset the software interrupt state. + we can do this because we know only one + sw int can be posted at a time on a given + core, unlike irqs */ + info->intr_core_state.swintr_posted = 0; + info->intr_core_state.swintr_vector = 0; break; } case V3_VIRTUAL_IRQ: diff --git a/palacios/src/palacios/svm_handler.c b/palacios/src/palacios/svm_handler.c index 62fe695..8822116 100644 --- a/palacios/src/palacios/svm_handler.c +++ b/palacios/src/palacios/svm_handler.c @@ -194,26 +194,15 @@ int v3_handle_svm_exit(struct guest_info * info, addr_t exit_code, addr_t exit_i } break; } -#ifdef CONFIG_SYSCALL_HIJACK - case VMEXIT_IDTR_WRITE: // KCH: syscall interposition -#ifdef CONFIG_DEBUG_SYSCALL_HIJACK - PrintDebug("IDTR Write\n"); -#endif - if (v3_handle_idtr_write(info) == -1) { - PrintError("Error handling IDTR write\n"); - return -1; - } - break; case VMEXIT_SWINT: -#ifdef CONFIG_DEBUG_SYSCALL_HIJACK - PrintDebug("Intercepting SW Interrupt\n"); +#ifdef CONFIG_DEBUG_INTERRUPTS + PrintDebug("Intercepted SW Interrupt\n"); #endif - if (v3_handle_swint(info) == -1) { + if (v3_handle_swintr(info) == -1) { PrintError("Error handling software interrupt\n"); return -1; } break; -#endif case VMEXIT_INVLPG: if (info->shdw_pg_mode == SHADOW_PAGING) { #ifdef CONFIG_DEBUG_SHADOW_PAGING diff --git a/palacios/src/palacios/vm_guest.c b/palacios/src/palacios/vm_guest.c index 4ab0134..5281dd4 100644 --- a/palacios/src/palacios/vm_guest.c +++ b/palacios/src/palacios/vm_guest.c @@ -31,6 +31,10 @@ #include #include +#ifdef CONFIG_SYSCALL_HIJACK +#include +#endif + v3_cpu_mode_t v3_get_vm_cpu_mode(struct guest_info * info) { @@ -678,6 +682,16 @@ int v3_init_core(struct guest_info * core) { v3_init_symbiotic_core(core); #endif +/* KCH: Hook INT 80 + not sure about this location though...*/ +#ifdef CONFIG_SYSCALL_HIJACK + v3_hook_swintr(core, 0x80, v3_syscall_handler, NULL); + /* hook a poll syscall */ + //v3_hook_syscall(core, 5, v3_sysopen_handler, NULL); + //v3_hook_syscall(core, 21, v3_sysmount_handler, NULL); + v3_hook_syscall(core, 11, v3_sysexecve_handler, NULL); +#endif + // init SVM/VMX diff --git a/palacios/src/palacios/vm_guest_mem.c b/palacios/src/palacios/vm_guest_mem.c index ca6c601..0fd6075 100644 --- a/palacios/src/palacios/vm_guest_mem.c +++ b/palacios/src/palacios/vm_guest_mem.c @@ -168,15 +168,15 @@ int v3_gva_to_gpa(struct guest_info * guest_info, addr_t gva, addr_t * gpa) { switch (guest_info->cpu_mode) { case PROTECTED: if (v3_translate_guest_pt_32(guest_info, guest_cr3, gva, gpa) == -1) { - PrintDebug("Could not translate addr (%p) through 32 bit guest PT at %p\n", - (void *)gva, (void *)(addr_t)guest_cr3); + /*PrintDebug("Could not translate addr (%p) through 32 bit guest PT at %p\n", + (void *)gva, (void *)(addr_t)guest_cr3);*/ return -1; } break; case PROTECTED_PAE: if (v3_translate_guest_pt_32pae(guest_info, guest_cr3, gva, gpa) == -1) { - PrintDebug("Could not translate addr (%p) through 32 bitpae guest PT at %p\n", - (void *)gva, (void *)(addr_t)guest_cr3); + /*PrintDebug("Could not translate addr (%p) through 32 bitpae guest PT at %p\n", + (void *)gva, (void *)(addr_t)guest_cr3);*/ return -1; } break; @@ -184,8 +184,8 @@ int v3_gva_to_gpa(struct guest_info * guest_info, addr_t gva, addr_t * gpa) { case LONG_32_COMPAT: case LONG_16_COMPAT: if (v3_translate_guest_pt_64(guest_info, guest_cr3, gva, gpa) == -1) { - PrintDebug("Could not translate addr (%p) through 64 bit guest PT at %p\n", - (void *)gva, (void *)(addr_t)guest_cr3); + /*PrintDebug("Could not translate addr (%p) through 64 bit guest PT at %p\n", + (void *)gva, (void *)(addr_t)guest_cr3);*/ return -1; } break; @@ -266,8 +266,8 @@ int v3_gva_to_hva(struct guest_info * guest_info, addr_t gva, addr_t * hva) { *hva = 0; if (v3_gva_to_gpa(guest_info, gva, &gpa) != 0) { - PrintError("In GVA->HVA: Invalid GVA(%p)->GPA lookup\n", - (void *)gva); + /*PrintError("In GVA->HVA: Invalid GVA(%p)->GPA lookup\n", + (void *)gva);*/ return -1; } @@ -317,6 +317,56 @@ int v3_hva_to_gva(struct guest_info * guest_info, addr_t hva, addr_t * gva) { +/* KCH: currently only checks if we can perform a user-mode write + return 1 on success */ +int v3_gva_can_access(struct guest_info * core, addr_t gva) { + + v3_reg_t guest_cr3 = 0; + pf_error_t access_type; + pt_access_status_t access_status; + + access_type.write = 1; + access_type.user = 1; + + if (core->mem_mode == PHYSICAL_MEM) { + return -1; + } + + if (core->shdw_pg_mode == SHADOW_PAGING) { + guest_cr3 = core->shdw_pg_state.guest_cr3; + } else { + guest_cr3 = core->ctrl_regs.cr3; + } + + // guest is in paged mode + switch (core->cpu_mode) { + case PROTECTED: + if (v3_check_guest_pt_32(core, guest_cr3, gva, access_type, &access_status) == -1) { + return -1; + } + break; + case PROTECTED_PAE: + if (v3_check_guest_pt_32pae(core, guest_cr3, gva, access_type, &access_status) == -1) { + return -1; + } + break; + case LONG: + case LONG_32_COMPAT: + case LONG_16_COMPAT: + if (v3_check_guest_pt_64(core, guest_cr3, gva, access_type, &access_status) == -1) { + return -1; + } + break; + default: + return -1; + } + + if (access_status != PT_ACCESS_OK) { + return 0; + } else { + return 1; + } +} diff --git a/palacios/src/palacios/vmm_intr.c b/palacios/src/palacios/vmm_intr.c index 0c0a677..101663b 100644 --- a/palacios/src/palacios/vmm_intr.c +++ b/palacios/src/palacios/vmm_intr.c @@ -25,6 +25,8 @@ #include #include +#include +#include #ifndef CONFIG_DEBUG_INTERRUPTS #undef PrintDebug @@ -167,7 +169,7 @@ void v3_remove_intr_router(struct v3_vm_info * vm, void * handle) { static inline struct v3_irq_hook * get_irq_hook(struct v3_vm_info * vm, uint_t irq) { - V3_ASSERT(irq <= 256); + V3_ASSERT(irq <= 255); return vm->intr_routers.hooks[irq]; } @@ -294,14 +296,138 @@ int v3_raise_irq(struct v3_vm_info * vm, int irq) { } -int v3_signal_sw_intr(struct guest_info * core, int vec) { +int v3_signal_swintr(struct guest_info * core, int vector) { struct v3_intr_core_state * intr_state = &(core->intr_core_state); - PrintDebug("KCH: Signalling a software interrupt in vmm_intr.c\n"); - PrintDebug("\tINT vector: %d\n", vec); + PrintDebug("Signaling software interrupt in vmm_intr.c\n"); + PrintDebug("\tINT vector: %d\n", vector); - intr_state->sw_intr_pending = 1; - intr_state->sw_intr_vector = vec; + intr_state->swintr_posted = 1; + intr_state->swintr_vector = vector; + return 0; +} + + +int v3_handle_swintr(struct guest_info * core) { + + int ret = 0; + void * instr_ptr = NULL; + struct x86_instr instr; + + if (core->mem_mode == PHYSICAL_MEM) { + ret = v3_gpa_to_hva(core, get_addr_linear(core, core->rip, &(core->segments.cs)), (addr_t *)&instr_ptr); + } else { + ret = v3_gva_to_hva(core, get_addr_linear(core, core->rip, &(core->segments.cs)), (addr_t *)&instr_ptr); + } + + if (ret == -1) { + PrintError("V3 Syscall Hijack: Could not translate Instruction Address (%p)\n", (void *)core->rip); + return -1; + } + + if (v3_decode(core, (addr_t)instr_ptr, &instr) == -1) { + PrintError("V3 Syscall Hijack: Decoding Error\n"); + return -1; + } + + uint8_t vector = instr.dst_operand.operand; + + //PrintDebug("KCH: SWINT\n"); + //PrintDebug("KCH: Data - %x\n",*((uint32_t*)instr_ptr)); + //PrintDebug("\t RIP: %llx CS: %x\n", core->rip, core->segments.cs.selector); + //PrintDebug("KCH: Disassembling\n\t"); + //addr_t rip = (addr_t) core->rip; + //v3_disasm(core, instr_ptr, &rip, 1); + + //v3_print_instr(&instr); + // only consider system calls + + /* + if (vector == 0x80) { + print_syscall(0, core); + } + */ + + struct v3_swintr_hook * hook = core->intr_core_state.swintr_hooks[vector]; + if (hook == NULL) { +#ifdef CONFIG_SWINTR_PASSTHROUGH + if (v3_hook_passthrough_swintr(core, vector) == -1) { + PrintDebug("Error hooking passthrough swintr\n"); + return -1; + } + hook = core->intr_core_state.swintr_hooks[vector]; +#else + core->rip += instr.instr_length; + return v3_signal_swintr(core, vector); +#endif + } + + ret = hook->handler(core, vector, NULL); + if (ret == -1) { + PrintDebug("V3 SWINT Handler: Error in swint hook\n"); + return -1; + } + + /* make software interrupts prioritized so they finish in time for the next + instruction?? */ + core->rip += instr.instr_length; + return v3_signal_swintr(core, vector); +} + + +static inline struct v3_swintr_hook * get_swintr_hook(struct guest_info * core, uint8_t vector) { + return core->intr_core_state.swintr_hooks[vector]; +} + + +int v3_hook_swintr(struct guest_info * core, + uint8_t vector, + int (*handler)(struct guest_info * core, uint8_t vector, void * priv_data), + void * priv_data) +{ + + struct v3_swintr_hook * hook = (struct v3_swintr_hook *)V3_Malloc(sizeof(struct v3_swintr_hook)); + + if (hook == NULL) { + return -1; + } + + if (get_swintr_hook(core, vector) != NULL) { + PrintError("SWINT %d already hooked\n", vector); + return -1; + } + + hook->handler = handler; + hook->priv_data = priv_data; + + core->intr_core_state.swintr_hooks[vector] = hook; + + return 0; +} + + +static int passthrough_swintr_handler(struct guest_info * core, uint8_t vector, void * priv_data) { + + PrintDebug("[passthrough_swint_handler] INT vector=%d (guest=0x%p)\n", + vector, (void *)core); + + return 0; +} + + +int v3_hook_passthrough_swintr(struct guest_info * core, uint8_t vector) { + + int rc = v3_hook_swintr(core, vector, passthrough_swintr_handler, NULL); + + if (rc) { + PrintError("guest_swintr_injection: failed to hook swint 0x%x (guest=0x%p)\n", vector, (void *)core); + return -1; + } else { + PrintDebug("guest_swintr_injection: hooked swint 0x%x (guest=0x%p)\n", vector, (void *)core); + return 0; + } + + /* shouldn't get here */ return 0; } @@ -339,12 +465,11 @@ v3_intr_type_t v3_intr_pending(struct guest_info * info) { } } - // KCH: not sure about this - if (intr_state->sw_intr_pending == 1) { + // KCH + if (intr_state->swintr_posted == 1) { ret = V3_SOFTWARE_INTR; } - v3_unlock_irqrestore(intr_state->irq_lock, irq_state); return ret;