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);
211 var_dump.argc = argc;
212 bytes += sizeof(uint32_t)*argc;
214 cursor = (char*)argv;
216 while (*((uint32_t*)cursor) != 0) {
218 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &argvn);
220 PrintDebug("Error translating argvn address\n");
223 /* malloc room for the string */
224 char * tmpstr = (char*)V3_Malloc(strlen((char*)argvn) + 1);
226 /* copy the pointer */
227 var_dump.argv[i] = tmpstr;
229 /* copy the string */
230 strncpy(tmpstr, (char*)argvn, strlen((char*)argvn) + 1);
233 bytes += strlen((char*)argvn) + 1;
236 /* stick in new arg strings */
239 char * tmpstr = (char*)V3_Malloc(strlen(argstrs[j]) + 1);
240 strncpy(tmpstr, argstrs[i], strlen(argstrs[j]) + 1);
241 var_dump.argv[i] = tmpstr;
242 bytes += strlen(argstrs[j]) + 1;
247 cursor = (char*)envp;
248 while (*((uint32_t*)cursor) != 0) {
250 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &envpn);
252 PrintDebug("Error translating address for envpn\n");
259 var_dump.envp = (char**)V3_Malloc(sizeof(char*)*envc);
260 var_dump.envc = envc;
261 bytes += sizeof(uint32_t)*envc;
263 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");
272 /* malloc room for the string */
273 char * tmpstr = (char*)V3_Malloc(strlen((char*)envpn) + 1);
275 /* copy the pointer */
276 var_dump.envp[i] = tmpstr;
278 /* deepcopy the string */
279 strncpy(tmpstr, (char*)envpn, strlen((char*)envpn) + 1);
282 bytes += strlen((char*)envpn) + 1;
285 /* put in our new env strings */
288 char * tmpstr = (char*)V3_Malloc(strlen(envstrs[j]) + 1);
289 strncpy(tmpstr, envstrs[j], strlen(envstrs[j]) + 1);
290 var_dump.envp[i] = tmpstr;
291 bytes += strlen(envstrs[j]) + 1;
296 /* account for padding for strings
297 and 2 null pointers */
298 bytes += (bytes % 4) + 8;
299 var_dump.bytes = bytes;
304 static int v3_inject_strings32 (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
307 uint_t bytes_needed = 0;
309 /* copy out all of the arguments and the environment to the VMM */
310 if ((bytes_needed = v3_copy_chunk_vmm32(core, argstrs, envstrs, argcnt, envcnt)) == -1) {
311 PrintDebug("Error copying out environment and arguments\n");
315 PrintDebug("environment successfully copied into VMM\n");
317 inject_gva = v3_prepare_guest_stack(core, bytes_needed);
319 PrintDebug("Not enough space on user stack\n");
323 v3_copy_chunk_guest32(core, inject_gva, argcnt, envcnt);
329 static int v3_copy_chunk_guest64(struct guest_info * core, addr_t gva, uint_t argcnt, uint_t envcnt) {
333 uint64_t tmp_args[var_dump.argc];
334 uint64_t tmp_envs[var_dump.envc];
336 PrintDebug("Initiating copy into guest (64bit)\n");
338 ret = v3_gva_to_hva(core, get_addr_linear(core, gva, &(core->segments.ds)), &hva);
340 PrintDebug("Error translating gva in v3_copy_chunk_2guest64\n");
344 char * host_cursor = (char*) hva;
345 uint64_t guest_cursor = (uint64_t) gva;
346 host_cursor -= strlen(var_dump.envp[i]) + 1;
347 guest_cursor -= strlen(var_dump.envp[i]) + 1;
348 while (i < var_dump.envc) {
349 //PrintDebug("Copying envvar#%d: %s\n", i, var_dump.envp[i]);
350 strcpy(host_cursor, var_dump.envp[i]);
351 tmp_envs[i] = guest_cursor;
353 if (i != var_dump.envc) {
354 host_cursor -= strlen(var_dump.envp[i]) + 1;
355 guest_cursor -= strlen(var_dump.envp[i]) + 1;
360 host_cursor -= strlen(var_dump.argv[i]) + 1;
361 guest_cursor -= strlen(var_dump.argv[i]) + 1;
362 while (i < var_dump.argc) {
363 //PrintDebug("Copying arg #%d: %s\n", i, var_dump.argv[i]);
364 strcpy(host_cursor, var_dump.argv[i]);
365 tmp_args[i] = guest_cursor;
367 if (i != var_dump.argc) {
368 host_cursor -= strlen(var_dump.argv[i]) + 1;
369 guest_cursor -= strlen(var_dump.argv[i]) + 1;
376 while ((long)host_cursor % 8) {
385 *((uint64_t*)host_cursor) = 0;
389 for (i = 0; i < var_dump.envc; i++) {
390 *((uint64_t*)host_cursor) = tmp_envs[i];
395 core->vm_regs.rdx = guest_cursor + 8;
397 *((uint64_t*)host_cursor) = 0;
400 for (i = 0; i < var_dump.argc; i++) {
401 *((uint64_t*)host_cursor) = tmp_args[i];
406 core->vm_regs.rcx = guest_cursor + 8;
408 for (i = 0; i < var_dump.argc; i++) {
409 V3_Free(var_dump.argv[i]);
411 for (i = 0; i < var_dump.envc; i++) {
412 V3_Free(var_dump.envp[i]);
415 V3_Free(var_dump.envp);
416 V3_Free(var_dump.argv);
421 static int v3_copy_chunk_vmm64(struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
424 uint_t argc = 0, envc = 0, bytes = 0;
427 PrintDebug("Initiating copy into vmm\n");
429 int ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rdx, &(core->segments.ds)), &envp);
431 PrintDebug("Error translating address in rdx\n");
435 ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rcx, &(core->segments.ds)), &argv);
437 PrintDebug("Error translating address in rcx\n");
441 cursor = (char*)argv;
442 while (*((uint64_t*)cursor) != 0) {
444 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &argvn);
446 PrintDebug("Error translating address for argvn\n");
452 /* account for new strings */
454 var_dump.argv = (char**)V3_Malloc(sizeof(char*)*argc);
455 var_dump.argc = argc;
456 bytes += sizeof(char*)*argc;
458 cursor = (char*)argv;
460 while (*((uint64_t*)cursor) != 0) {
462 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &argvn);
464 PrintDebug("Error translating argvn address\n");
467 /* malloc room for the string */
468 char * tmpstr = (char*)V3_Malloc(strlen((char*)argvn) + 1);
470 /* copy the pointer */
471 var_dump.argv[i] = tmpstr;
473 /* copy the string */
474 strncpy(tmpstr, (char*)argvn, strlen((char*)argvn) + 1);
477 bytes += strlen((char*)argvn) + 1;
480 /* stick in new arg strings */
483 char * tmpstr = (char*)V3_Malloc(strlen(argstrs[j]) + 1);
484 strncpy(tmpstr, argstrs[j], strlen(argstrs[j]) + 1);
485 var_dump.argv[i] = tmpstr;
486 bytes += strlen(argstrs[j]) + 1;
491 cursor = (char*)envp;
492 while (*((uint64_t*)cursor) != 0) {
494 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &envpn);
496 PrintDebug("Error translating address for envpn\n");
503 var_dump.envp = (char**)V3_Malloc(sizeof(char*)*envc);
504 var_dump.envc = envc;
505 bytes += sizeof(uint64_t)*(envc);
508 cursor = (char*)envp;
510 while (*((uint64_t*)cursor) != 0) {
512 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &envpn);
514 PrintDebug("Error translating address for envpn\n");
517 /* malloc room for the string */
518 char * tmpstr = (char*)V3_Malloc(strlen((char*)envpn) + 1);
520 /* copy the pointer */
521 var_dump.envp[i] = tmpstr;
523 /* deepcopy the string */
524 strncpy(tmpstr, (char*)envpn, strlen((char*)envpn) + 1);
527 bytes += strlen((char*)envpn) + 1;
530 /* stick in new env strings */
533 char * tmpstr = (char*)V3_Malloc(strlen(envstrs[j]) + 1);
534 strncpy(tmpstr, envstrs[i], strlen(envstrs[j]) + 1);
535 var_dump.envp[i] = tmpstr;
536 bytes += strlen(envstrs[j]) + 1;
541 /* account for padding for strings
542 and 2 null pointers */
543 bytes += (bytes % 8) + 16;
544 var_dump.bytes = bytes;
549 static int v3_inject_strings64 (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
552 uint_t bytes_needed = 0;
554 /* copy out all of the arguments and the environment to the VMM */
555 if ((bytes_needed = v3_copy_chunk_vmm64(core, argstrs, envstrs, argcnt, envcnt)) == -1) {
556 PrintDebug("Error copying out environment and arguments\n");
560 PrintDebug("environment successfully copied into VMM\n");
562 inject_gva = v3_prepare_guest_stack(core, bytes_needed);
564 PrintDebug("Not enough space on user stack\n");
568 v3_copy_chunk_guest64(core, inject_gva, argcnt, envcnt);
573 addr_t v3_prepare_guest_stack (struct guest_info * core, uint_t bytes_needed) {
575 /* TODO: check if we've injected a page fault to get more stack space */
577 // do we have enough room between esp and the next page boundary?
578 uint_t rem_bytes = 4096 - (core->vm_regs.rsp % 4096);
580 if (rem_bytes >= bytes_needed) {
581 return (addr_t)core->vm_regs.rsp;
583 // not enough room, find out how many pages we need (ceiling)
584 uint_t num_pages = (bytes_needed + 4095) / 4096;
586 // check if num_pages are user & writable
589 addr_t gva = core->vm_regs.rsp + rem_bytes;
590 for (; i < num_pages; i++, gva -= 4096) {
591 if (!v3_gva_can_access(core, gva)) {
597 return (addr_t)core->vm_regs.rsp;
601 // inject a page fault
602 pf_error_t fault_type = {
607 // hoping Linux will allocate all pages in between gva and esp
608 v3_inject_guest_pf(core, gva - (num_pages*4096), fault_type);
616 /* TODO: give these next to functions the ability to copy into guest stack */
617 int v3_replace_arg (struct guest_info * core, uint_t argnum, const char * newval) {
623 int v3_replace_env (struct guest_info * core, const char * envname, const char * newval) {
629 int v3_inject_strings (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
631 if (core->cpu_mode == LONG) {
632 if (v3_inject_strings64(core, argstrs, envstrs, argcnt, envcnt) == -1) {
633 PrintDebug("Error injecting strings into environment (64)\n");
637 if (v3_inject_strings32(core, argstrs, envstrs, argcnt, envcnt) == -1) {
638 PrintDebug("Error injecting strings into environment (32)\n");