blob: e85073da000434cc57e450ebac0ec67480075ab1 [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#define _GNU_SOURCE
33#define _FILE_OFFSET_BITS 64
34
35#include "vg_include.h"
36
37#include <stddef.h>
38#include <sys/mman.h>
39#include <fcntl.h>
40#include <errno.h>
41#include <elf.h>
42#include <stdio.h>
43#include <string.h>
44#include <stdlib.h>
45#include <unistd.h>
fitzhardinge7e343cd2003-12-16 02:14:00 +000046#include <sys/stat.h>
fitzhardinge7e343cd2003-12-16 02:14:00 +000047#include <dlfcn.h>
48#include <assert.h>
49
50#include "ume.h"
fitzhardingeb50068f2004-02-24 23:42:55 +000051#include "vg_include.h"
fitzhardinge7e343cd2003-12-16 02:14:00 +000052
53static int padfile = -1;
54static struct stat padstat;
55
56extern int kickstart_base; /* linker created */
57
nethercotebfed1c82004-07-17 12:57:44 +000058void check_mmap(void* res, void* base, int len)
59{
60 if ((void*)-1 == res) {
61 fprintf(stderr, "valgrind: mmap(%p, %d) failed during startup.\n"
62 "valgrind: is there a hard virtual memory limit set?\n",
63 base, len);
64 exit(1);
65 }
66}
67
fitzhardinge7e343cd2003-12-16 02:14:00 +000068void foreach_map(int (*fn)(void *start, void *end,
69 const char *perm, off_t offset,
70 int maj, int min, int ino))
71{
72 static char buf[10240];
73 char *bufptr = buf;
74 int ret, fd;
75
76 fd = open("/proc/self/maps", O_RDONLY);
77
78 if (fd == -1) {
79 perror("open /proc/self/maps");
80 return;
81 }
82
83 ret = read(fd, buf, sizeof(buf));
84
85 if (ret == -1) {
86 perror("read /proc/self/maps");
87 close(fd);
88 return;
89 }
90 close(fd);
91
92 if (ret == sizeof(buf)) {
93 fprintf(stderr, "buf too small\n");
94 return;
95 }
96
97 while(bufptr && bufptr < buf+ret) {
98 char perm[5];
99 off_t offset;
100 int maj, min;
101 int ino;
102 void *segstart, *segend;
103
104 sscanf(bufptr, "%p-%p %s %Lx %x:%x %d",
105 &segstart, &segend, perm, &offset, &maj, &min, &ino);
106 bufptr = strchr(bufptr, '\n');
107 if (bufptr != NULL)
108 bufptr++; /* skip \n */
109
110 if (!(*fn)(segstart, segend, perm, offset, maj, min, ino))
111 break;
112 }
113}
114
thughes4ad52d02004-06-27 17:37:21 +0000115static char *fillgap_addr;
116static char *fillgap_end;
117
118static int fillgap(void *segstart, void *segend, const char *perm, off_t off,
119 int maj, int min, int ino) {
120 if ((char *)segstart >= fillgap_end)
121 return 0;
122
nethercotebfed1c82004-07-17 12:57:44 +0000123 if ((char *)segstart > fillgap_addr) {
124 void* res = mmap(fillgap_addr, (char *)segstart-fillgap_addr, PROT_NONE,
125 MAP_FIXED|MAP_PRIVATE, padfile, 0);
126 check_mmap(res, fillgap_addr, (char*)segstart - fillgap_addr);
127 }
thughes4ad52d02004-06-27 17:37:21 +0000128 fillgap_addr = segend;
129
130 return 1;
131}
132
fitzhardinge7e343cd2003-12-16 02:14:00 +0000133/* pad all the empty spaces in a range of address space to stop
134 interlopers */
135void as_pad(void *start, void *end)
136{
137 char buf[1024];
fitzhardinge7e343cd2003-12-16 02:14:00 +0000138
139 if (padfile == -1) {
140 int seq = 1;
141 do {
142 sprintf(buf, "/tmp/.pad.%d.%d", getpid(), seq++);
143 padfile = open(buf, O_RDWR|O_CREAT|O_EXCL, 0);
144 unlink(buf);
145 if (padfile == -1 && errno != EEXIST)
146 exit(44);
147 } while(padfile == -1);
148 fstat(padfile, &padstat);
149 }
150
thughes4ad52d02004-06-27 17:37:21 +0000151 fillgap_addr = start;
152 fillgap_end = end;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000153
154 foreach_map(fillgap);
155
nethercotebfed1c82004-07-17 12:57:44 +0000156 if (fillgap_addr < fillgap_end) {
157 void* res = mmap(fillgap_addr, fillgap_end-fillgap_addr, PROT_NONE,
158 MAP_FIXED|MAP_PRIVATE, padfile, 0);
159 check_mmap(res, fillgap_addr, fillgap_end - fillgap_addr);
160 }
thughes4ad52d02004-06-27 17:37:21 +0000161}
162
163static void *killpad_start;
164static void *killpad_end;
165
166static int killpad(void *segstart, void *segend, const char *perm, off_t off,
nethercotebfed1c82004-07-17 12:57:44 +0000167 int maj, int min, int ino)
168{
thughes4ad52d02004-06-27 17:37:21 +0000169 void *b, *e;
nethercotebfed1c82004-07-17 12:57:44 +0000170 int res;
thughes4ad52d02004-06-27 17:37:21 +0000171
172 if (padstat.st_dev != makedev(maj, min) || padstat.st_ino != ino)
173 return 1;
174
175 if (segend <= killpad_start || segstart >= killpad_end)
176 return 1;
177
178 if (segstart <= killpad_start)
179 b = killpad_start;
180 else
181 b = segstart;
182
183 if (segend >= killpad_end)
184 e = killpad_end;
185 else
186 e = segend;
187
nethercotebfed1c82004-07-17 12:57:44 +0000188 res = munmap(b, (char *)e-(char *)b);
189 assert(0 == res);
thughes4ad52d02004-06-27 17:37:21 +0000190
191 return 1;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000192}
193
194/* remove padding from a range of address space - padding is always a
195 mapping of padfile*/
196void as_unpad(void *start, void *end)
197{
fitzhardinge7e343cd2003-12-16 02:14:00 +0000198 if (padfile == -1) /* no padfile, no padding */
199 return;
thughes4ad52d02004-06-27 17:37:21 +0000200
201 killpad_start = start;
202 killpad_end = end;
203
fitzhardinge7e343cd2003-12-16 02:14:00 +0000204 foreach_map(killpad);
205}
206
207void as_closepadfile(void)
208{
209 /* don't unpad */
210 close(padfile);
211 padfile = -1;
212}
213
214int as_getpadfd(void)
215{
216 return padfile;
217}
218
219void as_setpadfd(int fd)
220{
221 as_closepadfile();
222 padfile = fd;
223 fstat(padfile, &padstat);
224}
225
226struct ume_auxv *find_auxv(int *esp)
227{
228 esp++; /* skip argc */
229
230 while(*esp != 0) /* skip argv */
231 esp++;
232 esp++;
233
234 while(*esp != 0) /* skip env */
235 esp++;
236 esp++;
237
238 return (struct ume_auxv *)esp;
239}
240
241
242struct elfinfo *readelf(int fd, const char *filename)
243{
244 struct elfinfo *e = malloc(sizeof(*e));
245 int phsz;
246
nethercote7c018f42004-07-17 16:40:50 +0000247 assert(e);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000248 e->fd = fd;
249
250 if (pread(fd, &e->e, sizeof(e->e), 0) != sizeof(e->e)) {
251 fprintf(stderr, "%s: can't read elf header: %s\n",
252 filename, strerror(errno));
253 return NULL;
254 }
255
256 if (memcmp(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) {
257 fprintf(stderr, "%s: bad ELF magic\n",
258 filename);
259 return NULL;
260 }
261 if (e->e.e_ident[EI_CLASS] != ELFCLASS32) {
262 fprintf(stderr, "Can only handle 32-bit executables\n");
263 return NULL;
264 }
265 if (e->e.e_ident[EI_DATA] != ELFDATA2LSB) {
266 fprintf(stderr, "Expecting little-endian\n");
267 return NULL;
268 }
269 if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) {
270 fprintf(stderr, "need executable\n");
271 return NULL;
272 }
273
274 if (e->e.e_machine != EM_386) {
275 fprintf(stderr, "need x86\n");
276 return NULL;
277 }
278
279 if (e->e.e_phentsize != sizeof(ESZ(Phdr))) {
280 fprintf(stderr, "sizeof Phdr wrong\n");
281 return NULL;
282 }
283
284 phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum;
285 e->p = malloc(phsz);
nethercote7c018f42004-07-17 16:40:50 +0000286 assert(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000287
288 if (pread(fd, e->p, phsz, e->e.e_phoff) != phsz) {
289 fprintf(stderr, "can't read phdr: %s\n", strerror(errno));
290 return NULL;
291 }
292
293 return e;
294}
295
296#define REMAINS(x, a) ((x) & ((a)-1))
297
298/* Map an ELF file. Returns the brk address. */
fitzhardingeb50068f2004-02-24 23:42:55 +0000299ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000300{
301 int i;
nethercotebfed1c82004-07-17 12:57:44 +0000302 void* res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000303 ESZ(Addr) elfbrk = 0;
304
305 for(i = 0; i < e->e.e_phnum; i++) {
306 ESZ(Phdr) *ph = &e->p[i];
307 ESZ(Addr) addr, brkaddr;
308 ESZ(Word) memsz;
309
310 if (ph->p_type != PT_LOAD)
311 continue;
312
313 addr = ph->p_vaddr+base;
314 memsz = ph->p_memsz;
315 brkaddr = addr+memsz;
316
317 if (brkaddr > elfbrk)
318 elfbrk = brkaddr;
319 }
320
fitzhardinge7e343cd2003-12-16 02:14:00 +0000321 for(i = 0; i < e->e.e_phnum; i++) {
322 ESZ(Phdr) *ph = &e->p[i];
323 ESZ(Addr) addr, bss, brkaddr;
324 ESZ(Off) off;
325 ESZ(Word) filesz;
326 ESZ(Word) memsz;
327 ESZ(Word) align;
328 unsigned prot = 0;
329
330 if (ph->p_type != PT_LOAD)
331 continue;
332
333 if (ph->p_flags & PF_X)
334 prot |= PROT_EXEC;
335 if (ph->p_flags & PF_W)
336 prot |= PROT_WRITE;
337 if (ph->p_flags & PF_R)
338 prot |= PROT_READ;
339
340 align = ph->p_align;
341
342 addr = ph->p_vaddr+base;
343 off = ph->p_offset;
344 filesz = ph->p_filesz;
345 bss = addr+filesz;
346 memsz = ph->p_memsz;
347 brkaddr = addr+memsz;
348
nethercotebfed1c82004-07-17 12:57:44 +0000349 res = mmap((char *)ROUNDDN(addr, align),
350 ROUNDUP(bss, align)-ROUNDDN(addr, align),
351 prot, MAP_FIXED|MAP_PRIVATE, e->fd, ROUNDDN(off, align));
352 check_mmap(res, (char*)ROUNDDN(addr,align),
353 ROUNDUP(bss, align)-ROUNDDN(addr, align));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000354
355 /* if memsz > filesz, then we need to fill the remainder with zeroed pages */
356 if (memsz > filesz) {
357 UInt bytes;
358
359 bytes = ROUNDUP(brkaddr, align)-ROUNDUP(bss, align);
nethercotebfed1c82004-07-17 12:57:44 +0000360 if (bytes > 0) {
361 res = mmap((char *)ROUNDUP(bss, align), bytes,
362 prot, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
363 check_mmap(res, (char*)ROUNDUP(bss,align), bytes);
364 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000365
366 bytes = bss & (VKI_BYTES_PER_PAGE - 1);
367 if (bytes > 0) {
368 bytes = VKI_BYTES_PER_PAGE - bytes;
369 memset((char *)bss, 0, bytes);
370 }
371 }
372 }
373
374 return elfbrk;
375}
376
377
378static int do_exec_inner(const char *exe, struct exeinfo *info);
379
380
381static int match_ELF(const char *hdr, int len)
382{
383 ESZ(Ehdr) *e = (ESZ(Ehdr) *)hdr;
384 return (len > sizeof(*e)) && memcmp(&e->e_ident[0], ELFMAG, SELFMAG) == 0;
385}
386
387static int load_ELF(char *hdr, int len, int fd, const char *name, struct exeinfo *info)
388{
389 struct elfinfo *e;
390 struct elfinfo *interp = NULL;
391 ESZ(Addr) minaddr = ~0;
392 ESZ(Addr) maxaddr = 0;
393 ESZ(Addr) interp_addr = 0;
394 ESZ(Word) interp_size = 0;
395 int i;
396 void *entry;
397
398 e = readelf(fd, name);
399
400 if (e == NULL)
401 return ENOEXEC;
402
403 info->phnum = e->e.e_phnum;
404 info->entry = e->e.e_entry;
405
406 for(i = 0; i < e->e.e_phnum; i++) {
407 ESZ(Phdr) *ph = &e->p[i];
408
409 switch(ph->p_type) {
410 case PT_PHDR:
411 info->phdr = ph->p_vaddr;
412 break;
413
414 case PT_LOAD:
415 if (ph->p_vaddr < minaddr)
416 minaddr = ph->p_vaddr;
417 if (ph->p_vaddr+ph->p_memsz > maxaddr)
418 maxaddr = ph->p_vaddr+ph->p_memsz;
419 break;
420
421 case PT_INTERP: {
422 char *buf = malloc(ph->p_filesz+1);
423 int j;
424 int intfd;
425 int baseaddr_set;
426
nethercote7c018f42004-07-17 16:40:50 +0000427 assert(buf);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000428 pread(fd, buf, ph->p_filesz, ph->p_offset);
429 buf[ph->p_filesz] = '\0';
430
431 intfd = open(buf, O_RDONLY);
432 if (intfd == -1) {
433 perror("open interp");
434 exit(1);
435 }
436
437 interp = readelf(intfd, buf);
438 if (interp == NULL) {
439 fprintf(stderr, "Can't read interpreter\n");
440 return 1;
441 }
442 free(buf);
443
444 baseaddr_set = 0;
445 for(j = 0; j < interp->e.e_phnum; j++) {
446 ESZ(Phdr) *iph = &interp->p[j];
447 ESZ(Addr) end;
448
449 if (iph->p_type != PT_LOAD)
450 continue;
451
452 if (!baseaddr_set) {
453 interp_addr = iph->p_vaddr;
454 baseaddr_set = 1;
455 }
456
457 /* assumes that all segments in the interp are close */
458 end = (iph->p_vaddr - interp_addr) + iph->p_memsz;
459
460 if (end > interp_size)
461 interp_size = end;
462 }
463 break;
464 }
465 }
466 }
467
468 if (info->exe_base != info->exe_end) {
469 if (minaddr >= maxaddr ||
470 (minaddr < info->exe_base ||
471 maxaddr > info->exe_end)) {
472 fprintf(stderr, "Executable is mapped outside of range %p-%p\n",
473 (void *)info->exe_base, (void *)info->exe_end);
474 return ENOMEM;
475 }
476 }
477
fitzhardingeb50068f2004-02-24 23:42:55 +0000478 info->brkbase = mapelf(e, 0); /* map the executable */
fitzhardinge7e343cd2003-12-16 02:14:00 +0000479
fitzhardinge92360792003-12-24 10:11:11 +0000480 if (info->brkbase == 0)
481 return ENOMEM;
482
fitzhardinge7e343cd2003-12-16 02:14:00 +0000483 if (interp != NULL) {
484 /* reserve a chunk of address space for interpreter */
nethercotebfed1c82004-07-17 12:57:44 +0000485 void* res;
486 char* base = (char *)info->exe_base;
487 char* baseoff;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000488 int flags = MAP_PRIVATE|MAP_ANONYMOUS;
489
490 if (info->map_base != 0) {
491 base = (char *)info->map_base;
492 flags |= MAP_FIXED;
493 }
494
nethercotebfed1c82004-07-17 12:57:44 +0000495 res = mmap(base, interp_size, PROT_NONE, flags, -1, 0);
496 check_mmap(res, base, interp_size);
497 base = res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000498
499 baseoff = base - interp_addr;
500
fitzhardingeb50068f2004-02-24 23:42:55 +0000501 mapelf(interp, (ESZ(Addr))baseoff);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000502
503 close(interp->fd);
504 free(interp);
505
506 entry = baseoff + interp->e.e_entry;
507 info->interp_base = (ESZ(Addr))base;
508 } else
509 entry = (void *)e->e.e_entry;
510
511 info->exe_base = minaddr;
512 info->exe_end = maxaddr;
513
514 info->init_eip = (addr_t)entry;
515
516 free(e);
517
518 return 0;
519}
520
521
522static int match_script(const char *hdr, Int len)
523{
524 return (len > 2) && memcmp(hdr, "#!", 2) == 0;
525}
526
527static int load_script(char *hdr, int len, int fd, const char *name, struct exeinfo *info)
528{
529 char *interp;
530 char *const end = hdr+len;
531 char *cp;
532 char *arg = NULL;
533 int eol;
534
535 interp = hdr + 2;
536 while(interp < end && (*interp == ' ' || *interp == '\t'))
537 interp++;
538
539 if (*interp != '/')
540 return ENOEXEC; /* absolute path only for interpreter */
541
542 /* skip over interpreter name */
543 for(cp = interp; cp < end && *cp != ' ' && *cp != '\t' && *cp != '\n'; cp++)
544 ;
545
546 eol = (*cp == '\n');
547
548 *cp++ = '\0';
549
550 if (!eol && cp < end) {
551 /* skip space before arg */
552 while (cp < end && (*cp == '\t' || *cp == ' '))
553 cp++;
554
555 /* arg is from here to eol */
556 arg = cp;
557 while (cp < end && *cp != '\n')
558 cp++;
559 *cp = '\0';
560 }
561
562 info->argv0 = strdup(interp);
nethercote71980f02004-01-24 18:18:54 +0000563 assert(NULL != info->argv0);
564 if (arg != NULL && *arg != '\0') {
fitzhardinge7e343cd2003-12-16 02:14:00 +0000565 info->argv1 = strdup(arg);
nethercote71980f02004-01-24 18:18:54 +0000566 assert(NULL != info->argv1);
567 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000568
569 if (info->argv && info->argv[0] != NULL)
570 info->argv[0] = (char *)name;
571
572 if (0)
573 printf("#! script: argv0=\"%s\" argv1=\"%s\"\n",
574 info->argv0, info->argv1);
575
576 return do_exec_inner(interp, info);
577}
578
579struct binfmt {
580 int (*match)(const char *hdr, int len);
581 int (*load) ( char *hdr, int len, int fd, const char *name, struct exeinfo *);
582};
583
584static const struct binfmt formats[] = {
585 { match_ELF, load_ELF },
586 { match_script, load_script },
587};
588
589
590static int do_exec_inner(const char *exe, struct exeinfo *info)
591{
592 int fd;
593 char buf[VKI_BYTES_PER_PAGE];
594 int bufsz;
595 int i;
596 int ret;
597 struct stat st;
598
599 fd = open(exe, O_RDONLY);
600 if (fd == -1) {
601 if (0)
602 fprintf(stderr, "Can't open executable %s: %s\n",
603 exe, strerror(errno));
604 return errno;
605 }
606
607 if (fstat(fd, &st) == -1)
608 return errno;
609 else {
610 uid_t uid = geteuid();
611 gid_t gid = getegid();
612 gid_t groups[32];
613 int ngrp = getgroups(32, groups);
614
fitzhardingea49f9b52003-12-16 22:26:45 +0000615 if (st.st_mode & (S_ISUID | S_ISGID)) {
616 fprintf(stderr, "Can't execute suid/sgid executable %s\n", exe);
617 return EACCES;
618 }
619
fitzhardinge6d5dafa2004-01-04 23:10:07 +0000620 if (uid == st.st_uid) {
621 if (!(st.st_mode & S_IXUSR))
fitzhardinge7e343cd2003-12-16 02:14:00 +0000622 return EACCES;
fitzhardinge6d5dafa2004-01-04 23:10:07 +0000623 } else {
624 int grpmatch = 0;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000625
fitzhardinge6d5dafa2004-01-04 23:10:07 +0000626 if (gid == st.st_gid)
627 grpmatch = 1;
628 else
629 for(i = 0; i < ngrp; i++)
630 if (groups[i] == st.st_gid) {
631 grpmatch = 1;
632 break;
633 }
634
635 if (grpmatch) {
636 if (!(st.st_mode & S_IXGRP))
637 return EACCES;
638 } else if (!(st.st_mode & S_IXOTH))
639 return EACCES;
640 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000641 }
642
643 bufsz = pread(fd, buf, sizeof(buf), 0);
644 if (bufsz < 0) {
645 fprintf(stderr, "Can't read executable header: %s\n",
646 strerror(errno));
647 close(fd);
648 return errno;
649 }
650
651 ret = ENOEXEC;
652 for(i = 0; i < sizeof(formats)/sizeof(*formats); i++) {
653 if ((formats[i].match)(buf, bufsz)) {
654 ret = (formats[i].load)(buf, bufsz, fd, exe, info);
655 break;
656 }
657 }
658
659 close(fd);
660
661 return ret;
662}
663
664int do_exec(const char *exe, struct exeinfo *info)
665{
666 info->argv0 = NULL;
667 info->argv1 = NULL;
668
669 return do_exec_inner(exe, info);
670}
nethercotebb1c9912004-01-04 16:43:23 +0000671
672/*--------------------------------------------------------------------*/
673/*--- end ume.c ---*/
674/*--------------------------------------------------------------------*/