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);
90 if (!inject->old_code) {
91 PrintError(core->vm_info, core, "Cannot allocate in planting code\n");
95 for (i = 0; i < size; i++)
96 inject->old_code[i] = *(hva + i);
99 for (i = 0; i < size; i++)
100 *(hva + i) = *(code + i);
106 static int v3_restore_pre_mmap_state (struct guest_info * core, struct v3_code_inject_info * inject) {
108 addr_t rip_hva, mmap_gva;
110 if ((mmap_gva = (addr_t)core->vm_regs.rbx) < 0) {
111 PrintError(core->vm_info, core, "Error running mmap in guest: v3_restore_pre_mmap_state\n");
115 inject->code_region_gva = mmap_gva;
117 ret = v3_gva_to_hva(core,
118 get_addr_linear(core, (addr_t)inject->rip, &(core->segments.cs)),
121 PrintError(core->vm_info, core, "Error translating RIP address: v3_restore_pre_mmap_state\n");
125 // restore the code overwritten by mmap code
126 memcpy((void*)rip_hva, (void*)inject->old_code, MMAP_SIZE);
127 V3_Free(inject->old_code);
129 v3_do_static_inject(core, inject, MMAP_COMPLETE, mmap_gva);
134 static int v3_restore_pre_inject_state (struct guest_info * core, struct v3_code_inject_info * inject) {
138 // restore original register state at int 80
139 memcpy(&core->vm_regs, &inject->regs, sizeof(struct v3_gprs));
140 memcpy(&core->ctrl_regs, &inject->ctrl_regs, sizeof(struct v3_ctrl_regs));
142 ret = v3_gva_to_hva(core,
143 get_addr_linear(core, (addr_t)inject->rip, &(core->segments.cs)),
146 PrintError(core->vm_info, core, "Error translating RIP address: v3_pre_inject_state\n");
150 // increment original rip by 2 to skip the int 80
151 core->rip = inject->rip + 2;
157 * This function completes stage 1 of the inject. It is invoked when code to
158 * mmap space for the real code has been injected and has completed. This mmap
159 * code will hypercall back into Placios, getting us here.
161 static int mmap_init_handler (struct guest_info * core, unsigned int hcall_id, void * priv_data) {
162 struct v3_code_inject_info * inject = current_inject;
163 v3_restore_pre_mmap_state(core, inject);
169 * This function is stage 3 of the injection process. It is invoked when the injected code
170 * has run to completeion and run a hypercall at its tail to get back into the
171 * VMM. After this, it only remains to unmap the space we injected it into (the
172 * 4th and final stage)
174 static int inject_code_finish (struct guest_info * core, unsigned int hcall_id, void * priv_data) {
175 struct v3_code_inject_info * inject = current_inject;
178 // is the original int 80 page still paged in?
179 if (v3_gva_to_hva(core,
180 get_addr_linear(core, (addr_t)inject->rip, &(core->segments.cs)),
182 PrintError(core->vm_info, core, "No mapping in shadow page table: inject_code_finish\n");
186 inject->old_code = V3_Malloc(MUNMAP_SIZE);
188 if (!inject->old_code) {
189 PrintError(core->vm_info, core, "Problem mallocing old code segment\n");
193 // save old code and overwrite with munmap
194 v3_plant_code(core, inject, (char*)hva, munmap_code, MUNMAP_SIZE);
196 // set rbx with gva of code region
197 core->vm_regs.rbx = inject->code_region_gva;
200 core->rip = inject->rip;
206 // this is 4th and final stage of the code injection process. It is invoked after code
207 // has been injected to run the munmap system call on our previosuly allocated
208 // memory chunk. It results in the clean
209 // up and removal of the current inject's structures and state, and its
210 // removal from any injection queues
212 static int munmap_finish (struct guest_info * core, unsigned int hcall_id, void * priv_data) {
213 struct v3_code_inject_info * inject = current_inject;
217 if (core->vm_regs.rbx < 0) {
218 PrintError(core->vm_info, core, "Problem munmapping injected code\n");
222 if (v3_gva_to_hva(core,
223 get_addr_linear(core, (addr_t)inject->rip, &(core->segments.cs)),
225 PrintError(core->vm_info, core, "No mapping in shadow page table: inject_code_finish\n");
229 for (i = 0; i < MUNMAP_SIZE; i++)
230 *(char*)(hva + i) = *(char*)(inject->old_code + i);
232 V3_Free(inject->old_code);
234 v3_restore_pre_inject_state(core, inject);
237 v3_remove_code_inject(core->vm_info, inject);
238 current_inject = NULL;
240 // raise the original int 80 again, causing an exec
241 return v3_raise_swintr(core, SW_INTR_SYSCALL_VEC);
246 * This function is comprises stage 2 of the injection process. Here, the
247 * injected code is copied one page at a time. Each time a new page must be
248 * copied, Palacios injects a page fault for it to bring it into the guest and
249 * host page tables. The fault address will be somewhere in our previously
250 * mmap'd region, but we will jump back to the same RIP every time, which
251 * contains the hypercall that invokes this function.
253 static int mmap_pf_handler (struct guest_info * core, unsigned int hcall_id, void * priv_data) {
254 struct v3_code_inject_info * inject = current_inject;
256 int i, offset = core->vm_regs.rbx;
257 addr_t hva, gva = core->vm_regs.rcx;
258 memset((void*)&err, 0, sizeof(pf_error_t));
260 // was page fault handled by guest kernel?
261 if (v3_gva_to_hva(core,
262 get_addr_linear(core, gva, &(core->segments.ds)),
264 PrintError(core->vm_info, core, "No mapping in shadow page table: mmap_pf_handler\n");
268 if (offset >= inject->code_size) {
269 core->rip = gva - offset + inject->func_offset;
271 // restore registers (here, really just for sane ebp/esp)
272 memcpy(&core->vm_regs, &inject->regs, sizeof(struct v3_gprs));
273 memcpy(&core->ctrl_regs, &inject->ctrl_regs, sizeof(struct v3_ctrl_regs));
275 if (v3_gva_to_hva(core,
276 get_addr_linear(core, inject->rip, &(core->segments.cs)),
278 PrintError(core->vm_info, core, "No mapping for old RIP in shadow page table: mmap_pf_handler: %p\n", (void*)inject->rip);
282 // restore the hypercall with original int 80 code
283 for (i = 0; i < VMMCALL_SIZE; i++)
284 *(char*)(hva + i) = *(char*)(inject->old_code + i);
286 V3_Free(inject->old_code);
288 if (v3_gva_to_hva(core,
289 get_addr_linear(core, core->rip, &(core->segments.cs)),
291 PrintError(core->vm_info, core, "No mapping for new RIP in shadow page table: mmap_pf_handler: %p\n", (void*)core->rip);
298 // copy the next page of code
299 for (i = 0; i < PAGE_SIZE; i++)
300 *(char*)(hva + i) = *(char*)(inject->code + offset + i);
303 core->vm_regs.rbx += PAGE_SIZE;
304 core->vm_regs.rcx += PAGE_SIZE;
306 // to account for rip being incremented by hcall handler
307 core->rip -= VMMCALL_SIZE;
309 // inject the page fault for next page
312 v3_inject_guest_pf(core, gva + PAGE_SIZE, err);
318 static int init_code_inject (struct v3_vm_info * vm, v3_cfg_tree_t * cfg, void ** priv_data) {
319 struct v3_code_injects * injects = &code_injects;
320 INIT_LIST_HEAD(&(injects->code_inject_list));
321 INIT_LIST_HEAD(&(injects->hooked_code_injects));
325 current_inject = NULL;
327 v3_register_hypercall(vm, 0xf000, mmap_init_handler, NULL);
328 v3_register_hypercall(vm, 0xf001, inject_code_finish, NULL);
329 v3_register_hypercall(vm, 0xf002, mmap_pf_handler, NULL);
330 v3_register_hypercall(vm, 0xf003, munmap_finish, NULL);
335 static int deinit_code_inject (struct v3_vm_info * vm, void * priv_data) {
336 struct v3_code_injects * injects = &code_injects;
337 struct v3_code_inject_info * inject = NULL;
338 struct v3_code_inject_info * tmp = NULL;
340 list_for_each_entry_safe(inject, tmp, &(injects->code_inject_list), inject_node) {
341 free_code_inject(vm, inject);
344 list_for_each_entry_safe(inject, tmp, &(injects->hooked_code_injects), inject_node) {
345 free_code_inject(vm, inject);
348 v3_remove_hypercall(vm, 0xf000);
349 v3_remove_hypercall(vm, 0xf001);
350 v3_remove_hypercall(vm, 0xf002);
351 v3_remove_hypercall(vm, 0xf003);
358 /* KCH currently unused */
359 /* this dynamic linking stuff will eventually be moved out of this file... */
360 static addr_t v3_get_dyn_entry (struct guest_info * core, addr_t elf_gva, addr_t elf_hva,
363 ElfW(Phdr) *phdr, *phdr_cursor;
364 ElfW(Dyn) *dyn = NULL;
368 ehdr = (ElfW(Ehdr)*)elf_hva;
369 phdr = (ElfW(Phdr)*)(elf_hva + ehdr->e_phoff);
372 //PrintDebug(core->vm_info, core, "num phdrs: %d\n", ehdr->e_phnum);
373 for (i = 0; i < ehdr->e_phnum; i++, phdr_cursor++) {
374 if (phdr_cursor->p_type == PT_DYNAMIC) {
375 num_dyn = phdr_cursor->p_filesz / sizeof(ElfW(Dyn));
376 dyn = (ElfW(Dyn)*)(elf_hva + phdr_cursor->p_offset);
378 // make sure this addr is paged in
379 if (v3_gva_to_gpa(core, elf_gva + phdr_cursor->p_offset, &hva) == -1) {
380 PrintError(core->vm_info, core, "Dynamic segment isn't paged in\n");
384 for (j = 0; j < num_dyn; j++, dyn++) {
385 if (dyn->d_tag == section_code) {
386 switch (section_code) {
390 return (addr_t)dyn->d_un.d_val;
392 return (addr_t)dyn->d_un.d_ptr;
403 static int v3_do_resolve (struct guest_info * core, addr_t elf_gva, addr_t elf_hva) {
405 addr_t got_gva, symtab_gva, strtab_gva;
407 if ((got_gva = v3_get_dyn_entry(core, elf_gva, elf_hva, DT_PLTGOT)) == 0) {
408 PrintError(core->vm_info, core, "Problem getting at PLTGOT in v3_do_resolve\n");
413 if ((strtab_gva = v3_get_dyn_entry(core, elf_gva, elf_hva, DT_STRTAB)) == 0) {
414 PrintError(core->vm_info, core, "Problem getting at PLTGOT in v3_do_resolve\n");
418 if ((symtab_gva = v3_get_dyn_entry(core, elf_gva, elf_hva, DT_SYMTAB)) == 0) {
419 PrintError(core->vm_info, core, "Problem getting at PLTGOT in v3_do_resolve\n");
424 PrintDebug(core->vm_info, core, "Got gva: %p\n", (void*)got_gva);
425 PrintDebug(core->vm_info, core, "Symtab gva: %p\n", (void*)symtab_gva);
426 PrintDebug(core->vm_info, core, "Strtab gva: %p\n", (void*)strtab_gva);
430 static int v3_do_cont (struct guest_info * core, struct v3_code_inject_info * inject, addr_t check) {
436 ret = v3_gva_to_gpa(core, check, &hva);
438 // page fault wasn't handled by kernel??
440 PrintError(core->vm_info, core, "ERROR: no mapping in guest page table!\n");
444 ret = v3_gva_to_hva(core,
445 get_addr_linear(core, check, &(core->segments.cs)),
448 // this should never happen...
450 PrintError(core->vm_info, core, "ERROR: no mapping in shadow page table\n");
454 if (strncmp(elf_magic, (char*)hva, ELF_MAG_SIZE) != 0) {
457 inject->cont->check_addr = check;
458 inject->cont->cont_func = v3_do_cont;
460 memset((void*)&err_code, 0, sizeof(pf_error_t));
463 if (v3_inject_guest_pf(core, check, err_code) < 0) {
464 PrintError(core->vm_info, core, "Problem injecting pf\n");
471 PrintDebug(core->vm_info, core, "Found ELF!\n");
472 V3_Free(inject->cont);
474 return v3_do_resolve(core, check, hva);
479 * mmap_state: 0 = no inject space in procces yet
480 * 1 = code segment space mmap'd, still need data
481 * 2 = code & data segments mmap'd, ready to inject real code
485 // return E_NEED_PF up the call stack to signal page fault injection
486 // (so rip doesn't get incremented and sw_intr doesn't get injected
488 int v3_do_inject (struct guest_info * core, struct v3_code_inject_info * inject, int mmap_state) {
489 addr_t rip_hva, elf_hva, elf_gva;
493 memset((void*)&err_code, 0, sizeof(pf_error_t));
495 ret = v3_gva_to_hva(core,
496 get_addr_linear(core, (addr_t)core->rip, &(core->segments.cs)),
499 PrintError(core->vm_info, core, "Error translating RIP address in v3_do_inject\n");
503 elf_gva = (addr_t)(core->rip & 0xfffffffffffff000);
505 for (i = 0; i < PAGES_BACK; i++, elf_gva -= PAGE_SIZE) {
507 ret = v3_gva_to_hva(core,
508 get_addr_linear(core, elf_gva, &(core->segments.cs)),
514 PrintDebug(core->vm_info, core, "Found a page we need to fault in\n");
515 inject->cont = (struct v3_cont *)V3_Malloc(sizeof(struct v3_cont));
518 PrintError(core->vm_info, core, "Cannot allocate in doing inject\n");
522 ret = v3_gva_to_gpa(core, elf_gva, &elf_hva);
525 PrintDebug(core->vm_info, core, "no mapping in guest page table\n");
528 inject->cont->check_addr = elf_gva;
529 inject->cont->cont_func = v3_do_cont;
532 PrintDebug(core->vm_info, core, "Injecting pf for addr: %p\n", (void*) elf_gva);
534 if (v3_inject_guest_pf(core, elf_gva, err_code) < 0) {
535 PrintError(core->vm_info, core, "Problem injecting pf\n");
542 if (strncmp(elf_magic, (char*)elf_hva, ELF_MAG_SIZE) == 0) {
543 PrintDebug(core->vm_info, core, "Found elf_magic!\n");
550 V3_Free(inject->cont);
552 return v3_do_resolve(core, elf_gva, elf_hva);
554 PrintDebug(core->vm_info, core, "Planting code\n");
555 v3_plant_code(core, inject, (char*)rip_hva, mmap_code, MMAP_SIZE);
557 PrintDebug(core->vm_info, core, "Saving register context\n");
558 PrintDebug(core->vm_info, core, "First 8 bytes 0x%lx\n", *(long*)rip_hva);
559 /* may need to save v3_ctrl registers too... */
560 memcpy(&inject->regs, &core->vm_regs, sizeof(struct v3_gprs));
561 inject->rip = core->rip;
563 /* jump to injected code */
564 PrintDebug(core->vm_info, core, "Jumping to injected code\n");
570 * mmap_state: NO_MMAP = no inject space mmap'd in procces yet
571 * MMAP_COMPLETE = mmap complete, time to do real inject
574 int v3_do_static_inject (struct guest_info * core, struct v3_code_inject_info * inject,
575 int mmap_state, addr_t region_gva) {
580 ret = v3_gva_to_hva(core,
581 get_addr_linear(core, (addr_t)core->rip, &(core->segments.cs)),
584 PrintError(core->vm_info, core, "Error translating RIP address: v3_do_static_inject\n");
588 switch (mmap_state) {
592 v3_plant_code(core, inject, (char*)rip_hva, mmap_code, MMAP_SIZE);
594 // save registers (gprs and ctrl regs, and rip)
595 memcpy(&inject->regs, &core->vm_regs, sizeof(struct v3_gprs));
596 memcpy(&inject->ctrl_regs, &core->ctrl_regs, sizeof(struct v3_ctrl_regs));
597 inject->rip = core->rip;
599 // jump to mmap code, and squash original swintr
605 memset((void*)&err_code, 0, sizeof(pf_error_t));
607 ret = v3_gva_to_hva(core,
608 get_addr_linear(core, (addr_t)inject->rip, &(core->segments.cs)),
611 PrintError(core->vm_info, core, "Error translating RIP address: v3_do_static_inject\n");
615 // inject hypercall code
616 v3_plant_code(core, inject, (char*)rip_hva, vmmcall_code, VMMCALL_SIZE);
618 /* store current copy offset in rbx, fault gva in rcx */
619 core->vm_regs.rbx = 0;
620 core->vm_regs.rcx = region_gva;
625 // inject the first page fault for the code block
626 if (v3_inject_guest_pf(core, region_gva, err_code) < 0) {
627 PrintError(core->vm_info, core, "Problem injecting page fault in v3_do_static_inject\n");
631 // returning here will run hypercall 0xf002
632 // This will get us back in v3_mmap_pf_handler
633 core->rip = inject->rip;
637 PrintError(core->vm_info, core, "Invalid mmap state\n");
645 * This function is invoked in one of two ways:
646 * 1. A syscall has been intercepted and we've popped off the next pending
648 * 2. An exec has been intercepted and we've popped off the next hooked inject
651 int v3_handle_guest_inject (struct guest_info * core, void * priv_data) {
652 struct v3_code_inject_info * inject = (struct v3_code_inject_info *)priv_data;
654 /* eventually this should turn into a mutex lock */
655 if (current_inject) {
656 PrintError(core->vm_info, core, "An inject is already in progress\n");
659 current_inject = inject;
660 inject->in_progress = 1;
663 if (!inject->is_dyn) {
664 return v3_do_static_inject(core, inject, 0, (addr_t)NULL);
667 return inject->cont->cont_func(core, inject, inject->cont->check_addr);
669 return v3_do_inject(core, inject, 0);
676 int v3_insert_code_inject (void * ginfo, void * code, int size,
677 char * bin_file, int is_dyn, int is_exec_hooked, int func_offset) {
678 struct v3_code_injects * injects = &code_injects;
679 struct v3_vm_info * vm = (struct v3_vm_info *)ginfo;
680 struct v3_code_inject_info * inject;
682 if (!injects->active) {
683 PrintError(vm, VCORE_NONE, "Code injection has not been initialized\n");
687 inject = V3_Malloc(sizeof(struct v3_code_inject_info));
689 PrintError(vm, VCORE_NONE, "Error allocating inject info in v3_insert_code_inject\n");
693 memset(inject, 0, sizeof(struct v3_code_inject_info));
696 inject->code_size = size;
697 inject->is_dyn = is_dyn;
698 inject->func_offset = func_offset;
699 inject->bin_file = bin_file;
700 inject->is_exec_hooked = is_exec_hooked;
702 if (is_exec_hooked) {
703 v3_hook_executable(vm, bin_file, v3_handle_guest_inject, (void*)inject);
704 list_add_tail(&(inject->inject_node), &(injects->hooked_code_injects));
706 list_add_tail(&(inject->inject_node), &(injects->code_inject_list));
713 int v3_remove_code_inject (struct v3_vm_info * vm, struct v3_code_inject_info * inject) {
715 PrintDebug(vm, VCORE_NONE, "Removing and freeing code inject\n");
716 if (inject->is_exec_hooked) {
717 if (v3_unhook_executable(vm, inject->bin_file) < 0) {
718 PrintError(vm, VCORE_NONE, "Problem unhooking executable in v3_remove_code_inject\n");
723 free_code_inject(vm, inject);
728 static struct v3_extension_impl code_inject_impl = {
729 .name = "code_inject",
730 .vm_init = init_code_inject,
731 .vm_deinit = deinit_code_inject,
737 register_extension(&code_inject_impl);