Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


ce2f135ed3b675c835b21ff16bfd3aef44eee0fa
[palacios.git] / palacios / src / gears / ext_process_environment.c
1 /* 
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.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
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.
13  *
14  * Author: Kyle C. Hale <kh@u.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_decoder.h>
22 #include <palacios/vm_guest.h>
23 #include <palacios/vm_guest_mem.h>
24
25 #include <gears/process_environment.h>
26
27 static struct v3_execve_varchunk var_dump;
28
29
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) {
33
34     v3_reg_t guest_cr3 = 0;
35     pf_error_t access_type;
36     pt_access_status_t access_status;
37
38     access_type.write = 1;
39     access_type.user = 1;
40
41     if (core->mem_mode == PHYSICAL_MEM) {
42         return -1;
43     }
44
45     if (core->shdw_pg_mode == SHADOW_PAGING) {
46         guest_cr3 = core->shdw_pg_state.guest_cr3;
47     } else {
48         guest_cr3 = core->ctrl_regs.cr3;
49     }
50
51     // guest is in paged mode
52     switch (core->cpu_mode) {
53     case PROTECTED:
54         if (v3_check_guest_pt_32(core, guest_cr3, gva, access_type, &access_status) == -1) {
55             return -1;
56         }
57         break;
58     case PROTECTED_PAE:
59         if (v3_check_guest_pt_32pae(core, guest_cr3, gva, access_type, &access_status) == -1) {
60             return -1;
61         }
62         break;
63     case LONG:
64     case LONG_32_COMPAT:
65     case LONG_16_COMPAT:
66         if (v3_check_guest_pt_64(core, guest_cr3, gva, access_type, &access_status) == -1) {
67             return -1;
68         }
69         break;
70     default:
71         return -1;
72     }
73
74     if (access_status != PT_ACCESS_OK) {
75         return 0;
76     } else {
77         return 1;
78     }
79 }
80
81 static int v3_copy_chunk_guest32(struct guest_info * core, addr_t gva, uint_t argcnt, uint_t envcnt) {
82
83     int ret = 0, i = 0;
84     addr_t hva;
85     uint32_t tmp_args[var_dump.argc];
86     uint32_t tmp_envs[var_dump.envc];
87
88     PrintDebug(core->vm_info, core, "Initiating copy into guest (32bit)\n");
89     
90     ret = v3_gva_to_hva(core, get_addr_linear(core, gva, &(core->segments.ds)), &hva);
91     if (ret == -1) {
92         PrintDebug(core->vm_info, core, "Error translating gva in v3_copy_chunk_2guest\n");
93         return -1;
94     }
95     
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;
105         i++;
106         if (i != var_dump.envc) { 
107             host_cursor -= strlen(var_dump.envp[i]) + 1;
108             guest_cursor -= strlen(var_dump.envp[i]) + 1;
109         }
110     }
111         
112     // then the arg strings
113     i = 0;
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;
120         i++;
121         if (i != var_dump.argc) {
122             host_cursor -= strlen(var_dump.argv[i]) + 1;
123             guest_cursor -= strlen(var_dump.argv[i]) + 1;
124         }
125     }
126
127     
128     // padding
129     host_cursor--;  
130     guest_cursor--;
131     while ((long)host_cursor % 4) {
132         *host_cursor = 0;
133         host_cursor--;
134         guest_cursor--;
135     }
136
137     // null ptr
138     host_cursor -= 4;
139     guest_cursor -= 4;
140     *((uint32_t*)host_cursor) = 0;
141
142     host_cursor -= 4;
143     guest_cursor -= 4;
144     for (i = 0; i < var_dump.envc; i++) {
145        *((uint32_t*)host_cursor) = tmp_envs[i];
146         host_cursor -= 4;
147         guest_cursor -= 4;
148     }
149
150     core->vm_regs.rdx = guest_cursor + 4;
151     
152     *((uint32_t*)host_cursor) = 0;
153     host_cursor -= 4;
154     guest_cursor -= 4;
155     for (i = 0; i < var_dump.argc; i++) {
156         *((uint32_t*)host_cursor) = tmp_args[i];
157         host_cursor -= 4;
158         guest_cursor -= 4;
159     }
160
161     core->vm_regs.rcx = guest_cursor + 4;
162
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]);
166     }
167     for (i = 0; i < var_dump.envc; i++) {
168         V3_Free(var_dump.envp[i]);
169     }
170     
171     V3_Free(var_dump.envp);
172     V3_Free(var_dump.argv);
173     return 0;
174 }
175
176
177 static int v3_copy_chunk_vmm32(struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
178
179     addr_t envp, argv;
180     uint_t argc = 0, envc = 0, bytes = 0;
181     char * cursor;
182
183     PrintDebug(core->vm_info, core, "Initiating copy into vmm\n");
184
185     int ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rdx, &(core->segments.ds)), &envp);
186     if (ret == -1) {
187         PrintDebug(core->vm_info, core, "Error translating address in rdx\n");
188         return 0;
189     }
190
191     ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rcx, &(core->segments.ds)), &argv);
192     if (ret == -1) {
193         PrintDebug(core->vm_info, core, "Error translating address in rcx\n");
194         return 0;
195     }
196     
197     cursor = (char*)argv;
198     while (*((uint32_t*)cursor) != 0) {
199         addr_t argvn;
200         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &argvn);
201         if (ret == -1) {
202             PrintDebug(core->vm_info, core, "Error translating address for argvn\n");
203         }
204         argc++;
205         cursor += 4;
206     } 
207
208     /* account for new args */
209     argc += argcnt;
210     var_dump.argv = (char**)V3_Malloc(sizeof(char*)*argc);
211
212     if (!var_dump.argv) {
213         PrintError(core->vm_info, core, "Cannot allocate in copying\n");
214         return -1;
215     }
216
217     var_dump.argc = argc;
218     bytes += sizeof(uint32_t)*argc;
219
220     cursor = (char*)argv;
221     int i = 0;
222     while (*((uint32_t*)cursor) != 0) {
223         addr_t argvn;
224         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &argvn);
225         if (ret == -1) {
226             PrintDebug(core->vm_info, core, "Error translating argvn address\n");
227         }
228     
229         /* malloc room for the string */
230         char * tmpstr = (char*)V3_Malloc(strlen((char*)argvn) + 1);
231
232         if (!tmpstr) {
233             PrintError(core->vm_info, core, "Cannot allocate temporary\n");
234             return -1;
235         }
236
237         /* copy the pointer */
238         var_dump.argv[i] = tmpstr; 
239
240         /* copy the string */
241         strncpy(tmpstr, (char*)argvn, strlen((char*)argvn) + 1);
242         i++;
243         cursor += 4;
244         bytes += strlen((char*)argvn) + 1;
245     }
246
247     /* stick in new arg strings */
248     int j = 0;
249     while (j < argcnt) {
250         char * tmpstr = (char*)V3_Malloc(strlen(argstrs[j]) + 1);
251
252         if (!tmpstr) {
253             PrintError(core->vm_info, core, "Cannot allocate temp string\n");
254             return -1;
255         }
256
257         strncpy(tmpstr, argstrs[i], strlen(argstrs[j]) + 1);
258         var_dump.argv[i] = tmpstr;
259         bytes += strlen(argstrs[j]) + 1;
260         i++; j++;
261     }
262         
263     
264     cursor = (char*)envp;
265     while (*((uint32_t*)cursor) != 0) {
266         addr_t envpn;
267         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &envpn);
268         if (ret == -1) {
269             PrintDebug(core->vm_info, core, "Error translating address for envpn\n");
270         }
271         envc++;
272         cursor += 4;
273     } 
274
275     envc += envcnt;
276     var_dump.envp = (char**)V3_Malloc(sizeof(char*)*envc);
277
278     if (!var_dump.envp) {
279         PrintError(core->vm_info, core, "Cannot allocate var dump\n");
280         return -1;
281     }
282
283     var_dump.envc = envc;
284     bytes += sizeof(uint32_t)*envc;
285
286     cursor = (char*)envp;
287     i = 0;
288     while (*((uint32_t*)cursor) != 0) {
289         addr_t envpn;
290         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &envpn);
291         if (ret == -1) {
292             PrintDebug(core->vm_info, core, "Error translating address for envpn\n");
293         }
294         
295         /* malloc room for the string */
296         char * tmpstr = (char*)V3_Malloc(strlen((char*)envpn) + 1);
297
298         if (!tmpstr) {
299             PrintError(core->vm_info, core, "Cannot allocate temp string\n");
300             return -1;
301         }
302         
303         /* copy the pointer */
304         var_dump.envp[i] = tmpstr;
305
306         /* deepcopy the string */
307         strncpy(tmpstr, (char*)envpn, strlen((char*)envpn) + 1);
308         i++;    
309         cursor += 4;
310         bytes += strlen((char*)envpn) + 1; 
311     }
312
313     /* put in our new env strings */
314     j = 0;
315     while (j < envcnt) {
316         char * tmpstr = (char*)V3_Malloc(strlen(envstrs[j]) + 1);
317
318         if (!tmpstr) {
319             PrintError(core->vm_info, core, "Cannot allocate temp string\n");
320             return -1;
321         }
322
323         strncpy(tmpstr, envstrs[j], strlen(envstrs[j]) + 1);
324         var_dump.envp[i] = tmpstr;
325         bytes += strlen(envstrs[j]) + 1;
326         i++; j++;
327     }
328
329
330     /* account for padding for strings
331        and 2 null pointers */
332     bytes += (bytes % 4) + 8;
333     var_dump.bytes = bytes;
334     return bytes;
335 }
336
337
338 static int v3_inject_strings32 (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
339
340     addr_t inject_gva;
341     uint_t bytes_needed = 0;
342
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(core->vm_info, core, "Error copying out environment and arguments\n");
346         return -1;
347     }
348
349     PrintDebug(core->vm_info, core, "environment successfully copied into VMM\n");
350     
351     inject_gva = v3_prepare_guest_stack(core, bytes_needed);
352     if (!inject_gva) {
353         PrintDebug(core->vm_info, core, "Not enough space on user stack\n");
354         return -1;
355     }
356
357     v3_copy_chunk_guest32(core, inject_gva, argcnt, envcnt);
358
359     return 0;
360 }
361
362
363 static int v3_copy_chunk_guest64(struct guest_info * core, addr_t gva, uint_t argcnt, uint_t envcnt) {
364
365     int ret = 0, i = 0;
366     addr_t hva;
367     uint64_t tmp_args[var_dump.argc];
368     uint64_t tmp_envs[var_dump.envc];
369
370     PrintDebug(core->vm_info, core, "Initiating copy into guest (64bit)\n");
371     
372     ret = v3_gva_to_hva(core, get_addr_linear(core, gva, &(core->segments.ds)), &hva);
373     if (ret == -1) {
374         PrintDebug(core->vm_info, core, "Error translating gva in v3_copy_chunk_2guest64\n");
375         return -1;
376     }
377     
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(core->vm_info, core, "Copying envvar#%d: %s\n", i, var_dump.envp[i]);
384         strcpy(host_cursor, var_dump.envp[i]);
385         tmp_envs[i] = guest_cursor;
386         i++;
387         if (i != var_dump.envc) { 
388             host_cursor -= strlen(var_dump.envp[i]) + 1;
389             guest_cursor -= strlen(var_dump.envp[i]) + 1;
390         }
391     }
392         
393     i = 0;
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(core->vm_info, core, "Copying arg #%d: %s\n", i, var_dump.argv[i]);
398         strcpy(host_cursor, var_dump.argv[i]);
399         tmp_args[i] = guest_cursor;
400         i++;
401         if (i != var_dump.argc) {
402             host_cursor -= strlen(var_dump.argv[i]) + 1;
403             guest_cursor -= strlen(var_dump.argv[i]) + 1;
404         }
405     }
406
407     // padding
408     host_cursor--;  
409     guest_cursor--;
410     while ((long)host_cursor % 8) {
411         *host_cursor = 0;
412         host_cursor--;
413         guest_cursor--;
414     }
415
416     // one null ptr
417     host_cursor -= 8;
418     guest_cursor -= 8;
419     *((uint64_t*)host_cursor) = 0;
420
421     host_cursor -= 8;
422     guest_cursor -= 8;
423     for (i = 0; i < var_dump.envc; i++) {
424        *((uint64_t*)host_cursor) = tmp_envs[i];
425         host_cursor -= 8;
426         guest_cursor -= 8;
427     }
428
429     core->vm_regs.rdx = guest_cursor + 8;
430
431     *((uint64_t*)host_cursor) = 0;
432     host_cursor -= 8;
433     guest_cursor -= 8;
434     for (i = 0; i < var_dump.argc; i++) {
435         *((uint64_t*)host_cursor) = tmp_args[i];
436         host_cursor -= 8;
437         guest_cursor -= 8;
438     }
439
440     core->vm_regs.rcx = guest_cursor + 8;
441
442     for (i = 0; i < var_dump.argc; i++) {
443         V3_Free(var_dump.argv[i]);
444     }
445     for (i = 0; i < var_dump.envc; i++) {
446         V3_Free(var_dump.envp[i]);
447     }
448     
449     V3_Free(var_dump.envp);
450     V3_Free(var_dump.argv);
451     return 0;
452 }
453
454
455 static int v3_copy_chunk_vmm64(struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
456
457     addr_t envp, argv;
458     uint_t argc = 0, envc = 0, bytes = 0;
459     char * cursor;
460
461     PrintDebug(core->vm_info, core, "Initiating copy into vmm\n");
462
463     int ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rdx, &(core->segments.ds)), &envp);
464     if (ret == -1) {
465         PrintDebug(core->vm_info, core, "Error translating address in rdx\n");
466         return 0;
467     }
468
469     ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rcx, &(core->segments.ds)), &argv);
470     if (ret == -1) {
471         PrintDebug(core->vm_info, core, "Error translating address in rcx\n");
472         return 0;
473     }
474     
475     cursor = (char*)argv;
476     while (*((uint64_t*)cursor) != 0) {
477         addr_t argvn;
478         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &argvn);
479         if (ret == -1) {
480             PrintDebug(core->vm_info, core, "Error translating address for argvn\n");
481         }
482         argc++;
483         cursor += 8;
484     } 
485     
486     /* account for new strings */
487     argc += argcnt;
488     var_dump.argv = (char**)V3_Malloc(sizeof(char*)*argc);
489
490     if (!var_dump.argv) {
491         PrintError(core->vm_info, core, "Cannot allocate var dump\n");
492         return -1;
493     }
494
495     var_dump.argc = argc;
496     bytes += sizeof(char*)*argc;
497
498     cursor = (char*)argv;
499     int i = 0;
500     while (*((uint64_t*)cursor) != 0) {
501         addr_t argvn;
502         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &argvn);
503         if (ret == -1) {
504             PrintDebug(core->vm_info, core, "Error translating argvn address\n");
505         }
506     
507         /* malloc room for the string */
508         char * tmpstr = (char*)V3_Malloc(strlen((char*)argvn) + 1);
509
510         if (!tmpstr) {
511             PrintError(core->vm_info, core, "Cannot allocate temp string\n");
512             return -1;
513         }
514
515         /* copy the pointer */
516         var_dump.argv[i] = tmpstr; 
517
518         /* copy the string */
519         strncpy(tmpstr, (char*)argvn, strlen((char*)argvn) + 1);
520         i++;
521         cursor += 8;
522         bytes += strlen((char*)argvn) + 1;
523     }
524         
525     /* stick in new arg strings */
526     int j = 0;
527     while (j < argcnt) {
528         char * tmpstr = (char*)V3_Malloc(strlen(argstrs[j]) + 1);
529
530         if (!tmpstr) {
531             PrintError(core->vm_info, core, "Cannot allocate temp string\n");
532             return -1;
533         }
534
535         strncpy(tmpstr, argstrs[j], strlen(argstrs[j]) + 1);
536         var_dump.argv[i] = tmpstr;
537         bytes += strlen(argstrs[j]) + 1;
538         i++; j++;
539     }
540
541
542     cursor = (char*)envp;
543     while (*((uint64_t*)cursor) != 0) {
544         addr_t envpn;
545         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &envpn);
546         if (ret == -1) {
547             PrintDebug(core->vm_info, core, "Error translating address for envpn\n");
548         }
549         envc++;
550         cursor += 8;
551     } 
552
553     envc += envcnt;
554     var_dump.envp = (char**)V3_Malloc(sizeof(char*)*envc);
555
556     if (!var_dump.envp) {
557         PrintError(core->vm_info, core, "Cannot allocate var dump\n");
558         return -1;
559     }
560
561     var_dump.envc = envc;
562     bytes += sizeof(uint64_t)*(envc);
563
564
565     cursor = (char*)envp;
566     i = 0;
567     while (*((uint64_t*)cursor) != 0) {
568         addr_t envpn;
569         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &envpn);
570         if (ret == -1) {
571             PrintDebug(core->vm_info, core, "Error translating address for envpn\n");
572         }
573         
574         /* malloc room for the string */
575         char * tmpstr = (char*)V3_Malloc(strlen((char*)envpn) + 1);
576
577         if (!tmpstr) {
578             PrintError(core->vm_info, core, "Cannot allocate temp string\n");
579             return -1;
580         }
581         
582         /* copy the pointer */
583         var_dump.envp[i] = tmpstr;
584
585         /* deepcopy the string */
586         strncpy(tmpstr, (char*)envpn, strlen((char*)envpn) + 1);
587         i++;    
588         cursor += 8;
589         bytes += strlen((char*)envpn) + 1; 
590     }
591
592     /* stick in new env strings */
593     j = 0;
594     while (j < envcnt) {
595         char * tmpstr = (char*)V3_Malloc(strlen(envstrs[j]) + 1);
596
597         if (!tmpstr) {
598             PrintError(core->vm_info, core, "Cannot allocate temp string\n");
599             return -1;
600         }
601
602         strncpy(tmpstr, envstrs[i], strlen(envstrs[j]) + 1);
603         var_dump.envp[i] = tmpstr;
604         bytes += strlen(envstrs[j]) + 1;
605         i++; j++;
606     } 
607
608
609     /* account for padding for strings
610        and 2 null pointers */
611     bytes += (bytes % 8) + 16;
612     var_dump.bytes = bytes;
613     return bytes;
614 }
615
616
617 static int v3_inject_strings64 (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
618
619     addr_t inject_gva;
620     uint_t bytes_needed = 0;
621
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(core->vm_info, core, "Error copying out environment and arguments\n");
625         return -1;
626     }
627
628     PrintDebug(core->vm_info, core, "environment successfully copied into VMM\n");
629     
630     inject_gva = v3_prepare_guest_stack(core, bytes_needed);
631     if (!inject_gva) {
632         PrintDebug(core->vm_info, core, "Not enough space on user stack\n");
633         return -1;
634     }
635
636     v3_copy_chunk_guest64(core, inject_gva, argcnt, envcnt);
637     return 0;
638 }
639
640
641 addr_t v3_prepare_guest_stack (struct guest_info * core, uint_t bytes_needed) {
642
643     /* TODO: check if we've injected a page fault to get more stack space */
644
645     // do we have enough room between esp and the next page boundary?
646     uint_t rem_bytes = 4096 - (core->vm_regs.rsp % 4096);
647
648     if (rem_bytes >= bytes_needed) {
649         return (addr_t)core->vm_regs.rsp;
650     } else {
651         // not enough room, find out how many pages we need (ceiling)
652         uint_t num_pages = (bytes_needed + 4095) / 4096;
653         
654         // check if num_pages are user & writable
655         int i = 0;
656         int pages_ok = 1;
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)) {
660                 pages_ok = 0;
661             }
662         }
663
664         if (pages_ok) {
665             return (addr_t)core->vm_regs.rsp;
666         } else {
667     
668             /*
669             // inject a page fault
670             pf_error_t fault_type = {
671                 .write = 1,
672                 .user = 1
673             };
674
675             // hoping Linux will allocate all pages in between gva and esp 
676             v3_inject_guest_pf(core, gva - (num_pages*4096), fault_type);
677             */
678             return -1;
679         }
680     }
681 }
682
683
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) { 
686
687     return 0;
688 }
689
690
691 int v3_replace_env (struct guest_info * core, const char * envname, const char * newval) {
692
693     return 0;
694 }
695
696
697 int v3_inject_strings (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
698     
699     if (core->cpu_mode == LONG) {
700         if (v3_inject_strings64(core, argstrs, envstrs, argcnt, envcnt) == -1) {
701             PrintDebug(core->vm_info, core, "Error injecting strings into environment (64)\n");
702             return -1;
703         }
704     } else {
705         if (v3_inject_strings32(core, argstrs, envstrs, argcnt, envcnt) == -1) {
706             PrintDebug(core->vm_info, core, "Error injecting strings into environment (32)\n");
707             return -1;
708         }
709     }
710
711     return 0;
712 }