2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2011, Kyle C. Hale <kh@u.norhtwestern.edu>
11 * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * Author: Kyle C. Hale <kh@u.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
21 #include <palacios/vmm.h>
22 #include <palacios/vm_guest.h>
23 #include <palacios/vm_guest_mem.h>
24 #include <palacios/vmm_intr.h>
25 #include <palacios/vmm_extensions.h>
26 #include <palacios/vmm_decoder.h>
27 #include <palacios/vmm_types.h>
28 #include <palacios/vmm_hypercall.h>
29 #include <palacios/vmcb.h>
31 #include <gears/code_inject.h>
32 #include <gears/execve_hook.h>
33 #include <gears/sw_intr.h>
37 struct v3_code_injects code_injects;
39 static char mmap_code[] = "\xb8\xc0\x00\x00\x00\x31\xdb\xb9"
40 "\x00\x00\x10\x00\xba\x01\x00\x00"
41 "\x00\xbd\x02\x00\x00\x00\x09\xea"
42 "\xbd\x04\x00\x00\x00\x09\xea\xbe"
43 "\x02\x00\x00\x00\xbd\x20\x00\x00"
44 "\x00\x09\xee\xbf\xff\xff\xff\xff"
45 "\x31\xed\xcd\x80\x89\xc3\xb9\x00"
46 "\x00\x10\x00\xc7\x00\xef\xbe\xad"
47 "\xde\x05\x00\x10\x00\x00\x81\xe9"
48 "\x00\x10\x00\x00\x75\xed\xb8\x00"
49 "\xf0\x00\x00\x0f\x01\xd9";
51 static char munmap_code[] = "\xb8\x5b\x00\x00\x00\xb9\x00\x00"
52 "\x10\x00\xcd\x80\x89\xc3\xb8\x03"
53 "\xf0\x00\x00\x0f\x01\xd9";
55 static char vmmcall_code[] = "\x48\xc7\xc0\x02\xf0\x00\x00\x0f"
58 static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
62 * the presence of this is kind of a hack, and exists because
63 * when one of the below hypercall handlers is invoked, we don't
64 * have an elegant way of deciding which inject queue (normal or exec-hooked)
65 * to pull the first element from, so we have this place marker
67 * This could be ugly with more than one core...
69 static struct v3_code_inject_info * current_inject;
72 static int free_code_inject (struct v3_vm_info * vm, struct v3_code_inject_info * inject) {
73 list_del(&(inject->inject_node));
80 * helper function to save a chunk of code in an inject object's state and
81 * overwrite it with something else (mostly for injecting hypercalls)
83 static int v3_plant_code (struct guest_info * core, struct v3_code_inject_info * inject,
84 char * hva, char * code, uint_t size) {
87 // first back up old code
88 inject->old_code = (char*)V3_Malloc(size);
89 for (i = 0; i < size; i++)
90 inject->old_code[i] = *(hva + i);
93 for (i = 0; i < size; i++)
94 *(hva + i) = *(code + i);
100 static int v3_restore_pre_mmap_state (struct guest_info * core, struct v3_code_inject_info * inject) {
102 addr_t rip_hva, mmap_gva;
104 if ((mmap_gva = (addr_t)core->vm_regs.rbx) < 0) {
105 PrintError("Error running mmap in guest: v3_restore_pre_mmap_state\n");
109 inject->code_region_gva = mmap_gva;
111 ret = v3_gva_to_hva(core,
112 get_addr_linear(core, (addr_t)inject->rip, &(core->segments.cs)),
115 PrintError("Error translating RIP address: v3_restore_pre_mmap_state\n");
119 // restore the code overwritten by mmap code
120 memcpy((void*)rip_hva, (void*)inject->old_code, MMAP_SIZE);
121 V3_Free(inject->old_code);
123 v3_do_static_inject(core, inject, MMAP_COMPLETE, mmap_gva);
128 static int v3_restore_pre_inject_state (struct guest_info * core, struct v3_code_inject_info * inject) {
132 // restore original register state at int 80
133 memcpy(&core->vm_regs, &inject->regs, sizeof(struct v3_gprs));
134 memcpy(&core->ctrl_regs, &inject->ctrl_regs, sizeof(struct v3_ctrl_regs));
136 ret = v3_gva_to_hva(core,
137 get_addr_linear(core, (addr_t)inject->rip, &(core->segments.cs)),
140 PrintError("Error translating RIP address: v3_pre_inject_state\n");
144 // increment original rip by 2 to skip the int 80
145 core->rip = inject->rip + 2;
151 * This function completes stage 1 of the inject. It is invoked when code to
152 * mmap space for the real code has been injected and has completed. This mmap
153 * code will hypercall back into Placios, getting us here.
155 static int mmap_init_handler (struct guest_info * core, unsigned int hcall_id, void * priv_data) {
156 struct v3_code_inject_info * inject = current_inject;
157 v3_restore_pre_mmap_state(core, inject);
163 * This function is stage 3 of the injection process. It is invoked when the injected code
164 * has run to completeion and run a hypercall at its tail to get back into the
165 * VMM. After this, it only remains to unmap the space we injected it into (the
166 * 4th and final stage)
168 static int inject_code_finish (struct guest_info * core, unsigned int hcall_id, void * priv_data) {
169 struct v3_code_inject_info * inject = current_inject;
172 // is the original int 80 page still paged in?
173 if (v3_gva_to_hva(core,
174 get_addr_linear(core, (addr_t)inject->rip, &(core->segments.cs)),
176 PrintError("No mapping in shadow page table: inject_code_finish\n");
180 inject->old_code = V3_Malloc(MUNMAP_SIZE);
181 if (!inject->old_code) {
182 PrintError("Problem mallocing old code segment\n");
186 // save old code and overwrite with munmap
187 v3_plant_code(core, inject, (char*)hva, munmap_code, MUNMAP_SIZE);
189 // set rbx with gva of code region
190 core->vm_regs.rbx = inject->code_region_gva;
193 core->rip = inject->rip;
199 // this is 4th and final stage of the code injection process. It is invoked after code
200 // has been injected to run the munmap system call on our previosuly allocated
201 // memory chunk. It results in the clean
202 // up and removal of the current inject's structures and state, and its
203 // removal from any injection queues
205 static int munmap_finish (struct guest_info * core, unsigned int hcall_id, void * priv_data) {
206 struct v3_code_inject_info * inject = current_inject;
210 if (core->vm_regs.rbx < 0) {
211 PrintError("Problem munmapping injected code\n");
215 if (v3_gva_to_hva(core,
216 get_addr_linear(core, (addr_t)inject->rip, &(core->segments.cs)),
218 PrintError("No mapping in shadow page table: inject_code_finish\n");
222 for (i = 0; i < MUNMAP_SIZE; i++)
223 *(char*)(hva + i) = *(char*)(inject->old_code + i);
225 V3_Free(inject->old_code);
227 v3_restore_pre_inject_state(core, inject);
230 v3_remove_code_inject(core->vm_info, inject);
231 current_inject = NULL;
233 // raise the original int 80 again, causing an exec
234 return v3_raise_swintr(core, SW_INTR_SYSCALL_VEC);
239 * This function is comprises stage 2 of the injection process. Here, the
240 * injected code is copied one page at a time. Each time a new page must be
241 * copied, Palacios injects a page fault for it to bring it into the guest and
242 * host page tables. The fault address will be somewhere in our previously
243 * mmap'd region, but we will jump back to the same RIP every time, which
244 * contains the hypercall that invokes this function.
246 static int mmap_pf_handler (struct guest_info * core, unsigned int hcall_id, void * priv_data) {
247 struct v3_code_inject_info * inject = current_inject;
249 int i, offset = core->vm_regs.rbx;
250 addr_t hva, gva = core->vm_regs.rcx;
251 memset((void*)&err, 0, sizeof(pf_error_t));
253 // was page fault handled by guest kernel?
254 if (v3_gva_to_hva(core,
255 get_addr_linear(core, gva, &(core->segments.ds)),
257 PrintError("No mapping in shadow page table: mmap_pf_handler\n");
261 if (offset >= inject->code_size) {
262 core->rip = gva - offset + inject->func_offset;
264 // restore registers (here, really just for sane ebp/esp)
265 memcpy(&core->vm_regs, &inject->regs, sizeof(struct v3_gprs));
266 memcpy(&core->ctrl_regs, &inject->ctrl_regs, sizeof(struct v3_ctrl_regs));
268 if (v3_gva_to_hva(core,
269 get_addr_linear(core, inject->rip, &(core->segments.cs)),
271 PrintError("No mapping for old RIP in shadow page table: mmap_pf_handler: %p\n", (void*)inject->rip);
275 // restore the hypercall with original int 80 code
276 for (i = 0; i < VMMCALL_SIZE; i++)
277 *(char*)(hva + i) = *(char*)(inject->old_code + i);
279 V3_Free(inject->old_code);
281 if (v3_gva_to_hva(core,
282 get_addr_linear(core, core->rip, &(core->segments.cs)),
284 PrintError("No mapping for new RIP in shadow page table: mmap_pf_handler: %p\n", (void*)core->rip);
291 // copy the next page of code
292 for (i = 0; i < PAGE_SIZE; i++)
293 *(char*)(hva + i) = *(char*)(inject->code + offset + i);
296 core->vm_regs.rbx += PAGE_SIZE;
297 core->vm_regs.rcx += PAGE_SIZE;
299 // to account for rip being incremented by hcall handler
300 core->rip -= VMMCALL_SIZE;
302 // inject the page fault for next page
305 v3_inject_guest_pf(core, gva + PAGE_SIZE, err);
311 static int init_code_inject (struct v3_vm_info * vm, v3_cfg_tree_t * cfg, void ** priv_data) {
312 struct v3_code_injects * injects = &code_injects;
313 INIT_LIST_HEAD(&(injects->code_inject_list));
314 INIT_LIST_HEAD(&(injects->hooked_code_injects));
318 current_inject = NULL;
320 v3_register_hypercall(vm, 0xf000, mmap_init_handler, NULL);
321 v3_register_hypercall(vm, 0xf001, inject_code_finish, NULL);
322 v3_register_hypercall(vm, 0xf002, mmap_pf_handler, NULL);
323 v3_register_hypercall(vm, 0xf003, munmap_finish, NULL);
328 static int deinit_code_inject (struct v3_vm_info * vm, void * priv_data) {
329 struct v3_code_injects * injects = &code_injects;
330 struct v3_code_inject_info * inject = NULL;
331 struct v3_code_inject_info * tmp = NULL;
333 list_for_each_entry_safe(inject, tmp, &(injects->code_inject_list), inject_node) {
334 free_code_inject(vm, inject);
337 list_for_each_entry_safe(inject, tmp, &(injects->hooked_code_injects), inject_node) {
338 free_code_inject(vm, inject);
341 v3_remove_hypercall(vm, 0xf000);
342 v3_remove_hypercall(vm, 0xf001);
343 v3_remove_hypercall(vm, 0xf002);
344 v3_remove_hypercall(vm, 0xf003);
351 /* KCH currently unused */
352 /* this dynamic linking stuff will eventually be moved out of this file... */
353 static addr_t v3_get_dyn_entry (struct guest_info * core, addr_t elf_gva, addr_t elf_hva,
356 ElfW(Phdr) *phdr, *phdr_cursor;
357 ElfW(Dyn) *dyn = NULL;
361 ehdr = (ElfW(Ehdr)*)elf_hva;
362 phdr = (ElfW(Phdr)*)(elf_hva + ehdr->e_phoff);
365 //PrintDebug("num phdrs: %d\n", ehdr->e_phnum);
366 for (i = 0; i < ehdr->e_phnum; i++, phdr_cursor++) {
367 if (phdr_cursor->p_type == PT_DYNAMIC) {
368 num_dyn = phdr_cursor->p_filesz / sizeof(ElfW(Dyn));
369 dyn = (ElfW(Dyn)*)(elf_hva + phdr_cursor->p_offset);
371 // make sure this addr is paged in
372 if (v3_gva_to_gpa(core, elf_gva + phdr_cursor->p_offset, &hva) == -1) {
373 PrintError("Dynamic segment isn't paged in\n");
377 for (j = 0; j < num_dyn; j++, dyn++) {
378 if (dyn->d_tag == section_code) {
379 switch (section_code) {
383 return (addr_t)dyn->d_un.d_val;
385 return (addr_t)dyn->d_un.d_ptr;
396 static int v3_do_resolve (struct guest_info * core, addr_t elf_gva, addr_t elf_hva) {
398 addr_t got_gva, symtab_gva, strtab_gva;
400 if ((got_gva = v3_get_dyn_entry(core, elf_gva, elf_hva, DT_PLTGOT)) == 0) {
401 PrintError("Problem getting at PLTGOT in v3_do_resolve\n");
406 if ((strtab_gva = v3_get_dyn_entry(core, elf_gva, elf_hva, DT_STRTAB)) == 0) {
407 PrintError("Problem getting at PLTGOT in v3_do_resolve\n");
411 if ((symtab_gva = v3_get_dyn_entry(core, elf_gva, elf_hva, DT_SYMTAB)) == 0) {
412 PrintError("Problem getting at PLTGOT in v3_do_resolve\n");
417 PrintDebug("Got gva: %p\n", (void*)got_gva);
418 PrintDebug("Symtab gva: %p\n", (void*)symtab_gva);
419 PrintDebug("Strtab gva: %p\n", (void*)strtab_gva);
423 static int v3_do_cont (struct guest_info * core, struct v3_code_inject_info * inject, addr_t check) {
429 ret = v3_gva_to_gpa(core, check, &hva);
431 // page fault wasn't handled by kernel??
433 PrintError("ERROR: no mapping in guest page table!\n");
437 ret = v3_gva_to_hva(core,
438 get_addr_linear(core, check, &(core->segments.cs)),
441 // this should never happen...
443 PrintError("ERROR: no mapping in shadow page table\n");
447 if (strncmp(elf_magic, (char*)hva, ELF_MAG_SIZE) != 0) {
450 inject->cont->check_addr = check;
451 inject->cont->cont_func = v3_do_cont;
453 memset((void*)&err_code, 0, sizeof(pf_error_t));
456 if (v3_inject_guest_pf(core, check, err_code) < 0) {
457 PrintError("Problem injecting pf\n");
464 PrintDebug("Found ELF!\n");
465 V3_Free(inject->cont);
467 return v3_do_resolve(core, check, hva);
472 * mmap_state: 0 = no inject space in procces yet
473 * 1 = code segment space mmap'd, still need data
474 * 2 = code & data segments mmap'd, ready to inject real code
478 // return E_NEED_PF up the call stack to signal page fault injection
479 // (so rip doesn't get incremented and sw_intr doesn't get injected
481 int v3_do_inject (struct guest_info * core, struct v3_code_inject_info * inject, int mmap_state) {
482 addr_t rip_hva, elf_hva, elf_gva;
486 memset((void*)&err_code, 0, sizeof(pf_error_t));
488 ret = v3_gva_to_hva(core,
489 get_addr_linear(core, (addr_t)core->rip, &(core->segments.cs)),
492 PrintError("Error translating RIP address in v3_do_inject\n");
496 elf_gva = (addr_t)(core->rip & 0xfffffffffffff000);
498 for (i = 0; i < PAGES_BACK; i++, elf_gva -= PAGE_SIZE) {
500 ret = v3_gva_to_hva(core,
501 get_addr_linear(core, elf_gva, &(core->segments.cs)),
507 PrintDebug("Found a page we need to fault in\n");
508 inject->cont = (struct v3_cont *)V3_Malloc(sizeof(struct v3_cont));
509 ret = v3_gva_to_gpa(core, elf_gva, &elf_hva);
512 PrintDebug("no mapping in guest page table\n");
515 inject->cont->check_addr = elf_gva;
516 inject->cont->cont_func = v3_do_cont;
519 PrintDebug("Injecting pf for addr: %p\n", (void*) elf_gva);
521 if (v3_inject_guest_pf(core, elf_gva, err_code) < 0) {
522 PrintError("Problem injecting pf\n");
529 if (strncmp(elf_magic, (char*)elf_hva, ELF_MAG_SIZE) == 0) {
530 PrintDebug("Found elf_magic!\n");
537 V3_Free(inject->cont);
539 return v3_do_resolve(core, elf_gva, elf_hva);
541 PrintDebug("Planting code\n");
542 v3_plant_code(core, inject, (char*)rip_hva, mmap_code, MMAP_SIZE);
544 PrintDebug("Saving register context\n");
545 PrintDebug("First 8 bytes 0x%lx\n", *(long*)rip_hva);
546 /* may need to save v3_ctrl registers too... */
547 memcpy(&inject->regs, &core->vm_regs, sizeof(struct v3_gprs));
548 inject->rip = core->rip;
550 /* jump to injected code */
551 PrintDebug("Jumping to injected code\n");
557 * mmap_state: NO_MMAP = no inject space mmap'd in procces yet
558 * MMAP_COMPLETE = mmap complete, time to do real inject
561 int v3_do_static_inject (struct guest_info * core, struct v3_code_inject_info * inject,
562 int mmap_state, addr_t region_gva) {
567 ret = v3_gva_to_hva(core,
568 get_addr_linear(core, (addr_t)core->rip, &(core->segments.cs)),
571 PrintError("Error translating RIP address: v3_do_static_inject\n");
575 switch (mmap_state) {
579 v3_plant_code(core, inject, (char*)rip_hva, mmap_code, MMAP_SIZE);
581 // save registers (gprs and ctrl regs, and rip)
582 memcpy(&inject->regs, &core->vm_regs, sizeof(struct v3_gprs));
583 memcpy(&inject->ctrl_regs, &core->ctrl_regs, sizeof(struct v3_ctrl_regs));
584 inject->rip = core->rip;
586 // jump to mmap code, and squash original swintr
592 memset((void*)&err_code, 0, sizeof(pf_error_t));
594 ret = v3_gva_to_hva(core,
595 get_addr_linear(core, (addr_t)inject->rip, &(core->segments.cs)),
598 PrintError("Error translating RIP address: v3_do_static_inject\n");
602 // inject hypercall code
603 v3_plant_code(core, inject, (char*)rip_hva, vmmcall_code, VMMCALL_SIZE);
605 /* store current copy offset in rbx, fault gva in rcx */
606 core->vm_regs.rbx = 0;
607 core->vm_regs.rcx = region_gva;
612 // inject the first page fault for the code block
613 if (v3_inject_guest_pf(core, region_gva, err_code) < 0) {
614 PrintError("Problem injecting page fault in v3_do_static_inject\n");
618 // returning here will run hypercall 0xf002
619 // This will get us back in v3_mmap_pf_handler
620 core->rip = inject->rip;
624 PrintError("Invalid mmap state\n");
632 * This function is invoked in one of two ways:
633 * 1. A syscall has been intercepted and we've popped off the next pending
635 * 2. An exec has been intercepted and we've popped off the next hooked inject
638 int v3_handle_guest_inject (struct guest_info * core, void * priv_data) {
639 struct v3_code_inject_info * inject = (struct v3_code_inject_info *)priv_data;
641 /* eventually this should turn into a mutex lock */
642 if (current_inject) {
643 PrintError("An inject is already in progress\n");
646 current_inject = inject;
647 inject->in_progress = 1;
650 if (!inject->is_dyn) {
651 return v3_do_static_inject(core, inject, 0, (addr_t)NULL);
654 return inject->cont->cont_func(core, inject, inject->cont->check_addr);
656 return v3_do_inject(core, inject, 0);
663 int v3_insert_code_inject (void * ginfo, void * code, int size,
664 char * bin_file, int is_dyn, int is_exec_hooked, int func_offset) {
665 struct v3_code_injects * injects = &code_injects;
666 struct v3_vm_info * vm = (struct v3_vm_info *)ginfo;
667 struct v3_code_inject_info * inject;
669 if (!injects->active) {
670 PrintError("Code injection has not been initialized\n");
674 inject = V3_Malloc(sizeof(struct v3_code_inject_info));
676 PrintError("Error allocating inject info in v3_insert_code_inject\n");
680 memset(inject, 0, sizeof(struct v3_code_inject_info));
683 inject->code_size = size;
684 inject->is_dyn = is_dyn;
685 inject->func_offset = func_offset;
686 inject->bin_file = bin_file;
687 inject->is_exec_hooked = is_exec_hooked;
689 if (is_exec_hooked) {
690 v3_hook_executable(vm, bin_file, v3_handle_guest_inject, (void*)inject);
691 list_add_tail(&(inject->inject_node), &(injects->hooked_code_injects));
693 list_add_tail(&(inject->inject_node), &(injects->code_inject_list));
700 int v3_remove_code_inject (struct v3_vm_info * vm, struct v3_code_inject_info * inject) {
702 PrintDebug("Removing and freeing code inject\n");
703 if (inject->is_exec_hooked) {
704 if (v3_unhook_executable(vm, inject->bin_file) < 0) {
705 PrintError("Problem unhooking executable in v3_remove_code_inject\n");
710 free_code_inject(vm, inject);
715 static struct v3_extension_impl code_inject_impl = {
716 .name = "code_inject",
717 .init = init_code_inject,
718 .deinit = deinit_code_inject,
724 register_extension(&code_inject_impl);