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".
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_decoder.h>
22 #include <palacios/vm_guest.h>
23 #include <palacios/vm_guest_mem.h>
25 #include <gears/process_environment.h>
27 static struct v3_execve_varchunk var_dump;
30 /* KCH: currently only checks if we can perform a user-mode write
31 return 1 on success */
32 static int v3_gva_can_access(struct guest_info * core, addr_t gva) {
34 v3_reg_t guest_cr3 = 0;
35 pf_error_t access_type;
36 pt_access_status_t access_status;
38 access_type.write = 1;
41 if (core->mem_mode == PHYSICAL_MEM) {
45 if (core->shdw_pg_mode == SHADOW_PAGING) {
46 guest_cr3 = core->shdw_pg_state.guest_cr3;
48 guest_cr3 = core->ctrl_regs.cr3;
51 // guest is in paged mode
52 switch (core->cpu_mode) {
54 if (v3_check_guest_pt_32(core, guest_cr3, gva, access_type, &access_status) == -1) {
59 if (v3_check_guest_pt_32pae(core, guest_cr3, gva, access_type, &access_status) == -1) {
66 if (v3_check_guest_pt_64(core, guest_cr3, gva, access_type, &access_status) == -1) {
74 if (access_status != PT_ACCESS_OK) {
81 static int v3_copy_chunk_guest32(struct guest_info * core, addr_t gva, uint_t argcnt, uint_t envcnt) {
85 uint32_t tmp_args[var_dump.argc];
86 uint32_t tmp_envs[var_dump.envc];
88 PrintDebug(core->vm_info, core, "Initiating copy into guest (32bit)\n");
90 ret = v3_gva_to_hva(core, get_addr_linear(core, gva, &(core->segments.ds)), &hva);
92 PrintDebug(core->vm_info, core, "Error translating gva in v3_copy_chunk_2guest\n");
96 // copy the env strings (we're moving top-down through the stack)
97 char * host_cursor = (char*) hva;
98 uint32_t guest_cursor = (uint32_t) gva;
99 host_cursor -= strlen(var_dump.envp[i]) + 1;
100 guest_cursor -= strlen(var_dump.envp[i]) + 1;
101 while (i < var_dump.envc) {
102 //PrintDebug(core->vm_info, core, "Copying envvar#%d: %s\n", i, var_dump.envp[i]);
103 strcpy(host_cursor, var_dump.envp[i]);
104 tmp_envs[i] = guest_cursor;
106 if (i != var_dump.envc) {
107 host_cursor -= strlen(var_dump.envp[i]) + 1;
108 guest_cursor -= strlen(var_dump.envp[i]) + 1;
112 // then the arg strings
114 host_cursor -= strlen(var_dump.argv[i]) + 1;
115 guest_cursor -= strlen(var_dump.argv[i]) + 1;
116 while (i < var_dump.argc) {
117 //PrintDebug(core->vm_info, core, "Copying arg #%d: %s\n", i, var_dump.argv[i]);
118 strcpy(host_cursor, var_dump.argv[i]);
119 tmp_args[i] = guest_cursor;
121 if (i != var_dump.argc) {
122 host_cursor -= strlen(var_dump.argv[i]) + 1;
123 guest_cursor -= strlen(var_dump.argv[i]) + 1;
131 while ((long)host_cursor % 4) {
140 *((uint32_t*)host_cursor) = 0;
144 for (i = 0; i < var_dump.envc; i++) {
145 *((uint32_t*)host_cursor) = tmp_envs[i];
150 core->vm_regs.rdx = guest_cursor + 4;
152 *((uint32_t*)host_cursor) = 0;
155 for (i = 0; i < var_dump.argc; i++) {
156 *((uint32_t*)host_cursor) = tmp_args[i];
161 core->vm_regs.rcx = guest_cursor + 4;
163 // free up our temporary storage in the VMM
164 for (i = 0; i < var_dump.argc; i++) {
165 V3_Free(var_dump.argv[i]);
167 for (i = 0; i < var_dump.envc; i++) {
168 V3_Free(var_dump.envp[i]);
171 V3_Free(var_dump.envp);
172 V3_Free(var_dump.argv);
177 static int v3_copy_chunk_vmm32(struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
180 uint_t argc = 0, envc = 0, bytes = 0;
183 PrintDebug(core->vm_info, core, "Initiating copy into vmm\n");
185 int ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rdx, &(core->segments.ds)), &envp);
187 PrintDebug(core->vm_info, core, "Error translating address in rdx\n");
191 ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rcx, &(core->segments.ds)), &argv);
193 PrintDebug(core->vm_info, core, "Error translating address in rcx\n");
197 cursor = (char*)argv;
198 while (*((uint32_t*)cursor) != 0) {
200 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &argvn);
202 PrintDebug(core->vm_info, core, "Error translating address for argvn\n");
208 /* account for new args */
210 var_dump.argv = (char**)V3_Malloc(sizeof(char*)*argc);
212 if (!var_dump.argv) {
213 PrintError(core->vm_info, core, "Cannot allocate in copying\n");
217 var_dump.argc = argc;
218 bytes += sizeof(uint32_t)*argc;
220 cursor = (char*)argv;
222 while (*((uint32_t*)cursor) != 0) {
224 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &argvn);
226 PrintDebug(core->vm_info, core, "Error translating argvn address\n");
229 /* malloc room for the string */
230 char * tmpstr = (char*)V3_Malloc(strlen((char*)argvn) + 1);
233 PrintError(core->vm_info, core, "Cannot allocate temporary\n");
237 /* copy the pointer */
238 var_dump.argv[i] = tmpstr;
240 /* copy the string */
241 // this is guaranteed to alwys null terminate tmpstr
242 strncpy(tmpstr, (char*)argvn, strlen((char*)argvn) + 1);
246 bytes += strlen((char*)argvn) + 1;
249 /* stick in new arg strings */
252 char * tmpstr = (char*)V3_Malloc(strlen(argstrs[j]) + 1);
255 PrintError(core->vm_info, core, "Cannot allocate temp string\n");
259 // will always null-terminate tmpstr
260 strncpy(tmpstr, argstrs[i], strlen(argstrs[j]) + 1);
261 var_dump.argv[i] = tmpstr;
262 bytes += strlen(argstrs[j]) + 1;
267 cursor = (char*)envp;
268 while (*((uint32_t*)cursor) != 0) {
270 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &envpn);
272 PrintDebug(core->vm_info, core, "Error translating address for envpn\n");
279 var_dump.envp = (char**)V3_Malloc(sizeof(char*)*envc);
281 if (!var_dump.envp) {
282 PrintError(core->vm_info, core, "Cannot allocate var dump\n");
286 var_dump.envc = envc;
287 bytes += sizeof(uint32_t)*envc;
289 cursor = (char*)envp;
291 while (*((uint32_t*)cursor) != 0) {
293 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &envpn);
295 PrintDebug(core->vm_info, core, "Error translating address for envpn\n");
298 /* malloc room for the string */
299 char * tmpstr = (char*)V3_Malloc(strlen((char*)envpn) + 1);
302 PrintError(core->vm_info, core, "Cannot allocate temp string\n");
306 /* copy the pointer */
307 var_dump.envp[i] = tmpstr;
309 /* deepcopy the string */
310 // will always null-terminate tmpstr
311 strncpy(tmpstr, (char*)envpn, strlen((char*)envpn) + 1);
314 bytes += strlen((char*)envpn) + 1;
317 /* put in our new env strings */
320 char * tmpstr = (char*)V3_Malloc(strlen(envstrs[j]) + 1);
323 PrintError(core->vm_info, core, "Cannot allocate temp string\n");
326 // will always null-terminate tmpstr
327 strncpy(tmpstr, envstrs[j], strlen(envstrs[j]) + 1);
328 var_dump.envp[i] = tmpstr;
329 bytes += strlen(envstrs[j]) + 1;
334 /* account for padding for strings
335 and 2 null pointers */
336 bytes += (bytes % 4) + 8;
337 var_dump.bytes = bytes;
342 static int v3_inject_strings32 (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
345 uint_t bytes_needed = 0;
347 /* copy out all of the arguments and the environment to the VMM */
348 if ((bytes_needed = v3_copy_chunk_vmm32(core, argstrs, envstrs, argcnt, envcnt)) == -1) {
349 PrintDebug(core->vm_info, core, "Error copying out environment and arguments\n");
353 PrintDebug(core->vm_info, core, "environment successfully copied into VMM\n");
355 inject_gva = v3_prepare_guest_stack(core, bytes_needed);
357 PrintDebug(core->vm_info, core, "Not enough space on user stack\n");
361 v3_copy_chunk_guest32(core, inject_gva, argcnt, envcnt);
367 static int v3_copy_chunk_guest64(struct guest_info * core, addr_t gva, uint_t argcnt, uint_t envcnt) {
371 uint64_t tmp_args[var_dump.argc];
372 uint64_t tmp_envs[var_dump.envc];
374 PrintDebug(core->vm_info, core, "Initiating copy into guest (64bit)\n");
376 ret = v3_gva_to_hva(core, get_addr_linear(core, gva, &(core->segments.ds)), &hva);
378 PrintDebug(core->vm_info, core, "Error translating gva in v3_copy_chunk_2guest64\n");
382 char * host_cursor = (char*) hva;
383 uint64_t guest_cursor = (uint64_t) gva;
384 host_cursor -= strlen(var_dump.envp[i]) + 1;
385 guest_cursor -= strlen(var_dump.envp[i]) + 1;
386 while (i < var_dump.envc) {
387 //PrintDebug(core->vm_info, core, "Copying envvar#%d: %s\n", i, var_dump.envp[i]);
388 strcpy(host_cursor, var_dump.envp[i]);
389 tmp_envs[i] = guest_cursor;
391 if (i != var_dump.envc) {
392 host_cursor -= strlen(var_dump.envp[i]) + 1;
393 guest_cursor -= strlen(var_dump.envp[i]) + 1;
398 host_cursor -= strlen(var_dump.argv[i]) + 1;
399 guest_cursor -= strlen(var_dump.argv[i]) + 1;
400 while (i < var_dump.argc) {
401 //PrintDebug(core->vm_info, core, "Copying arg #%d: %s\n", i, var_dump.argv[i]);
402 strcpy(host_cursor, var_dump.argv[i]);
403 tmp_args[i] = guest_cursor;
405 if (i != var_dump.argc) {
406 host_cursor -= strlen(var_dump.argv[i]) + 1;
407 guest_cursor -= strlen(var_dump.argv[i]) + 1;
414 while ((long)host_cursor % 8) {
423 *((uint64_t*)host_cursor) = 0;
427 for (i = 0; i < var_dump.envc; i++) {
428 *((uint64_t*)host_cursor) = tmp_envs[i];
433 core->vm_regs.rdx = guest_cursor + 8;
435 *((uint64_t*)host_cursor) = 0;
438 for (i = 0; i < var_dump.argc; i++) {
439 *((uint64_t*)host_cursor) = tmp_args[i];
444 core->vm_regs.rcx = guest_cursor + 8;
446 for (i = 0; i < var_dump.argc; i++) {
447 V3_Free(var_dump.argv[i]);
449 for (i = 0; i < var_dump.envc; i++) {
450 V3_Free(var_dump.envp[i]);
453 V3_Free(var_dump.envp);
454 V3_Free(var_dump.argv);
459 static int v3_copy_chunk_vmm64(struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
462 uint_t argc = 0, envc = 0, bytes = 0;
465 PrintDebug(core->vm_info, core, "Initiating copy into vmm\n");
467 int ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rdx, &(core->segments.ds)), &envp);
469 PrintDebug(core->vm_info, core, "Error translating address in rdx\n");
473 ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rcx, &(core->segments.ds)), &argv);
475 PrintDebug(core->vm_info, core, "Error translating address in rcx\n");
479 cursor = (char*)argv;
480 while (*((uint64_t*)cursor) != 0) {
482 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &argvn);
484 PrintDebug(core->vm_info, core, "Error translating address for argvn\n");
490 /* account for new strings */
492 var_dump.argv = (char**)V3_Malloc(sizeof(char*)*argc);
494 if (!var_dump.argv) {
495 PrintError(core->vm_info, core, "Cannot allocate var dump\n");
499 var_dump.argc = argc;
500 bytes += sizeof(char*)*argc;
502 cursor = (char*)argv;
504 while (*((uint64_t*)cursor) != 0) {
506 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &argvn);
508 PrintDebug(core->vm_info, core, "Error translating argvn address\n");
511 /* malloc room for the string */
512 char * tmpstr = (char*)V3_Malloc(strlen((char*)argvn) + 1);
515 PrintError(core->vm_info, core, "Cannot allocate temp string\n");
519 /* copy the pointer */
520 var_dump.argv[i] = tmpstr;
522 /* copy the string */
523 // will always null-terminate tmpstr
524 strncpy(tmpstr, (char*)argvn, strlen((char*)argvn) + 1);
527 bytes += strlen((char*)argvn) + 1;
530 /* stick in new arg strings */
533 char * tmpstr = (char*)V3_Malloc(strlen(argstrs[j]) + 1);
536 PrintError(core->vm_info, core, "Cannot allocate temp string\n");
540 // will always null-terminate tmpstr
541 strncpy(tmpstr, argstrs[j], strlen(argstrs[j]) + 1);
542 var_dump.argv[i] = tmpstr;
543 bytes += strlen(argstrs[j]) + 1;
548 cursor = (char*)envp;
549 while (*((uint64_t*)cursor) != 0) {
551 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &envpn);
553 PrintDebug(core->vm_info, core, "Error translating address for envpn\n");
560 var_dump.envp = (char**)V3_Malloc(sizeof(char*)*envc);
562 if (!var_dump.envp) {
563 PrintError(core->vm_info, core, "Cannot allocate var dump\n");
567 var_dump.envc = envc;
568 bytes += sizeof(uint64_t)*(envc);
571 cursor = (char*)envp;
573 while (*((uint64_t*)cursor) != 0) {
575 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &envpn);
577 PrintDebug(core->vm_info, core, "Error translating address for envpn\n");
580 /* malloc room for the string */
581 char * tmpstr = (char*)V3_Malloc(strlen((char*)envpn) + 1);
584 PrintError(core->vm_info, core, "Cannot allocate temp string\n");
588 /* copy the pointer */
589 var_dump.envp[i] = tmpstr;
591 /* deepcopy the string */
592 // will always null-terminate tmpstr
593 strncpy(tmpstr, (char*)envpn, strlen((char*)envpn) + 1);
596 bytes += strlen((char*)envpn) + 1;
599 /* stick in new env strings */
602 char * tmpstr = (char*)V3_Malloc(strlen(envstrs[j]) + 1);
605 PrintError(core->vm_info, core, "Cannot allocate temp string\n");
608 // will always null-terminate tmpstr
609 strncpy(tmpstr, envstrs[i], strlen(envstrs[j]) + 1);
610 var_dump.envp[i] = tmpstr;
611 bytes += strlen(envstrs[j]) + 1;
616 /* account for padding for strings
617 and 2 null pointers */
618 bytes += (bytes % 8) + 16;
619 var_dump.bytes = bytes;
624 static int v3_inject_strings64 (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
627 uint_t bytes_needed = 0;
629 /* copy out all of the arguments and the environment to the VMM */
630 if ((bytes_needed = v3_copy_chunk_vmm64(core, argstrs, envstrs, argcnt, envcnt)) == -1) {
631 PrintDebug(core->vm_info, core, "Error copying out environment and arguments\n");
635 PrintDebug(core->vm_info, core, "environment successfully copied into VMM\n");
637 inject_gva = v3_prepare_guest_stack(core, bytes_needed);
639 PrintDebug(core->vm_info, core, "Not enough space on user stack\n");
643 v3_copy_chunk_guest64(core, inject_gva, argcnt, envcnt);
648 addr_t v3_prepare_guest_stack (struct guest_info * core, uint_t bytes_needed) {
650 /* TODO: check if we've injected a page fault to get more stack space */
652 // do we have enough room between esp and the next page boundary?
653 uint_t rem_bytes = 4096 - (core->vm_regs.rsp % 4096);
655 if (rem_bytes >= bytes_needed) {
656 return (addr_t)core->vm_regs.rsp;
658 // not enough room, find out how many pages we need (ceiling)
659 uint_t num_pages = (bytes_needed + 4095) / 4096;
661 // check if num_pages are user & writable
664 addr_t gva = core->vm_regs.rsp + rem_bytes;
665 for (; i < num_pages; i++, gva -= 4096) {
666 if (!v3_gva_can_access(core, gva)) {
672 return (addr_t)core->vm_regs.rsp;
676 // inject a page fault
677 pf_error_t fault_type = {
682 // hoping Linux will allocate all pages in between gva and esp
683 v3_inject_guest_pf(core, gva - (num_pages*4096), fault_type);
691 /* TODO: give these next to functions the ability to copy into guest stack */
692 int v3_replace_arg (struct guest_info * core, uint_t argnum, const char * newval) {
698 int v3_replace_env (struct guest_info * core, const char * envname, const char * newval) {
704 int v3_inject_strings (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
706 if (core->cpu_mode == LONG) {
707 if (v3_inject_strings64(core, argstrs, envstrs, argcnt, envcnt) == -1) {
708 PrintDebug(core->vm_info, core, "Error injecting strings into environment (64)\n");
712 if (v3_inject_strings32(core, argstrs, envstrs, argcnt, envcnt) == -1) {
713 PrintDebug(core->vm_info, core, "Error injecting strings into environment (32)\n");