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.


15f04a0702fb4c2ee4ec57c9e097765f2720463d
[palacios.git] / palacios / src / extensions / vmm_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/vmm_process_environment.h>
23 #include <palacios/vm_guest.h>
24 #include <palacios/vm_guest_mem.h>
25
26 static int v3_copy_chunk_guest32(struct guest_info * core, addr_t gva, uint_t argcnt, uint_t envcnt) {
27
28     int ret = 0, i = 0;
29     addr_t hva;
30     uint32_t tmp_args[core->var_dump.argc];
31     uint32_t tmp_envs[core->var_dump.envc];
32
33     PrintDebug("Initiating copy into guest (32bit)\n");
34     
35     ret = v3_gva_to_hva(core, get_addr_linear(core, gva, &(core->segments.ds)), &hva);
36     if (ret == -1) {
37         PrintDebug("Error translating gva in v3_copy_chunk_2guest\n");
38         return -1;
39     }
40     
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;
50         i++;
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;
54         }
55     }
56         
57     // then the arg strings
58     i = 0;
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;
65         i++;
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;
69         }
70     }
71
72     
73     // padding
74     host_cursor--;  
75     guest_cursor--;
76     while ((long)host_cursor % 4) {
77         *host_cursor = 0;
78         host_cursor--;
79         guest_cursor--;
80     }
81
82     // null ptr
83     host_cursor -= 4;
84     guest_cursor -= 4;
85     *((uint32_t*)host_cursor) = 0;
86
87     host_cursor -= 4;
88     guest_cursor -= 4;
89     for (i = 0; i < core->var_dump.envc; i++) {
90        *((uint32_t*)host_cursor) = tmp_envs[i];
91         host_cursor -= 4;
92         guest_cursor -= 4;
93     }
94
95     core->vm_regs.rdx = guest_cursor + 4;
96     
97     *((uint32_t*)host_cursor) = 0;
98     host_cursor -= 4;
99     guest_cursor -= 4;
100     for (i = 0; i < core->var_dump.argc; i++) {
101         *((uint32_t*)host_cursor) = tmp_args[i];
102         host_cursor -= 4;
103         guest_cursor -= 4;
104     }
105
106     core->vm_regs.rcx = guest_cursor + 4;
107
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]);
111     }
112     for (i = 0; i < core->var_dump.envc; i++) {
113         V3_Free(core->var_dump.envp[i]);
114     }
115     
116     V3_Free(core->var_dump.envp);
117     V3_Free(core->var_dump.argv);
118     return 0;
119 }
120
121
122 static int v3_copy_chunk_vmm32(struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
123
124     addr_t envp, argv;
125     uint_t argc = 0, envc = 0, bytes = 0;
126     char * cursor;
127
128     PrintDebug("Initiating copy into vmm\n");
129
130     int ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rdx, &(core->segments.ds)), &envp);
131     if (ret == -1) {
132         PrintDebug("Error translating address in rdx\n");
133         return 0;
134     }
135
136     ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rcx, &(core->segments.ds)), &argv);
137     if (ret == -1) {
138         PrintDebug("Error translating address in rcx\n");
139         return 0;
140     }
141     
142     cursor = (char*)argv;
143     while (*((uint32_t*)cursor) != 0) {
144         addr_t argvn;
145         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &argvn);
146         if (ret == -1) {
147             PrintDebug("Error translating address for argvn\n");
148         }
149         argc++;
150         cursor += 4;
151     } 
152
153     /* account for new args */
154     argc += argcnt;
155     core->var_dump.argv = (char**)V3_Malloc(sizeof(char*)*argc);
156     core->var_dump.argc = argc;
157     bytes += sizeof(uint32_t)*argc;
158
159     cursor = (char*)argv;
160     int i = 0;
161     while (*((uint32_t*)cursor) != 0) {
162         addr_t argvn;
163         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &argvn);
164         if (ret == -1) {
165             PrintDebug("Error translating argvn address\n");
166         }
167     
168         /* malloc room for the string */
169         char * tmpstr = (char*)V3_Malloc(strlen((char*)argvn) + 1);
170
171         /* copy the pointer */
172         core->var_dump.argv[i] = tmpstr; 
173
174         /* copy the string */
175         strncpy(tmpstr, (char*)argvn, strlen((char*)argvn) + 1);
176         i++;
177         cursor += 4;
178         bytes += strlen((char*)argvn) + 1;
179     }
180
181     /* stick in new arg strings */
182     int j = 0;
183     while (j < argcnt) {
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;
188         i++; j++;
189     }
190         
191     
192     cursor = (char*)envp;
193     while (*((uint32_t*)cursor) != 0) {
194         addr_t envpn;
195         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &envpn);
196         if (ret == -1) {
197             PrintDebug("Error translating address for envpn\n");
198         }
199         envc++;
200         cursor += 4;
201     } 
202
203     envc += envcnt;
204     core->var_dump.envp = (char**)V3_Malloc(sizeof(char*)*envc);
205     core->var_dump.envc = envc;
206     bytes += sizeof(uint32_t)*envc;
207
208     cursor = (char*)envp;
209     i = 0;
210     while (*((uint32_t*)cursor) != 0) {
211         addr_t envpn;
212         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint32_t*)cursor), &(core->segments.ds)), &envpn);
213         if (ret == -1) {
214             PrintDebug("Error translating address for envpn\n");
215         }
216         
217         /* malloc room for the string */
218         char * tmpstr = (char*)V3_Malloc(strlen((char*)envpn) + 1);
219         
220         /* copy the pointer */
221         core->var_dump.envp[i] = tmpstr;
222
223         /* deepcopy the string */
224         strncpy(tmpstr, (char*)envpn, strlen((char*)envpn) + 1);
225         i++;    
226         cursor += 4;
227         bytes += strlen((char*)envpn) + 1; 
228     }
229
230     /* put in our new env strings */
231     j = 0;
232     while (j < envcnt) {
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;
237         i++; j++;
238     }
239
240
241     /* account for padding for strings
242        and 2 null pointers */
243     bytes += (bytes % 4) + 8;
244     core->var_dump.bytes = bytes;
245     return bytes;
246 }
247
248
249 static int v3_inject_strings32 (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
250
251     addr_t inject_gva;
252     uint_t bytes_needed = 0;
253
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");
257         return -1;
258     }
259
260     PrintDebug("environment successfully copied into VMM\n");
261     
262     inject_gva = v3_prepare_guest_stack(core, bytes_needed);
263     if (!inject_gva) {
264         PrintDebug("Not enough space on user stack\n");
265         return -1;
266     }
267
268     v3_copy_chunk_guest32(core, inject_gva, argcnt, envcnt);
269
270     return 0;
271 }
272
273
274 static int v3_copy_chunk_guest64(struct guest_info * core, addr_t gva, uint_t argcnt, uint_t envcnt) {
275
276     int ret = 0, i = 0;
277     addr_t hva;
278     uint64_t tmp_args[core->var_dump.argc];
279     uint64_t tmp_envs[core->var_dump.envc];
280
281     PrintDebug("Initiating copy into guest (64bit)\n");
282     
283     ret = v3_gva_to_hva(core, get_addr_linear(core, gva, &(core->segments.ds)), &hva);
284     if (ret == -1) {
285         PrintDebug("Error translating gva in v3_copy_chunk_2guest64\n");
286         return -1;
287     }
288     
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;
297         i++;
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;
301         }
302     }
303         
304     i = 0;
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;
311         i++;
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;
315         }
316     }
317
318     // padding
319     host_cursor--;  
320     guest_cursor--;
321     while ((long)host_cursor % 8) {
322         *host_cursor = 0;
323         host_cursor--;
324         guest_cursor--;
325     }
326
327     // one null ptr
328     host_cursor -= 8;
329     guest_cursor -= 8;
330     *((uint64_t*)host_cursor) = 0;
331
332     host_cursor -= 8;
333     guest_cursor -= 8;
334     for (i = 0; i < core->var_dump.envc; i++) {
335        *((uint64_t*)host_cursor) = tmp_envs[i];
336         host_cursor -= 8;
337         guest_cursor -= 8;
338     }
339
340     core->vm_regs.rdx = guest_cursor + 8;
341
342     *((uint64_t*)host_cursor) = 0;
343     host_cursor -= 8;
344     guest_cursor -= 8;
345     for (i = 0; i < core->var_dump.argc; i++) {
346         *((uint64_t*)host_cursor) = tmp_args[i];
347         host_cursor -= 8;
348         guest_cursor -= 8;
349     }
350
351     core->vm_regs.rcx = guest_cursor + 8;
352
353     for (i = 0; i < core->var_dump.argc; i++) {
354         V3_Free(core->var_dump.argv[i]);
355     }
356     for (i = 0; i < core->var_dump.envc; i++) {
357         V3_Free(core->var_dump.envp[i]);
358     }
359     
360     V3_Free(core->var_dump.envp);
361     V3_Free(core->var_dump.argv);
362     return 0;
363 }
364
365
366 static int v3_copy_chunk_vmm64(struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
367
368     addr_t envp, argv;
369     uint_t argc = 0, envc = 0, bytes = 0;
370     char * cursor;
371
372     PrintDebug("Initiating copy into vmm\n");
373
374     int ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rdx, &(core->segments.ds)), &envp);
375     if (ret == -1) {
376         PrintDebug("Error translating address in rdx\n");
377         return 0;
378     }
379
380     ret = v3_gva_to_hva(core, get_addr_linear(core, core->vm_regs.rcx, &(core->segments.ds)), &argv);
381     if (ret == -1) {
382         PrintDebug("Error translating address in rcx\n");
383         return 0;
384     }
385     
386     cursor = (char*)argv;
387     while (*((uint64_t*)cursor) != 0) {
388         addr_t argvn;
389         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &argvn);
390         if (ret == -1) {
391             PrintDebug("Error translating address for argvn\n");
392         }
393         argc++;
394         cursor += 8;
395     } 
396     
397     /* account for new strings */
398     argc += argcnt;
399     core->var_dump.argv = (char**)V3_Malloc(sizeof(char*)*argc);
400     core->var_dump.argc = argc;
401     bytes += sizeof(char*)*argc;
402
403     cursor = (char*)argv;
404     int i = 0;
405     while (*((uint64_t*)cursor) != 0) {
406         addr_t argvn;
407         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &argvn);
408         if (ret == -1) {
409             PrintDebug("Error translating argvn address\n");
410         }
411     
412         /* malloc room for the string */
413         char * tmpstr = (char*)V3_Malloc(strlen((char*)argvn) + 1);
414
415         /* copy the pointer */
416         core->var_dump.argv[i] = tmpstr; 
417
418         /* copy the string */
419         strncpy(tmpstr, (char*)argvn, strlen((char*)argvn) + 1);
420         i++;
421         cursor += 8;
422         bytes += strlen((char*)argvn) + 1;
423     }
424         
425     /* stick in new arg strings */
426     int j = 0;
427     while (j < argcnt) {
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;
432         i++; j++;
433     }
434
435
436     cursor = (char*)envp;
437     while (*((uint64_t*)cursor) != 0) {
438         addr_t envpn;
439         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &envpn);
440         if (ret == -1) {
441             PrintDebug("Error translating address for envpn\n");
442         }
443         envc++;
444         cursor += 8;
445     } 
446
447     envc += envcnt;
448     core->var_dump.envp = (char**)V3_Malloc(sizeof(char*)*envc);
449     core->var_dump.envc = envc;
450     bytes += sizeof(uint64_t)*(envc);
451
452
453     cursor = (char*)envp;
454     i = 0;
455     while (*((uint64_t*)cursor) != 0) {
456         addr_t envpn;
457         ret = v3_gva_to_hva(core, get_addr_linear(core, (addr_t)*((uint64_t*)cursor), &(core->segments.ds)), &envpn);
458         if (ret == -1) {
459             PrintDebug("Error translating address for envpn\n");
460         }
461         
462         /* malloc room for the string */
463         char * tmpstr = (char*)V3_Malloc(strlen((char*)envpn) + 1);
464         
465         /* copy the pointer */
466         core->var_dump.envp[i] = tmpstr;
467
468         /* deepcopy the string */
469         strncpy(tmpstr, (char*)envpn, strlen((char*)envpn) + 1);
470         i++;    
471         cursor += 8;
472         bytes += strlen((char*)envpn) + 1; 
473     }
474
475     /* stick in new env strings */
476     j = 0;
477     while (j < envcnt) {
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;
482         i++; j++;
483     } 
484
485
486     /* account for padding for strings
487        and 2 null pointers */
488     bytes += (bytes % 8) + 16;
489     core->var_dump.bytes = bytes;
490     return bytes;
491 }
492
493
494 static int v3_inject_strings64 (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
495
496     addr_t inject_gva;
497     uint_t bytes_needed = 0;
498
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");
502         return -1;
503     }
504
505     PrintDebug("environment successfully copied into VMM\n");
506     
507     inject_gva = v3_prepare_guest_stack(core, bytes_needed);
508     if (!inject_gva) {
509         PrintDebug("Not enough space on user stack\n");
510         return -1;
511     }
512
513     v3_copy_chunk_guest64(core, inject_gva, argcnt, envcnt);
514     return 0;
515 }
516
517
518 addr_t v3_prepare_guest_stack (struct guest_info * core, uint_t bytes_needed) {
519
520     /* TODO: check if we've injected a page fault to get more stack space */
521
522     // do we have enough room between esp and the next page boundary?
523     uint_t rem_bytes = 4096 - (core->vm_regs.rsp % 4096);
524
525     if (rem_bytes >= bytes_needed) {
526         return (addr_t)core->vm_regs.rsp;
527     } else {
528         // not enough room, find out how many pages we need (ceiling)
529         uint_t num_pages = (bytes_needed + 4095) / 4096;
530         
531         // check if num_pages are user & writable
532         int i = 0;
533         int pages_ok = 1;
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)) {
537                 pages_ok = 0;
538             }
539         }
540
541         if (pages_ok) {
542             return (addr_t)core->vm_regs.rsp;
543         } else {
544     
545             /*
546             // inject a page fault
547             pf_error_t fault_type = {
548                 .write = 1,
549                 .user = 1
550             };
551
552             // hoping Linux will allocate all pages in between gva and esp 
553             v3_inject_guest_pf(core, gva - (num_pages*4096), fault_type);
554             */
555             return -1;
556         }
557     }
558 }
559
560
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) { 
563
564     return 0;
565 }
566
567
568 int v3_replace_env (struct guest_info * core, const char * envname, const char * newval) {
569
570     return 0;
571 }
572
573
574 int v3_inject_strings (struct guest_info * core, const char ** argstrs, const char ** envstrs, uint_t argcnt, uint_t envcnt) {
575     
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");
579             return -1;
580         }
581     } else {
582         if (v3_inject_strings32(core, argstrs, envstrs, argcnt, envcnt) == -1) {
583             PrintDebug("Error injecting strings into environment (32)\n");
584             return -1;
585         }
586     }
587
588     return 0;
589 }