blob: 2a12f01a7a760cf813ede3c348068c07dea7f943 [file] [log] [blame]
jseward2886b0e2004-01-04 03:46:11 +00001
nethercotebb1c9912004-01-04 16:43:23 +00002/*--------------------------------------------------------------------*/
3/*--- User-mode execve() ume.c ---*/
4/*--------------------------------------------------------------------*/
5
jseward2886b0e2004-01-04 03:46:11 +00006/*
7 This file is part of Valgrind, an extensible x86 protected-mode
8 emulator for monitoring program execution on x86-Unixes.
9
10 Copyright (C) 2000-2004 Julian Seward
11 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
fitzhardinge7e343cd2003-12-16 02:14:00 +000031/*
32 User-mode exec
33
34 This bootstraps Valgrind. This code decides on the layout of the
35 client and Valgrind address spaces, loads valgrind.so and the
36 skin.so into the valgrind part, loads the client executable (and the
37 dynamic linker, if necessary) into the client part, and calls into
38 Valgrind proper.
39
40 The code is careful not to allow spurious mappings to appear in the
41 wrong parts of the address space. In particular, to make sure
42 dlopen puts things in the right place, it will pad out the forbidden
43 chunks of address space so that dlopen is forced to put things where
44 we want them.
45
46 The memory map it creates is:
47
48 CLIENT_BASE +-------------------------+
49 | client address space |
50 : :
51 : :
52 | client stack |
53 client_end +-------------------------+
54 | redzone |
55 shadow_base +-------------------------+
56 | |
57 : shadow memory for skins :
58 | (may be 0 sized) |
59 shadow_end +-------------------------+
60 : gap (may be 0 sized) :
61 valgrind_base +-------------------------+
62 | valgrind .so files |
63 | and mappings |
64 valgrind_mmap_end -
65 | kickstart executable |
66 - -
67 | valgrind heap vvvvvvvvv|
68 valgrind_end - -
69 | valgrind stack ^^^^^^^^^|
70 +-------------------------+
71 : kernel :
72 */
73
74#define _GNU_SOURCE
75#define _FILE_OFFSET_BITS 64
76
77#include "vg_include.h"
78
79#include <stddef.h>
80#include <sys/mman.h>
81#include <fcntl.h>
82#include <errno.h>
83#include <elf.h>
84#include <stdio.h>
85#include <string.h>
86#include <stdlib.h>
87#include <unistd.h>
fitzhardinge7e343cd2003-12-16 02:14:00 +000088#include <sys/stat.h>
fitzhardinge7e343cd2003-12-16 02:14:00 +000089#include <dlfcn.h>
90#include <assert.h>
91
92#include "ume.h"
93
94static int padfile = -1;
95static struct stat padstat;
96
97extern int kickstart_base; /* linker created */
98
99void foreach_map(int (*fn)(void *start, void *end,
100 const char *perm, off_t offset,
101 int maj, int min, int ino))
102{
103 static char buf[10240];
104 char *bufptr = buf;
105 int ret, fd;
106
107 fd = open("/proc/self/maps", O_RDONLY);
108
109 if (fd == -1) {
110 perror("open /proc/self/maps");
111 return;
112 }
113
114 ret = read(fd, buf, sizeof(buf));
115
116 if (ret == -1) {
117 perror("read /proc/self/maps");
118 close(fd);
119 return;
120 }
121 close(fd);
122
123 if (ret == sizeof(buf)) {
124 fprintf(stderr, "buf too small\n");
125 return;
126 }
127
128 while(bufptr && bufptr < buf+ret) {
129 char perm[5];
130 off_t offset;
131 int maj, min;
132 int ino;
133 void *segstart, *segend;
134
135 sscanf(bufptr, "%p-%p %s %Lx %x:%x %d",
136 &segstart, &segend, perm, &offset, &maj, &min, &ino);
137 bufptr = strchr(bufptr, '\n');
138 if (bufptr != NULL)
139 bufptr++; /* skip \n */
140
141 if (!(*fn)(segstart, segend, perm, offset, maj, min, ino))
142 break;
143 }
144}
145
146/* pad all the empty spaces in a range of address space to stop
147 interlopers */
148void as_pad(void *start, void *end)
149{
150 char buf[1024];
151 char *addr;
152
153 int fillgap(void *segstart, void *segend, const char *perm, off_t off,
154 int maj, int min, int ino) {
155 if (segstart >= end)
156 return 0;
157
158 if ((char *)segstart > addr)
159 mmap(addr, (char *)segstart-addr, PROT_NONE, MAP_FIXED|MAP_PRIVATE,
160 padfile, 0);
161 addr = segend;
162
163 return 1;
164 }
165
166 if (padfile == -1) {
167 int seq = 1;
168 do {
169 sprintf(buf, "/tmp/.pad.%d.%d", getpid(), seq++);
170 padfile = open(buf, O_RDWR|O_CREAT|O_EXCL, 0);
171 unlink(buf);
172 if (padfile == -1 && errno != EEXIST)
173 exit(44);
174 } while(padfile == -1);
175 fstat(padfile, &padstat);
176 }
177
178 addr = start;
179
180 foreach_map(fillgap);
181
182 if (addr < (char *)end)
183 mmap(addr, (char *)end-addr, PROT_NONE, MAP_FIXED|MAP_PRIVATE,
184 padfile, 0);
185}
186
187/* remove padding from a range of address space - padding is always a
188 mapping of padfile*/
189void as_unpad(void *start, void *end)
190{
191 int killpad(void *segstart, void *segend, const char *perm, off_t off,
192 int maj, int min, int ino) {
193 void *b, *e;
194
195 if (padstat.st_dev != makedev(maj, min) || padstat.st_ino != ino)
196 return 1;
197
198 if (segend <= start || segstart >= end)
199 return 1;
200
201 if (segstart <= start)
202 b = start;
203 else
204 b = segstart;
205
206 if (segend >= end)
207 e = end;
208 else
209 e = segend;
210
211 munmap(b, (char *)e-(char *)b);
212
213 return 1;
214 }
215
216 if (padfile == -1) /* no padfile, no padding */
217 return;
218
219 foreach_map(killpad);
220}
221
222void as_closepadfile(void)
223{
224 /* don't unpad */
225 close(padfile);
226 padfile = -1;
227}
228
229int as_getpadfd(void)
230{
231 return padfile;
232}
233
234void as_setpadfd(int fd)
235{
236 as_closepadfile();
237 padfile = fd;
238 fstat(padfile, &padstat);
239}
240
241struct ume_auxv *find_auxv(int *esp)
242{
243 esp++; /* skip argc */
244
245 while(*esp != 0) /* skip argv */
246 esp++;
247 esp++;
248
249 while(*esp != 0) /* skip env */
250 esp++;
251 esp++;
252
253 return (struct ume_auxv *)esp;
254}
255
256
257struct elfinfo *readelf(int fd, const char *filename)
258{
259 struct elfinfo *e = malloc(sizeof(*e));
260 int phsz;
261
262 e->fd = fd;
263
264 if (pread(fd, &e->e, sizeof(e->e), 0) != sizeof(e->e)) {
265 fprintf(stderr, "%s: can't read elf header: %s\n",
266 filename, strerror(errno));
267 return NULL;
268 }
269
270 if (memcmp(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) {
271 fprintf(stderr, "%s: bad ELF magic\n",
272 filename);
273 return NULL;
274 }
275 if (e->e.e_ident[EI_CLASS] != ELFCLASS32) {
276 fprintf(stderr, "Can only handle 32-bit executables\n");
277 return NULL;
278 }
279 if (e->e.e_ident[EI_DATA] != ELFDATA2LSB) {
280 fprintf(stderr, "Expecting little-endian\n");
281 return NULL;
282 }
283 if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) {
284 fprintf(stderr, "need executable\n");
285 return NULL;
286 }
287
288 if (e->e.e_machine != EM_386) {
289 fprintf(stderr, "need x86\n");
290 return NULL;
291 }
292
293 if (e->e.e_phentsize != sizeof(ESZ(Phdr))) {
294 fprintf(stderr, "sizeof Phdr wrong\n");
295 return NULL;
296 }
297
298 phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum;
299 e->p = malloc(phsz);
300
301 if (pread(fd, e->p, phsz, e->e.e_phoff) != phsz) {
302 fprintf(stderr, "can't read phdr: %s\n", strerror(errno));
303 return NULL;
304 }
305
306 return e;
307}
308
309#define REMAINS(x, a) ((x) & ((a)-1))
310
311/* Map an ELF file. Returns the brk address. */
312ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base, int setbrk)
313{
314 int i;
315 ESZ(Addr) elfbrk = 0;
316
317 for(i = 0; i < e->e.e_phnum; i++) {
318 ESZ(Phdr) *ph = &e->p[i];
319 ESZ(Addr) addr, brkaddr;
320 ESZ(Word) memsz;
321
322 if (ph->p_type != PT_LOAD)
323 continue;
324
325 addr = ph->p_vaddr+base;
326 memsz = ph->p_memsz;
327 brkaddr = addr+memsz;
328
329 if (brkaddr > elfbrk)
330 elfbrk = brkaddr;
331 }
332
333 if (setbrk) {
334 /* sneaking up on the brk limit works better than actually
335 jumping directly there. Unfortunately, setting the brk is
336 tested against the datasize rlimit, even though we're not
337 actually using any memory. */
338 char *b = sbrk(0);
339 char *initb = (char *)PGROUNDUP(b);
340
341 while(b < (char *)elfbrk) {
342 unsigned delta = (char *)elfbrk - b;
343 static const unsigned limit = 256*1024*1024;
344 char *bb;
345
346 if (delta > limit)
347 delta = limit;
348 //printf("elfbrk=%p b=%p delta=%u\n", elfbrk, b, delta);
349 bb = sbrk(delta);
350 if (bb != b) {
351 fprintf(stderr, "sbrk failed while adjusting brk base: "
352 "perhaps we hit the datasize ulimit?\n");
fitzhardinge92360792003-12-24 10:11:11 +0000353 return 0;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000354 }
355 b += delta;
356 }
357 munmap(initb, (char *)PGROUNDDN(elfbrk)-initb);
358 }
359
360 for(i = 0; i < e->e.e_phnum; i++) {
361 ESZ(Phdr) *ph = &e->p[i];
362 ESZ(Addr) addr, bss, brkaddr;
363 ESZ(Off) off;
364 ESZ(Word) filesz;
365 ESZ(Word) memsz;
366 ESZ(Word) align;
367 unsigned prot = 0;
368
369 if (ph->p_type != PT_LOAD)
370 continue;
371
372 if (ph->p_flags & PF_X)
373 prot |= PROT_EXEC;
374 if (ph->p_flags & PF_W)
375 prot |= PROT_WRITE;
376 if (ph->p_flags & PF_R)
377 prot |= PROT_READ;
378
379 align = ph->p_align;
380
381 addr = ph->p_vaddr+base;
382 off = ph->p_offset;
383 filesz = ph->p_filesz;
384 bss = addr+filesz;
385 memsz = ph->p_memsz;
386 brkaddr = addr+memsz;
387
388 mmap((char *)ROUNDDN(addr, align), ROUNDUP(bss, align)-ROUNDDN(addr, align),
389 prot, MAP_FIXED|MAP_PRIVATE, e->fd, ROUNDDN(off, align));
390
391 /* if memsz > filesz, then we need to fill the remainder with zeroed pages */
392 if (memsz > filesz) {
393 UInt bytes;
394
395 bytes = ROUNDUP(brkaddr, align)-ROUNDUP(bss, align);
396 if (bytes > 0)
397 mmap((char *)ROUNDUP(bss, align), bytes,
398 prot, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
399
400 bytes = bss & (VKI_BYTES_PER_PAGE - 1);
401 if (bytes > 0) {
402 bytes = VKI_BYTES_PER_PAGE - bytes;
403 memset((char *)bss, 0, bytes);
404 }
405 }
406 }
407
408 return elfbrk;
409}
410
411
412static int do_exec_inner(const char *exe, struct exeinfo *info);
413
414
415static int match_ELF(const char *hdr, int len)
416{
417 ESZ(Ehdr) *e = (ESZ(Ehdr) *)hdr;
418 return (len > sizeof(*e)) && memcmp(&e->e_ident[0], ELFMAG, SELFMAG) == 0;
419}
420
421static int load_ELF(char *hdr, int len, int fd, const char *name, struct exeinfo *info)
422{
423 struct elfinfo *e;
424 struct elfinfo *interp = NULL;
425 ESZ(Addr) minaddr = ~0;
426 ESZ(Addr) maxaddr = 0;
427 ESZ(Addr) interp_addr = 0;
428 ESZ(Word) interp_size = 0;
429 int i;
430 void *entry;
431
432 e = readelf(fd, name);
433
434 if (e == NULL)
435 return ENOEXEC;
436
437 info->phnum = e->e.e_phnum;
438 info->entry = e->e.e_entry;
439
440 for(i = 0; i < e->e.e_phnum; i++) {
441 ESZ(Phdr) *ph = &e->p[i];
442
443 switch(ph->p_type) {
444 case PT_PHDR:
445 info->phdr = ph->p_vaddr;
446 break;
447
448 case PT_LOAD:
449 if (ph->p_vaddr < minaddr)
450 minaddr = ph->p_vaddr;
451 if (ph->p_vaddr+ph->p_memsz > maxaddr)
452 maxaddr = ph->p_vaddr+ph->p_memsz;
453 break;
454
455 case PT_INTERP: {
456 char *buf = malloc(ph->p_filesz+1);
457 int j;
458 int intfd;
459 int baseaddr_set;
460
461 pread(fd, buf, ph->p_filesz, ph->p_offset);
462 buf[ph->p_filesz] = '\0';
463
464 intfd = open(buf, O_RDONLY);
465 if (intfd == -1) {
466 perror("open interp");
467 exit(1);
468 }
469
470 interp = readelf(intfd, buf);
471 if (interp == NULL) {
472 fprintf(stderr, "Can't read interpreter\n");
473 return 1;
474 }
475 free(buf);
476
477 baseaddr_set = 0;
478 for(j = 0; j < interp->e.e_phnum; j++) {
479 ESZ(Phdr) *iph = &interp->p[j];
480 ESZ(Addr) end;
481
482 if (iph->p_type != PT_LOAD)
483 continue;
484
485 if (!baseaddr_set) {
486 interp_addr = iph->p_vaddr;
487 baseaddr_set = 1;
488 }
489
490 /* assumes that all segments in the interp are close */
491 end = (iph->p_vaddr - interp_addr) + iph->p_memsz;
492
493 if (end > interp_size)
494 interp_size = end;
495 }
496 break;
497 }
498 }
499 }
500
501 if (info->exe_base != info->exe_end) {
502 if (minaddr >= maxaddr ||
503 (minaddr < info->exe_base ||
504 maxaddr > info->exe_end)) {
505 fprintf(stderr, "Executable is mapped outside of range %p-%p\n",
506 (void *)info->exe_base, (void *)info->exe_end);
507 return ENOMEM;
508 }
509 }
510
511 info->brkbase = mapelf(e, 0, info->setbrk); /* map the executable */
512
fitzhardinge92360792003-12-24 10:11:11 +0000513 if (info->brkbase == 0)
514 return ENOMEM;
515
fitzhardinge7e343cd2003-12-16 02:14:00 +0000516 if (interp != NULL) {
517 /* reserve a chunk of address space for interpreter */
518 char *base = (char *)info->exe_base;
519 char *baseoff;
520 int flags = MAP_PRIVATE|MAP_ANONYMOUS;
521
522 if (info->map_base != 0) {
523 base = (char *)info->map_base;
524 flags |= MAP_FIXED;
525 }
526
527 base = mmap(base, interp_size, PROT_NONE, flags, -1, 0);
528
529 baseoff = base - interp_addr;
530
531 mapelf(interp, (ESZ(Addr))baseoff, 0);
532
533 close(interp->fd);
534 free(interp);
535
536 entry = baseoff + interp->e.e_entry;
537 info->interp_base = (ESZ(Addr))base;
538 } else
539 entry = (void *)e->e.e_entry;
540
541 info->exe_base = minaddr;
542 info->exe_end = maxaddr;
543
544 info->init_eip = (addr_t)entry;
545
546 free(e);
547
548 return 0;
549}
550
551
552static int match_script(const char *hdr, Int len)
553{
554 return (len > 2) && memcmp(hdr, "#!", 2) == 0;
555}
556
557static int load_script(char *hdr, int len, int fd, const char *name, struct exeinfo *info)
558{
559 char *interp;
560 char *const end = hdr+len;
561 char *cp;
562 char *arg = NULL;
563 int eol;
564
565 interp = hdr + 2;
566 while(interp < end && (*interp == ' ' || *interp == '\t'))
567 interp++;
568
569 if (*interp != '/')
570 return ENOEXEC; /* absolute path only for interpreter */
571
572 /* skip over interpreter name */
573 for(cp = interp; cp < end && *cp != ' ' && *cp != '\t' && *cp != '\n'; cp++)
574 ;
575
576 eol = (*cp == '\n');
577
578 *cp++ = '\0';
579
580 if (!eol && cp < end) {
581 /* skip space before arg */
582 while (cp < end && (*cp == '\t' || *cp == ' '))
583 cp++;
584
585 /* arg is from here to eol */
586 arg = cp;
587 while (cp < end && *cp != '\n')
588 cp++;
589 *cp = '\0';
590 }
591
592 info->argv0 = strdup(interp);
593 if (arg != NULL && *arg != '\0')
594 info->argv1 = strdup(arg);
595
596 if (info->argv && info->argv[0] != NULL)
597 info->argv[0] = (char *)name;
598
599 if (0)
600 printf("#! script: argv0=\"%s\" argv1=\"%s\"\n",
601 info->argv0, info->argv1);
602
603 return do_exec_inner(interp, info);
604}
605
606struct binfmt {
607 int (*match)(const char *hdr, int len);
608 int (*load) ( char *hdr, int len, int fd, const char *name, struct exeinfo *);
609};
610
611static const struct binfmt formats[] = {
612 { match_ELF, load_ELF },
613 { match_script, load_script },
614};
615
616
617static int do_exec_inner(const char *exe, struct exeinfo *info)
618{
619 int fd;
620 char buf[VKI_BYTES_PER_PAGE];
621 int bufsz;
622 int i;
623 int ret;
624 struct stat st;
625
626 fd = open(exe, O_RDONLY);
627 if (fd == -1) {
628 if (0)
629 fprintf(stderr, "Can't open executable %s: %s\n",
630 exe, strerror(errno));
631 return errno;
632 }
633
634 if (fstat(fd, &st) == -1)
635 return errno;
636 else {
637 uid_t uid = geteuid();
638 gid_t gid = getegid();
639 gid_t groups[32];
640 int ngrp = getgroups(32, groups);
641
fitzhardingea49f9b52003-12-16 22:26:45 +0000642 if (st.st_mode & (S_ISUID | S_ISGID)) {
643 fprintf(stderr, "Can't execute suid/sgid executable %s\n", exe);
644 return EACCES;
645 }
646
fitzhardinge6d5dafa2004-01-04 23:10:07 +0000647 if (uid == st.st_uid) {
648 if (!(st.st_mode & S_IXUSR))
fitzhardinge7e343cd2003-12-16 02:14:00 +0000649 return EACCES;
fitzhardinge6d5dafa2004-01-04 23:10:07 +0000650 } else {
651 int grpmatch = 0;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000652
fitzhardinge6d5dafa2004-01-04 23:10:07 +0000653 if (gid == st.st_gid)
654 grpmatch = 1;
655 else
656 for(i = 0; i < ngrp; i++)
657 if (groups[i] == st.st_gid) {
658 grpmatch = 1;
659 break;
660 }
661
662 if (grpmatch) {
663 if (!(st.st_mode & S_IXGRP))
664 return EACCES;
665 } else if (!(st.st_mode & S_IXOTH))
666 return EACCES;
667 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000668 }
669
670 bufsz = pread(fd, buf, sizeof(buf), 0);
671 if (bufsz < 0) {
672 fprintf(stderr, "Can't read executable header: %s\n",
673 strerror(errno));
674 close(fd);
675 return errno;
676 }
677
678 ret = ENOEXEC;
679 for(i = 0; i < sizeof(formats)/sizeof(*formats); i++) {
680 if ((formats[i].match)(buf, bufsz)) {
681 ret = (formats[i].load)(buf, bufsz, fd, exe, info);
682 break;
683 }
684 }
685
686 close(fd);
687
688 return ret;
689}
690
691int do_exec(const char *exe, struct exeinfo *info)
692{
693 info->argv0 = NULL;
694 info->argv1 = NULL;
695
696 return do_exec_inner(exe, info);
697}
nethercotebb1c9912004-01-04 16:43:23 +0000698
699/*--------------------------------------------------------------------*/
700/*--- end ume.c ---*/
701/*--------------------------------------------------------------------*/