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"
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
struct v3_sym_core_state;
#endif
+#ifdef CONFIG_SYSCALL_HIJACK
+#include <palacios/vmm_syscall_hijack.h>
+#endif
+
#include <palacios/vmm_config.h>
/* 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;
+// KCH
+// Check if pte for this gva has certain permissions
+int v3_gva_can_access(struct guest_info * core, addr_t gva);
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
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];
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 {
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);
*/
-
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),
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__
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/
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
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,
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:
}
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
#include <palacios/vmm_xed.h>
#include <palacios/vmm_direct_paging.h>
+#ifdef CONFIG_SYSCALL_HIJACK
+#include <palacios/vmm_syscall_hijack.h>
+#endif
+
v3_cpu_mode_t v3_get_vm_cpu_mode(struct guest_info * info) {
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
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;
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;
*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;
}
+/* 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;
+ }
+}
#include <palacios/vmm_ctrl_regs.h>
#include <palacios/vmm_lock.h>
+#include <palacios/vm_guest_mem.h>
+#include <palacios/vmm_decoder.h>
#ifndef CONFIG_DEBUG_INTERRUPTS
#undef PrintDebug
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];
}
}
-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;
}
}
}
- // 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;