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("Initiating copy into guest (32bit)\n");
90 ret = v3_gva_to_hva(core, get_addr_linear(core, gva, &(core->segments.ds)), &hva);
92 PrintDebug("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("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("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("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("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("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("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("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("Error translating argvn address\n");
229 /* malloc room for the string */
230 char * tmpstr = (char*)V3_Malloc(strlen((char*)argvn) + 1);
233 PrintError("Cannot allocate temporary\n");
237 /* copy the pointer */
238 var_dump.argv[i] = tmpstr;
240 /* copy the string */
241 strncpy(tmpstr, (char*)argvn, strlen((char*)argvn) + 1);
244 bytes += strlen((char*)argvn) + 1;
247 /* stick in new arg strings */
250 char * tmpstr = (char*)V3_Malloc(strlen(argstrs[j]) + 1);
253 PrintError("Cannot allocate temp string\n");
257 strncpy(tmpstr, argstrs[i], strlen(argstrs[j]) + 1);
258 var_dump.argv[i] = tmpstr;
259 bytes += strlen(argstrs[j]) + 1;
264 cursor = (char*)envp;
265 while (*((uint32_t*)cursor) != 0) {
267 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &envpn);
269 PrintDebug("Error translating address for envpn\n");
276 var_dump.envp = (char**)V3_Malloc(sizeof(char*)*envc);
278 if (!var_dump.envp) {
279 PrintError("Cannot allocate var dump\n");
283 var_dump.envc = envc;
284 bytes += sizeof(uint32_t)*envc;
286 cursor = (char*)envp;
288 while (*((uint32_t*)cursor) != 0) {
290 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &envpn);
292 PrintDebug("Error translating address for envpn\n");
295 /* malloc room for the string */
296 char * tmpstr = (char*)V3_Malloc(strlen((char*)envpn) + 1);
299 PrintError("Cannot allocate temp string\n");
303 /* copy the pointer */
304 var_dump.envp[i] = tmpstr;
306 /* deepcopy the string */
307 strncpy(tmpstr, (char*)envpn, strlen((char*)envpn) + 1);
310 bytes += strlen((char*)envpn) + 1;
313 /* put in our new env strings */
316 char * tmpstr = (char*)V3_Malloc(strlen(envstrs[j]) + 1);
319 PrintError("Cannot allocate temp string\n");
323 strncpy(tmpstr, envstrs[j], strlen(envstrs[j]) + 1);
324 var_dump.envp[i] = tmpstr;
325 bytes += strlen(envstrs[j]) + 1;
330 /* account for padding for strings
331 and 2 null pointers */
332 bytes += (bytes % 4) + 8;
333 var_dump.bytes = bytes;
338 static int v3_inject_strings32 (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
341 uint_t bytes_needed = 0;
343 /* copy out all of the arguments and the environment to the VMM */
344 if ((bytes_needed = v3_copy_chunk_vmm32(core, argstrs, envstrs, argcnt, envcnt)) == -1) {
345 PrintDebug("Error copying out environment and arguments\n");
349 PrintDebug("environment successfully copied into VMM\n");
351 inject_gva = v3_prepare_guest_stack(core, bytes_needed);
353 PrintDebug("Not enough space on user stack\n");
357 v3_copy_chunk_guest32(core, inject_gva, argcnt, envcnt);
363 static int v3_copy_chunk_guest64(struct guest_info * core, addr_t gva, uint_t argcnt, uint_t envcnt) {
367 uint64_t tmp_args[var_dump.argc];
368 uint64_t tmp_envs[var_dump.envc];
370 PrintDebug("Initiating copy into guest (64bit)\n");
372 ret = v3_gva_to_hva(core, get_addr_linear(core, gva, &(core->segments.ds)), &hva);
374 PrintDebug("Error translating gva in v3_copy_chunk_2guest64\n");
378 char * host_cursor = (char*) hva;
379 uint64_t guest_cursor = (uint64_t) gva;
380 host_cursor -= strlen(var_dump.envp[i]) + 1;
381 guest_cursor -= strlen(var_dump.envp[i]) + 1;
382 while (i < var_dump.envc) {
383 //PrintDebug("Copying envvar#%d: %s\n", i, var_dump.envp[i]);
384 strcpy(host_cursor, var_dump.envp[i]);
385 tmp_envs[i] = guest_cursor;
387 if (i != var_dump.envc) {
388 host_cursor -= strlen(var_dump.envp[i]) + 1;
389 guest_cursor -= strlen(var_dump.envp[i]) + 1;
394 host_cursor -= strlen(var_dump.argv[i]) + 1;
395 guest_cursor -= strlen(var_dump.argv[i]) + 1;
396 while (i < var_dump.argc) {
397 //PrintDebug("Copying arg #%d: %s\n", i, var_dump.argv[i]);
398 strcpy(host_cursor, var_dump.argv[i]);
399 tmp_args[i] = guest_cursor;
401 if (i != var_dump.argc) {
402 host_cursor -= strlen(var_dump.argv[i]) + 1;
403 guest_cursor -= strlen(var_dump.argv[i]) + 1;
410 while ((long)host_cursor % 8) {
419 *((uint64_t*)host_cursor) = 0;
423 for (i = 0; i < var_dump.envc; i++) {
424 *((uint64_t*)host_cursor) = tmp_envs[i];
429 core->vm_regs.rdx = guest_cursor + 8;
431 *((uint64_t*)host_cursor) = 0;
434 for (i = 0; i < var_dump.argc; i++) {
435 *((uint64_t*)host_cursor) = tmp_args[i];
440 core->vm_regs.rcx = guest_cursor + 8;
442 for (i = 0; i < var_dump.argc; i++) {
443 V3_Free(var_dump.argv[i]);
445 for (i = 0; i < var_dump.envc; i++) {
446 V3_Free(var_dump.envp[i]);
449 V3_Free(var_dump.envp);
450 V3_Free(var_dump.argv);
455 static int v3_copy_chunk_vmm64(struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
458 uint_t argc = 0, envc = 0, bytes = 0;
461 PrintDebug("Initiating copy into vmm\n");
463 int ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rdx, &(core->segments.ds)), &envp);
465 PrintDebug("Error translating address in rdx\n");
469 ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rcx, &(core->segments.ds)), &argv);
471 PrintDebug("Error translating address in rcx\n");
475 cursor = (char*)argv;
476 while (*((uint64_t*)cursor) != 0) {
478 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &argvn);
480 PrintDebug("Error translating address for argvn\n");
486 /* account for new strings */
488 var_dump.argv = (char**)V3_Malloc(sizeof(char*)*argc);
490 if (!var_dump.argv) {
491 PrintError("Cannot allocate var dump\n");
495 var_dump.argc = argc;
496 bytes += sizeof(char*)*argc;
498 cursor = (char*)argv;
500 while (*((uint64_t*)cursor) != 0) {
502 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &argvn);
504 PrintDebug("Error translating argvn address\n");
507 /* malloc room for the string */
508 char * tmpstr = (char*)V3_Malloc(strlen((char*)argvn) + 1);
511 PrintError("Cannot allocate temp string\n");
515 /* copy the pointer */
516 var_dump.argv[i] = tmpstr;
518 /* copy the string */
519 strncpy(tmpstr, (char*)argvn, strlen((char*)argvn) + 1);
522 bytes += strlen((char*)argvn) + 1;
525 /* stick in new arg strings */
528 char * tmpstr = (char*)V3_Malloc(strlen(argstrs[j]) + 1);
531 PrintError("Cannot allocate temp string\n");
535 strncpy(tmpstr, argstrs[j], strlen(argstrs[j]) + 1);
536 var_dump.argv[i] = tmpstr;
537 bytes += strlen(argstrs[j]) + 1;
542 cursor = (char*)envp;
543 while (*((uint64_t*)cursor) != 0) {
545 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &envpn);
547 PrintDebug("Error translating address for envpn\n");
554 var_dump.envp = (char**)V3_Malloc(sizeof(char*)*envc);
556 if (!var_dump.envp) {
557 PrintError("Cannot allocate var dump\n");
561 var_dump.envc = envc;
562 bytes += sizeof(uint64_t)*(envc);
565 cursor = (char*)envp;
567 while (*((uint64_t*)cursor) != 0) {
569 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &envpn);
571 PrintDebug("Error translating address for envpn\n");
574 /* malloc room for the string */
575 char * tmpstr = (char*)V3_Malloc(strlen((char*)envpn) + 1);
578 PrintError("Cannot allocate temp string\n");
582 /* copy the pointer */
583 var_dump.envp[i] = tmpstr;
585 /* deepcopy the string */
586 strncpy(tmpstr, (char*)envpn, strlen((char*)envpn) + 1);
589 bytes += strlen((char*)envpn) + 1;
592 /* stick in new env strings */
595 char * tmpstr = (char*)V3_Malloc(strlen(envstrs[j]) + 1);
598 PrintError("Cannot allocate temp string\n");
602 strncpy(tmpstr, envstrs[i], strlen(envstrs[j]) + 1);
603 var_dump.envp[i] = tmpstr;
604 bytes += strlen(envstrs[j]) + 1;
609 /* account for padding for strings
610 and 2 null pointers */
611 bytes += (bytes % 8) + 16;
612 var_dump.bytes = bytes;
617 static int v3_inject_strings64 (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
620 uint_t bytes_needed = 0;
622 /* copy out all of the arguments and the environment to the VMM */
623 if ((bytes_needed = v3_copy_chunk_vmm64(core, argstrs, envstrs, argcnt, envcnt)) == -1) {
624 PrintDebug("Error copying out environment and arguments\n");
628 PrintDebug("environment successfully copied into VMM\n");
630 inject_gva = v3_prepare_guest_stack(core, bytes_needed);
632 PrintDebug("Not enough space on user stack\n");
636 v3_copy_chunk_guest64(core, inject_gva, argcnt, envcnt);
641 addr_t v3_prepare_guest_stack (struct guest_info * core, uint_t bytes_needed) {
643 /* TODO: check if we've injected a page fault to get more stack space */
645 // do we have enough room between esp and the next page boundary?
646 uint_t rem_bytes = 4096 - (core->vm_regs.rsp % 4096);
648 if (rem_bytes >= bytes_needed) {
649 return (addr_t)core->vm_regs.rsp;
651 // not enough room, find out how many pages we need (ceiling)
652 uint_t num_pages = (bytes_needed + 4095) / 4096;
654 // check if num_pages are user & writable
657 addr_t gva = core->vm_regs.rsp + rem_bytes;
658 for (; i < num_pages; i++, gva -= 4096) {
659 if (!v3_gva_can_access(core, gva)) {
665 return (addr_t)core->vm_regs.rsp;
669 // inject a page fault
670 pf_error_t fault_type = {
675 // hoping Linux will allocate all pages in between gva and esp
676 v3_inject_guest_pf(core, gva - (num_pages*4096), fault_type);
684 /* TODO: give these next to functions the ability to copy into guest stack */
685 int v3_replace_arg (struct guest_info * core, uint_t argnum, const char * newval) {
691 int v3_replace_env (struct guest_info * core, const char * envname, const char * newval) {
697 int v3_inject_strings (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
699 if (core->cpu_mode == LONG) {
700 if (v3_inject_strings64(core, argstrs, envstrs, argcnt, envcnt) == -1) {
701 PrintDebug("Error injecting strings into environment (64)\n");
705 if (v3_inject_strings32(core, argstrs, envstrs, argcnt, envcnt) == -1) {
706 PrintDebug("Error injecting strings into environment (32)\n");