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.


Cleanup and sanity-checking of use of strncpy/strcpy (Coverity static analysis)
[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         // this is guaranteed to alwys null terminate tmpstr
242         strncpy(tmpstr, (char*)argvn, strlen((char*)argvn) + 1);
243
244         i++;
245         cursor += 4;
246         bytes += strlen((char*)argvn) + 1;
247     }
248
249     /* stick in new arg strings */
250     int j = 0;
251     while (j < argcnt) {
252         char * tmpstr = (char*)V3_Malloc(strlen(argstrs[j]) + 1);
253
254         if (!tmpstr) {
255             PrintError(core->vm_info, core, "Cannot allocate temp string\n");
256             return -1;
257         }
258
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;
263         i++; j++;
264     }
265         
266     
267     cursor = (char*)envp;
268     while (*((uint32_t*)cursor) != 0) {
269         addr_t envpn;
270         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &envpn);
271         if (ret == -1) {
272             PrintDebug(core->vm_info, core, "Error translating address for envpn\n");
273         }
274         envc++;
275         cursor += 4;
276     } 
277
278     envc += envcnt;
279     var_dump.envp = (char**)V3_Malloc(sizeof(char*)*envc);
280
281     if (!var_dump.envp) {
282         PrintError(core->vm_info, core, "Cannot allocate var dump\n");
283         return -1;
284     }
285
286     var_dump.envc = envc;
287     bytes += sizeof(uint32_t)*envc;
288
289     cursor = (char*)envp;
290     i = 0;
291     while (*((uint32_t*)cursor) != 0) {
292         addr_t envpn;
293         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &envpn);
294         if (ret == -1) {
295             PrintDebug(core->vm_info, core, "Error translating address for envpn\n");
296         }
297         
298         /* malloc room for the string */
299         char * tmpstr = (char*)V3_Malloc(strlen((char*)envpn) + 1);
300
301         if (!tmpstr) {
302             PrintError(core->vm_info, core, "Cannot allocate temp string\n");
303             return -1;
304         }
305         
306         /* copy the pointer */
307         var_dump.envp[i] = tmpstr;
308
309         /* deepcopy the string */
310         // will always null-terminate tmpstr
311         strncpy(tmpstr, (char*)envpn, strlen((char*)envpn) + 1);
312         i++;    
313         cursor += 4;
314         bytes += strlen((char*)envpn) + 1; 
315     }
316
317     /* put in our new env strings */
318     j = 0;
319     while (j < envcnt) {
320         char * tmpstr = (char*)V3_Malloc(strlen(envstrs[j]) + 1);
321
322         if (!tmpstr) {
323             PrintError(core->vm_info, core, "Cannot allocate temp string\n");
324             return -1;
325         }
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;
330         i++; j++;
331     }
332
333
334     /* account for padding for strings
335        and 2 null pointers */
336     bytes += (bytes % 4) + 8;
337     var_dump.bytes = bytes;
338     return bytes;
339 }
340
341
342 static int v3_inject_strings32 (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
343
344     addr_t inject_gva;
345     uint_t bytes_needed = 0;
346
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");
350         return -1;
351     }
352
353     PrintDebug(core->vm_info, core, "environment successfully copied into VMM\n");
354     
355     inject_gva = v3_prepare_guest_stack(core, bytes_needed);
356     if (!inject_gva) {
357         PrintDebug(core->vm_info, core, "Not enough space on user stack\n");
358         return -1;
359     }
360
361     v3_copy_chunk_guest32(core, inject_gva, argcnt, envcnt);
362
363     return 0;
364 }
365
366
367 static int v3_copy_chunk_guest64(struct guest_info * core, addr_t gva, uint_t argcnt, uint_t envcnt) {
368
369     int ret = 0, i = 0;
370     addr_t hva;
371     uint64_t tmp_args[var_dump.argc];
372     uint64_t tmp_envs[var_dump.envc];
373
374     PrintDebug(core->vm_info, core, "Initiating copy into guest (64bit)\n");
375     
376     ret = v3_gva_to_hva(core, get_addr_linear(core, gva, &(core->segments.ds)), &hva);
377     if (ret == -1) {
378         PrintDebug(core->vm_info, core, "Error translating gva in v3_copy_chunk_2guest64\n");
379         return -1;
380     }
381     
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;
390         i++;
391         if (i != var_dump.envc) { 
392             host_cursor -= strlen(var_dump.envp[i]) + 1;
393             guest_cursor -= strlen(var_dump.envp[i]) + 1;
394         }
395     }
396         
397     i = 0;
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;
404         i++;
405         if (i != var_dump.argc) {
406             host_cursor -= strlen(var_dump.argv[i]) + 1;
407             guest_cursor -= strlen(var_dump.argv[i]) + 1;
408         }
409     }
410
411     // padding
412     host_cursor--;  
413     guest_cursor--;
414     while ((long)host_cursor % 8) {
415         *host_cursor = 0;
416         host_cursor--;
417         guest_cursor--;
418     }
419
420     // one null ptr
421     host_cursor -= 8;
422     guest_cursor -= 8;
423     *((uint64_t*)host_cursor) = 0;
424
425     host_cursor -= 8;
426     guest_cursor -= 8;
427     for (i = 0; i < var_dump.envc; i++) {
428        *((uint64_t*)host_cursor) = tmp_envs[i];
429         host_cursor -= 8;
430         guest_cursor -= 8;
431     }
432
433     core->vm_regs.rdx = guest_cursor + 8;
434
435     *((uint64_t*)host_cursor) = 0;
436     host_cursor -= 8;
437     guest_cursor -= 8;
438     for (i = 0; i < var_dump.argc; i++) {
439         *((uint64_t*)host_cursor) = tmp_args[i];
440         host_cursor -= 8;
441         guest_cursor -= 8;
442     }
443
444     core->vm_regs.rcx = guest_cursor + 8;
445
446     for (i = 0; i < var_dump.argc; i++) {
447         V3_Free(var_dump.argv[i]);
448     }
449     for (i = 0; i < var_dump.envc; i++) {
450         V3_Free(var_dump.envp[i]);
451     }
452     
453     V3_Free(var_dump.envp);
454     V3_Free(var_dump.argv);
455     return 0;
456 }
457
458
459 static int v3_copy_chunk_vmm64(struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
460
461     addr_t envp, argv;
462     uint_t argc = 0, envc = 0, bytes = 0;
463     char * cursor;
464
465     PrintDebug(core->vm_info, core, "Initiating copy into vmm\n");
466
467     int ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rdx, &(core->segments.ds)), &envp);
468     if (ret == -1) {
469         PrintDebug(core->vm_info, core, "Error translating address in rdx\n");
470         return 0;
471     }
472
473     ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rcx, &(core->segments.ds)), &argv);
474     if (ret == -1) {
475         PrintDebug(core->vm_info, core, "Error translating address in rcx\n");
476         return 0;
477     }
478     
479     cursor = (char*)argv;
480     while (*((uint64_t*)cursor) != 0) {
481         addr_t argvn;
482         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &argvn);
483         if (ret == -1) {
484             PrintDebug(core->vm_info, core, "Error translating address for argvn\n");
485         }
486         argc++;
487         cursor += 8;
488     } 
489     
490     /* account for new strings */
491     argc += argcnt;
492     var_dump.argv = (char**)V3_Malloc(sizeof(char*)*argc);
493
494     if (!var_dump.argv) {
495         PrintError(core->vm_info, core, "Cannot allocate var dump\n");
496         return -1;
497     }
498
499     var_dump.argc = argc;
500     bytes += sizeof(char*)*argc;
501
502     cursor = (char*)argv;
503     int i = 0;
504     while (*((uint64_t*)cursor) != 0) {
505         addr_t argvn;
506         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &argvn);
507         if (ret == -1) {
508             PrintDebug(core->vm_info, core, "Error translating argvn address\n");
509         }
510     
511         /* malloc room for the string */
512         char * tmpstr = (char*)V3_Malloc(strlen((char*)argvn) + 1);
513
514         if (!tmpstr) {
515             PrintError(core->vm_info, core, "Cannot allocate temp string\n");
516             return -1;
517         }
518
519         /* copy the pointer */
520         var_dump.argv[i] = tmpstr; 
521
522         /* copy the string */
523         // will always null-terminate tmpstr
524         strncpy(tmpstr, (char*)argvn, strlen((char*)argvn) + 1);
525         i++;
526         cursor += 8;
527         bytes += strlen((char*)argvn) + 1;
528     }
529         
530     /* stick in new arg strings */
531     int j = 0;
532     while (j < argcnt) {
533         char * tmpstr = (char*)V3_Malloc(strlen(argstrs[j]) + 1);
534
535         if (!tmpstr) {
536             PrintError(core->vm_info, core, "Cannot allocate temp string\n");
537             return -1;
538         }
539
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;
544         i++; j++;
545     }
546
547
548     cursor = (char*)envp;
549     while (*((uint64_t*)cursor) != 0) {
550         addr_t envpn;
551         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &envpn);
552         if (ret == -1) {
553             PrintDebug(core->vm_info, core, "Error translating address for envpn\n");
554         }
555         envc++;
556         cursor += 8;
557     } 
558
559     envc += envcnt;
560     var_dump.envp = (char**)V3_Malloc(sizeof(char*)*envc);
561
562     if (!var_dump.envp) {
563         PrintError(core->vm_info, core, "Cannot allocate var dump\n");
564         return -1;
565     }
566
567     var_dump.envc = envc;
568     bytes += sizeof(uint64_t)*(envc);
569
570
571     cursor = (char*)envp;
572     i = 0;
573     while (*((uint64_t*)cursor) != 0) {
574         addr_t envpn;
575         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &envpn);
576         if (ret == -1) {
577             PrintDebug(core->vm_info, core, "Error translating address for envpn\n");
578         }
579         
580         /* malloc room for the string */
581         char * tmpstr = (char*)V3_Malloc(strlen((char*)envpn) + 1);
582
583         if (!tmpstr) {
584             PrintError(core->vm_info, core, "Cannot allocate temp string\n");
585             return -1;
586         }
587         
588         /* copy the pointer */
589         var_dump.envp[i] = tmpstr;
590
591         /* deepcopy the string */
592         // will always null-terminate tmpstr
593         strncpy(tmpstr, (char*)envpn, strlen((char*)envpn) + 1);
594         i++;    
595         cursor += 8;
596         bytes += strlen((char*)envpn) + 1; 
597     }
598
599     /* stick in new env strings */
600     j = 0;
601     while (j < envcnt) {
602         char * tmpstr = (char*)V3_Malloc(strlen(envstrs[j]) + 1);
603
604         if (!tmpstr) {
605             PrintError(core->vm_info, core, "Cannot allocate temp string\n");
606             return -1;
607         }
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;
612         i++; j++;
613     } 
614
615
616     /* account for padding for strings
617        and 2 null pointers */
618     bytes += (bytes % 8) + 16;
619     var_dump.bytes = bytes;
620     return bytes;
621 }
622
623
624 static int v3_inject_strings64 (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
625
626     addr_t inject_gva;
627     uint_t bytes_needed = 0;
628
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");
632         return -1;
633     }
634
635     PrintDebug(core->vm_info, core, "environment successfully copied into VMM\n");
636     
637     inject_gva = v3_prepare_guest_stack(core, bytes_needed);
638     if (!inject_gva) {
639         PrintDebug(core->vm_info, core, "Not enough space on user stack\n");
640         return -1;
641     }
642
643     v3_copy_chunk_guest64(core, inject_gva, argcnt, envcnt);
644     return 0;
645 }
646
647
648 addr_t v3_prepare_guest_stack (struct guest_info * core, uint_t bytes_needed) {
649
650     /* TODO: check if we've injected a page fault to get more stack space */
651
652     // do we have enough room between esp and the next page boundary?
653     uint_t rem_bytes = 4096 - (core->vm_regs.rsp % 4096);
654
655     if (rem_bytes >= bytes_needed) {
656         return (addr_t)core->vm_regs.rsp;
657     } else {
658         // not enough room, find out how many pages we need (ceiling)
659         uint_t num_pages = (bytes_needed + 4095) / 4096;
660         
661         // check if num_pages are user & writable
662         int i = 0;
663         int pages_ok = 1;
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)) {
667                 pages_ok = 0;
668             }
669         }
670
671         if (pages_ok) {
672             return (addr_t)core->vm_regs.rsp;
673         } else {
674     
675             /*
676             // inject a page fault
677             pf_error_t fault_type = {
678                 .write = 1,
679                 .user = 1
680             };
681
682             // hoping Linux will allocate all pages in between gva and esp 
683             v3_inject_guest_pf(core, gva - (num_pages*4096), fault_type);
684             */
685             return -1;
686         }
687     }
688 }
689
690
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) { 
693
694     return 0;
695 }
696
697
698 int v3_replace_env (struct guest_info * core, const char * envname, const char * newval) {
699
700     return 0;
701 }
702
703
704 int v3_inject_strings (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
705     
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");
709             return -1;
710         }
711     } else {
712         if (v3_inject_strings32(core, argstrs, envstrs, argcnt, envcnt) == -1) {
713             PrintDebug(core->vm_info, core, "Error injecting strings into environment (32)\n");
714             return -1;
715         }
716     }
717
718     return 0;
719 }