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.


New Gears Tools And Structure
[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("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("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("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("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("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("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("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("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     var_dump.argc = argc;
212     bytes += sizeof(uint32_t)*argc;
213
214     cursor = (char*)argv;
215     int i = 0;
216     while (*((uint32_t*)cursor) != 0) {
217         addr_t argvn;
218         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &argvn);
219         if (ret == -1) {
220             PrintDebug("Error translating argvn address\n");
221         }
222     
223         /* malloc room for the string */
224         char * tmpstr = (char*)V3_Malloc(strlen((char*)argvn) + 1);
225
226         /* copy the pointer */
227         var_dump.argv[i] = tmpstr; 
228
229         /* copy the string */
230         strncpy(tmpstr, (char*)argvn, strlen((char*)argvn) + 1);
231         i++;
232         cursor += 4;
233         bytes += strlen((char*)argvn) + 1;
234     }
235
236     /* stick in new arg strings */
237     int j = 0;
238     while (j < argcnt) {
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;
243         i++; j++;
244     }
245         
246     
247     cursor = (char*)envp;
248     while (*((uint32_t*)cursor) != 0) {
249         addr_t envpn;
250         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &envpn);
251         if (ret == -1) {
252             PrintDebug("Error translating address for envpn\n");
253         }
254         envc++;
255         cursor += 4;
256     } 
257
258     envc += envcnt;
259     var_dump.envp = (char**)V3_Malloc(sizeof(char*)*envc);
260     var_dump.envc = envc;
261     bytes += sizeof(uint32_t)*envc;
262
263     cursor = (char*)envp;
264     i = 0;
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("Error translating address for envpn\n");
270         }
271         
272         /* malloc room for the string */
273         char * tmpstr = (char*)V3_Malloc(strlen((char*)envpn) + 1);
274         
275         /* copy the pointer */
276         var_dump.envp[i] = tmpstr;
277
278         /* deepcopy the string */
279         strncpy(tmpstr, (char*)envpn, strlen((char*)envpn) + 1);
280         i++;    
281         cursor += 4;
282         bytes += strlen((char*)envpn) + 1; 
283     }
284
285     /* put in our new env strings */
286     j = 0;
287     while (j < envcnt) {
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;
292         i++; j++;
293     }
294
295
296     /* account for padding for strings
297        and 2 null pointers */
298     bytes += (bytes % 4) + 8;
299     var_dump.bytes = bytes;
300     return bytes;
301 }
302
303
304 static int v3_inject_strings32 (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
305
306     addr_t inject_gva;
307     uint_t bytes_needed = 0;
308
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");
312         return -1;
313     }
314
315     PrintDebug("environment successfully copied into VMM\n");
316     
317     inject_gva = v3_prepare_guest_stack(core, bytes_needed);
318     if (!inject_gva) {
319         PrintDebug("Not enough space on user stack\n");
320         return -1;
321     }
322
323     v3_copy_chunk_guest32(core, inject_gva, argcnt, envcnt);
324
325     return 0;
326 }
327
328
329 static int v3_copy_chunk_guest64(struct guest_info * core, addr_t gva, uint_t argcnt, uint_t envcnt) {
330
331     int ret = 0, i = 0;
332     addr_t hva;
333     uint64_t tmp_args[var_dump.argc];
334     uint64_t tmp_envs[var_dump.envc];
335
336     PrintDebug("Initiating copy into guest (64bit)\n");
337     
338     ret = v3_gva_to_hva(core, get_addr_linear(core, gva, &(core->segments.ds)), &hva);
339     if (ret == -1) {
340         PrintDebug("Error translating gva in v3_copy_chunk_2guest64\n");
341         return -1;
342     }
343     
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;
352         i++;
353         if (i != var_dump.envc) { 
354             host_cursor -= strlen(var_dump.envp[i]) + 1;
355             guest_cursor -= strlen(var_dump.envp[i]) + 1;
356         }
357     }
358         
359     i = 0;
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;
366         i++;
367         if (i != var_dump.argc) {
368             host_cursor -= strlen(var_dump.argv[i]) + 1;
369             guest_cursor -= strlen(var_dump.argv[i]) + 1;
370         }
371     }
372
373     // padding
374     host_cursor--;  
375     guest_cursor--;
376     while ((long)host_cursor % 8) {
377         *host_cursor = 0;
378         host_cursor--;
379         guest_cursor--;
380     }
381
382     // one null ptr
383     host_cursor -= 8;
384     guest_cursor -= 8;
385     *((uint64_t*)host_cursor) = 0;
386
387     host_cursor -= 8;
388     guest_cursor -= 8;
389     for (i = 0; i < var_dump.envc; i++) {
390        *((uint64_t*)host_cursor) = tmp_envs[i];
391         host_cursor -= 8;
392         guest_cursor -= 8;
393     }
394
395     core->vm_regs.rdx = guest_cursor + 8;
396
397     *((uint64_t*)host_cursor) = 0;
398     host_cursor -= 8;
399     guest_cursor -= 8;
400     for (i = 0; i < var_dump.argc; i++) {
401         *((uint64_t*)host_cursor) = tmp_args[i];
402         host_cursor -= 8;
403         guest_cursor -= 8;
404     }
405
406     core->vm_regs.rcx = guest_cursor + 8;
407
408     for (i = 0; i < var_dump.argc; i++) {
409         V3_Free(var_dump.argv[i]);
410     }
411     for (i = 0; i < var_dump.envc; i++) {
412         V3_Free(var_dump.envp[i]);
413     }
414     
415     V3_Free(var_dump.envp);
416     V3_Free(var_dump.argv);
417     return 0;
418 }
419
420
421 static int v3_copy_chunk_vmm64(struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
422
423     addr_t envp, argv;
424     uint_t argc = 0, envc = 0, bytes = 0;
425     char * cursor;
426
427     PrintDebug("Initiating copy into vmm\n");
428
429     int ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rdx, &(core->segments.ds)), &envp);
430     if (ret == -1) {
431         PrintDebug("Error translating address in rdx\n");
432         return 0;
433     }
434
435     ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rcx, &(core->segments.ds)), &argv);
436     if (ret == -1) {
437         PrintDebug("Error translating address in rcx\n");
438         return 0;
439     }
440     
441     cursor = (char*)argv;
442     while (*((uint64_t*)cursor) != 0) {
443         addr_t argvn;
444         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &argvn);
445         if (ret == -1) {
446             PrintDebug("Error translating address for argvn\n");
447         }
448         argc++;
449         cursor += 8;
450     } 
451     
452     /* account for new strings */
453     argc += argcnt;
454     var_dump.argv = (char**)V3_Malloc(sizeof(char*)*argc);
455     var_dump.argc = argc;
456     bytes += sizeof(char*)*argc;
457
458     cursor = (char*)argv;
459     int i = 0;
460     while (*((uint64_t*)cursor) != 0) {
461         addr_t argvn;
462         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &argvn);
463         if (ret == -1) {
464             PrintDebug("Error translating argvn address\n");
465         }
466     
467         /* malloc room for the string */
468         char * tmpstr = (char*)V3_Malloc(strlen((char*)argvn) + 1);
469
470         /* copy the pointer */
471         var_dump.argv[i] = tmpstr; 
472
473         /* copy the string */
474         strncpy(tmpstr, (char*)argvn, strlen((char*)argvn) + 1);
475         i++;
476         cursor += 8;
477         bytes += strlen((char*)argvn) + 1;
478     }
479         
480     /* stick in new arg strings */
481     int j = 0;
482     while (j < argcnt) {
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;
487         i++; j++;
488     }
489
490
491     cursor = (char*)envp;
492     while (*((uint64_t*)cursor) != 0) {
493         addr_t envpn;
494         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &envpn);
495         if (ret == -1) {
496             PrintDebug("Error translating address for envpn\n");
497         }
498         envc++;
499         cursor += 8;
500     } 
501
502     envc += envcnt;
503     var_dump.envp = (char**)V3_Malloc(sizeof(char*)*envc);
504     var_dump.envc = envc;
505     bytes += sizeof(uint64_t)*(envc);
506
507
508     cursor = (char*)envp;
509     i = 0;
510     while (*((uint64_t*)cursor) != 0) {
511         addr_t envpn;
512         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &envpn);
513         if (ret == -1) {
514             PrintDebug("Error translating address for envpn\n");
515         }
516         
517         /* malloc room for the string */
518         char * tmpstr = (char*)V3_Malloc(strlen((char*)envpn) + 1);
519         
520         /* copy the pointer */
521         var_dump.envp[i] = tmpstr;
522
523         /* deepcopy the string */
524         strncpy(tmpstr, (char*)envpn, strlen((char*)envpn) + 1);
525         i++;    
526         cursor += 8;
527         bytes += strlen((char*)envpn) + 1; 
528     }
529
530     /* stick in new env strings */
531     j = 0;
532     while (j < envcnt) {
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;
537         i++; j++;
538     } 
539
540
541     /* account for padding for strings
542        and 2 null pointers */
543     bytes += (bytes % 8) + 16;
544     var_dump.bytes = bytes;
545     return bytes;
546 }
547
548
549 static int v3_inject_strings64 (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
550
551     addr_t inject_gva;
552     uint_t bytes_needed = 0;
553
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");
557         return -1;
558     }
559
560     PrintDebug("environment successfully copied into VMM\n");
561     
562     inject_gva = v3_prepare_guest_stack(core, bytes_needed);
563     if (!inject_gva) {
564         PrintDebug("Not enough space on user stack\n");
565         return -1;
566     }
567
568     v3_copy_chunk_guest64(core, inject_gva, argcnt, envcnt);
569     return 0;
570 }
571
572
573 addr_t v3_prepare_guest_stack (struct guest_info * core, uint_t bytes_needed) {
574
575     /* TODO: check if we've injected a page fault to get more stack space */
576
577     // do we have enough room between esp and the next page boundary?
578     uint_t rem_bytes = 4096 - (core->vm_regs.rsp % 4096);
579
580     if (rem_bytes >= bytes_needed) {
581         return (addr_t)core->vm_regs.rsp;
582     } else {
583         // not enough room, find out how many pages we need (ceiling)
584         uint_t num_pages = (bytes_needed + 4095) / 4096;
585         
586         // check if num_pages are user & writable
587         int i = 0;
588         int pages_ok = 1;
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)) {
592                 pages_ok = 0;
593             }
594         }
595
596         if (pages_ok) {
597             return (addr_t)core->vm_regs.rsp;
598         } else {
599     
600             /*
601             // inject a page fault
602             pf_error_t fault_type = {
603                 .write = 1,
604                 .user = 1
605             };
606
607             // hoping Linux will allocate all pages in between gva and esp 
608             v3_inject_guest_pf(core, gva - (num_pages*4096), fault_type);
609             */
610             return -1;
611         }
612     }
613 }
614
615
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) { 
618
619     return 0;
620 }
621
622
623 int v3_replace_env (struct guest_info * core, const char * envname, const char * newval) {
624
625     return 0;
626 }
627
628
629 int v3_inject_strings (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
630     
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");
634             return -1;
635         }
636     } else {
637         if (v3_inject_strings32(core, argstrs, envstrs, argcnt, envcnt) == -1) {
638             PrintDebug("Error injecting strings into environment (32)\n");
639             return -1;
640         }
641     }
642
643     return 0;
644 }