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/vmm_process_environment.h>
23 #include <palacios/vm_guest.h>
24 #include <palacios/vm_guest_mem.h>
26 static int v3_copy_chunk_guest32(struct guest_info * core, addr_t gva, uint_t argcnt, uint_t envcnt) {
30 uint32_t tmp_args[core->var_dump.argc];
31 uint32_t tmp_envs[core->var_dump.envc];
33 PrintDebug("Initiating copy into guest (32bit)\n");
35 ret = v3_gva_to_hva(core, get_addr_linear(core, gva, &(core->segments.ds)), &hva);
37 PrintDebug("Error translating gva in v3_copy_chunk_2guest\n");
41 // copy the env strings (we're moving top-down through the stack)
42 char * host_cursor = (char*) hva;
43 uint32_t guest_cursor = (uint32_t) gva;
44 host_cursor -= strlen(core->var_dump.envp[i]) + 1;
45 guest_cursor -= strlen(core->var_dump.envp[i]) + 1;
46 while (i < core->var_dump.envc) {
47 //PrintDebug("Copying envvar#%d: %s\n", i, core->var_dump.envp[i]);
48 strcpy(host_cursor, core->var_dump.envp[i]);
49 tmp_envs[i] = guest_cursor;
51 if (i != core->var_dump.envc) {
52 host_cursor -= strlen(core->var_dump.envp[i]) + 1;
53 guest_cursor -= strlen(core->var_dump.envp[i]) + 1;
57 // then the arg strings
59 host_cursor -= strlen(core->var_dump.argv[i]) + 1;
60 guest_cursor -= strlen(core->var_dump.argv[i]) + 1;
61 while (i < core->var_dump.argc) {
62 //PrintDebug("Copying arg #%d: %s\n", i, core->var_dump.argv[i]);
63 strcpy(host_cursor, core->var_dump.argv[i]);
64 tmp_args[i] = guest_cursor;
66 if (i != core->var_dump.argc) {
67 host_cursor -= strlen(core->var_dump.argv[i]) + 1;
68 guest_cursor -= strlen(core->var_dump.argv[i]) + 1;
76 while ((long)host_cursor % 4) {
85 *((uint32_t*)host_cursor) = 0;
89 for (i = 0; i < core->var_dump.envc; i++) {
90 *((uint32_t*)host_cursor) = tmp_envs[i];
95 core->vm_regs.rdx = guest_cursor + 4;
97 *((uint32_t*)host_cursor) = 0;
100 for (i = 0; i < core->var_dump.argc; i++) {
101 *((uint32_t*)host_cursor) = tmp_args[i];
106 core->vm_regs.rcx = guest_cursor + 4;
108 // free up our temporary storage in the VMM
109 for (i = 0; i < core->var_dump.argc; i++) {
110 V3_Free(core->var_dump.argv[i]);
112 for (i = 0; i < core->var_dump.envc; i++) {
113 V3_Free(core->var_dump.envp[i]);
116 V3_Free(core->var_dump.envp);
117 V3_Free(core->var_dump.argv);
122 static int v3_copy_chunk_vmm32(struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
125 uint_t argc = 0, envc = 0, bytes = 0;
128 PrintDebug("Initiating copy into vmm\n");
130 int ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rdx, &(core->segments.ds)), &envp);
132 PrintDebug("Error translating address in rdx\n");
136 ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rcx, &(core->segments.ds)), &argv);
138 PrintDebug("Error translating address in rcx\n");
142 cursor = (char*)argv;
143 while (*((uint32_t*)cursor) != 0) {
145 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &argvn);
147 PrintDebug("Error translating address for argvn\n");
153 /* account for new args */
155 core->var_dump.argv = (char**)V3_Malloc(sizeof(char*)*argc);
156 core->var_dump.argc = argc;
157 bytes += sizeof(uint32_t)*argc;
159 cursor = (char*)argv;
161 while (*((uint32_t*)cursor) != 0) {
163 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &argvn);
165 PrintDebug("Error translating argvn address\n");
168 /* malloc room for the string */
169 char * tmpstr = (char*)V3_Malloc(strlen((char*)argvn) + 1);
171 /* copy the pointer */
172 core->var_dump.argv[i] = tmpstr;
174 /* copy the string */
175 strncpy(tmpstr, (char*)argvn, strlen((char*)argvn) + 1);
178 bytes += strlen((char*)argvn) + 1;
181 /* stick in new arg strings */
184 char * tmpstr = (char*)V3_Malloc(strlen(argstrs[j]) + 1);
185 strncpy(tmpstr, argstrs[i], strlen(argstrs[j]) + 1);
186 core->var_dump.argv[i] = tmpstr;
187 bytes += strlen(argstrs[j]) + 1;
192 cursor = (char*)envp;
193 while (*((uint32_t*)cursor) != 0) {
195 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &envpn);
197 PrintDebug("Error translating address for envpn\n");
204 core->var_dump.envp = (char**)V3_Malloc(sizeof(char*)*envc);
205 core->var_dump.envc = envc;
206 bytes += sizeof(uint32_t)*envc;
208 cursor = (char*)envp;
210 while (*((uint32_t*)cursor) != 0) {
212 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &envpn);
214 PrintDebug("Error translating address for envpn\n");
217 /* malloc room for the string */
218 char * tmpstr = (char*)V3_Malloc(strlen((char*)envpn) + 1);
220 /* copy the pointer */
221 core->var_dump.envp[i] = tmpstr;
223 /* deepcopy the string */
224 strncpy(tmpstr, (char*)envpn, strlen((char*)envpn) + 1);
227 bytes += strlen((char*)envpn) + 1;
230 /* put in our new env strings */
233 char * tmpstr = (char*)V3_Malloc(strlen(envstrs[j]) + 1);
234 strncpy(tmpstr, envstrs[j], strlen(envstrs[j]) + 1);
235 core->var_dump.envp[i] = tmpstr;
236 bytes += strlen(envstrs[j]) + 1;
241 /* account for padding for strings
242 and 2 null pointers */
243 bytes += (bytes % 4) + 8;
244 core->var_dump.bytes = bytes;
249 static int v3_inject_strings32 (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
252 uint_t bytes_needed = 0;
254 /* copy out all of the arguments and the environment to the VMM */
255 if ((bytes_needed = v3_copy_chunk_vmm32(core, argstrs, envstrs, argcnt, envcnt)) == -1) {
256 PrintDebug("Error copying out environment and arguments\n");
260 PrintDebug("environment successfully copied into VMM\n");
262 inject_gva = v3_prepare_guest_stack(core, bytes_needed);
264 PrintDebug("Not enough space on user stack\n");
268 v3_copy_chunk_guest32(core, inject_gva, argcnt, envcnt);
274 static int v3_copy_chunk_guest64(struct guest_info * core, addr_t gva, uint_t argcnt, uint_t envcnt) {
278 uint64_t tmp_args[core->var_dump.argc];
279 uint64_t tmp_envs[core->var_dump.envc];
281 PrintDebug("Initiating copy into guest (64bit)\n");
283 ret = v3_gva_to_hva(core, get_addr_linear(core, gva, &(core->segments.ds)), &hva);
285 PrintDebug("Error translating gva in v3_copy_chunk_2guest64\n");
289 char * host_cursor = (char*) hva;
290 uint64_t guest_cursor = (uint64_t) gva;
291 host_cursor -= strlen(core->var_dump.envp[i]) + 1;
292 guest_cursor -= strlen(core->var_dump.envp[i]) + 1;
293 while (i < core->var_dump.envc) {
294 //PrintDebug("Copying envvar#%d: %s\n", i, core->var_dump.envp[i]);
295 strcpy(host_cursor, core->var_dump.envp[i]);
296 tmp_envs[i] = guest_cursor;
298 if (i != core->var_dump.envc) {
299 host_cursor -= strlen(core->var_dump.envp[i]) + 1;
300 guest_cursor -= strlen(core->var_dump.envp[i]) + 1;
305 host_cursor -= strlen(core->var_dump.argv[i]) + 1;
306 guest_cursor -= strlen(core->var_dump.argv[i]) + 1;
307 while (i < core->var_dump.argc) {
308 //PrintDebug("Copying arg #%d: %s\n", i, core->var_dump.argv[i]);
309 strcpy(host_cursor, core->var_dump.argv[i]);
310 tmp_args[i] = guest_cursor;
312 if (i != core->var_dump.argc) {
313 host_cursor -= strlen(core->var_dump.argv[i]) + 1;
314 guest_cursor -= strlen(core->var_dump.argv[i]) + 1;
321 while ((long)host_cursor % 8) {
330 *((uint64_t*)host_cursor) = 0;
334 for (i = 0; i < core->var_dump.envc; i++) {
335 *((uint64_t*)host_cursor) = tmp_envs[i];
340 core->vm_regs.rdx = guest_cursor + 8;
342 *((uint64_t*)host_cursor) = 0;
345 for (i = 0; i < core->var_dump.argc; i++) {
346 *((uint64_t*)host_cursor) = tmp_args[i];
351 core->vm_regs.rcx = guest_cursor + 8;
353 for (i = 0; i < core->var_dump.argc; i++) {
354 V3_Free(core->var_dump.argv[i]);
356 for (i = 0; i < core->var_dump.envc; i++) {
357 V3_Free(core->var_dump.envp[i]);
360 V3_Free(core->var_dump.envp);
361 V3_Free(core->var_dump.argv);
366 static int v3_copy_chunk_vmm64(struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
369 uint_t argc = 0, envc = 0, bytes = 0;
372 PrintDebug("Initiating copy into vmm\n");
374 int ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rdx, &(core->segments.ds)), &envp);
376 PrintDebug("Error translating address in rdx\n");
380 ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rcx, &(core->segments.ds)), &argv);
382 PrintDebug("Error translating address in rcx\n");
386 cursor = (char*)argv;
387 while (*((uint64_t*)cursor) != 0) {
389 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &argvn);
391 PrintDebug("Error translating address for argvn\n");
397 /* account for new strings */
399 core->var_dump.argv = (char**)V3_Malloc(sizeof(char*)*argc);
400 core->var_dump.argc = argc;
401 bytes += sizeof(char*)*argc;
403 cursor = (char*)argv;
405 while (*((uint64_t*)cursor) != 0) {
407 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &argvn);
409 PrintDebug("Error translating argvn address\n");
412 /* malloc room for the string */
413 char * tmpstr = (char*)V3_Malloc(strlen((char*)argvn) + 1);
415 /* copy the pointer */
416 core->var_dump.argv[i] = tmpstr;
418 /* copy the string */
419 strncpy(tmpstr, (char*)argvn, strlen((char*)argvn) + 1);
422 bytes += strlen((char*)argvn) + 1;
425 /* stick in new arg strings */
428 char * tmpstr = (char*)V3_Malloc(strlen(argstrs[j]) + 1);
429 strncpy(tmpstr, argstrs[j], strlen(argstrs[j]) + 1);
430 core->var_dump.argv[i] = tmpstr;
431 bytes += strlen(argstrs[j]) + 1;
436 cursor = (char*)envp;
437 while (*((uint64_t*)cursor) != 0) {
439 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &envpn);
441 PrintDebug("Error translating address for envpn\n");
448 core->var_dump.envp = (char**)V3_Malloc(sizeof(char*)*envc);
449 core->var_dump.envc = envc;
450 bytes += sizeof(uint64_t)*(envc);
453 cursor = (char*)envp;
455 while (*((uint64_t*)cursor) != 0) {
457 ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &envpn);
459 PrintDebug("Error translating address for envpn\n");
462 /* malloc room for the string */
463 char * tmpstr = (char*)V3_Malloc(strlen((char*)envpn) + 1);
465 /* copy the pointer */
466 core->var_dump.envp[i] = tmpstr;
468 /* deepcopy the string */
469 strncpy(tmpstr, (char*)envpn, strlen((char*)envpn) + 1);
472 bytes += strlen((char*)envpn) + 1;
475 /* stick in new env strings */
478 char * tmpstr = (char*)V3_Malloc(strlen(envstrs[j]) + 1);
479 strncpy(tmpstr, envstrs[i], strlen(envstrs[j]) + 1);
480 core->var_dump.envp[i] = tmpstr;
481 bytes += strlen(envstrs[j]) + 1;
486 /* account for padding for strings
487 and 2 null pointers */
488 bytes += (bytes % 8) + 16;
489 core->var_dump.bytes = bytes;
494 static int v3_inject_strings64 (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
497 uint_t bytes_needed = 0;
499 /* copy out all of the arguments and the environment to the VMM */
500 if ((bytes_needed = v3_copy_chunk_vmm64(core, argstrs, envstrs, argcnt, envcnt)) == -1) {
501 PrintDebug("Error copying out environment and arguments\n");
505 PrintDebug("environment successfully copied into VMM\n");
507 inject_gva = v3_prepare_guest_stack(core, bytes_needed);
509 PrintDebug("Not enough space on user stack\n");
513 v3_copy_chunk_guest64(core, inject_gva, argcnt, envcnt);
518 addr_t v3_prepare_guest_stack (struct guest_info * core, uint_t bytes_needed) {
520 /* TODO: check if we've injected a page fault to get more stack space */
522 // do we have enough room between esp and the next page boundary?
523 uint_t rem_bytes = 4096 - (core->vm_regs.rsp % 4096);
525 if (rem_bytes >= bytes_needed) {
526 return (addr_t)core->vm_regs.rsp;
528 // not enough room, find out how many pages we need (ceiling)
529 uint_t num_pages = (bytes_needed + 4095) / 4096;
531 // check if num_pages are user & writable
534 addr_t gva = core->vm_regs.rsp + rem_bytes;
535 for (; i < num_pages; i++, gva -= 4096) {
536 if (!v3_gva_can_access(core, gva)) {
542 return (addr_t)core->vm_regs.rsp;
546 // inject a page fault
547 pf_error_t fault_type = {
552 // hoping Linux will allocate all pages in between gva and esp
553 v3_inject_guest_pf(core, gva - (num_pages*4096), fault_type);
561 /* TODO: give these next to functions the ability to copy into guest stack */
562 int v3_replace_arg (struct guest_info * core, uint_t argnum, const char * newval) {
568 int v3_replace_env (struct guest_info * core, const char * envname, const char * newval) {
574 int v3_inject_strings (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
576 if (core->cpu_mode == LONG || core->cpu_mode == LONG_32_COMPAT) {
577 if (v3_inject_strings64(core, argstrs, envstrs, argcnt, envcnt) == -1) {
578 PrintDebug("Error injecting strings into environment (64)\n");
582 if (v3_inject_strings32(core, argstrs, envstrs, argcnt, envcnt) == -1) {
583 PrintDebug("Error injecting strings into environment (32)\n");