blob: cdfb59a99c616421a7fe429cd7f224edd25bfabf [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
nethercotef1e5e152004-09-01 23:58:16 +000035#include "core.h"
fitzhardinge7e343cd2003-12-16 02:14:00 +000036
fitzhardinge7e343cd2003-12-16 02:14:00 +000037#include <sys/mman.h>
38#include <fcntl.h>
39#include <errno.h>
fitzhardinge7e343cd2003-12-16 02:14:00 +000040#include <stdio.h>
41#include <string.h>
42#include <stdlib.h>
43#include <unistd.h>
fitzhardinge7e343cd2003-12-16 02:14:00 +000044#include <assert.h>
45
46#include "ume.h"
47
nethercote1fe54502004-07-26 15:28:33 +000048struct elfinfo
49{
50 ESZ(Ehdr) e;
51 ESZ(Phdr) *p;
52 int fd;
53};
54
nethercote30d37842004-07-26 10:05:55 +000055static void check_mmap(void* res, void* base, int len)
nethercotebfed1c82004-07-17 12:57:44 +000056{
57 if ((void*)-1 == res) {
58 fprintf(stderr, "valgrind: mmap(%p, %d) failed during startup.\n"
59 "valgrind: is there a hard virtual memory limit set?\n",
60 base, len);
61 exit(1);
62 }
63}
64
nethercote31779c72004-07-30 21:50:15 +000065// 'extra' allows the caller to pass in extra args to 'fn', like free
66// variables to a closure.
67void foreach_map(int (*fn)(char *start, char *end,
fitzhardinge7e343cd2003-12-16 02:14:00 +000068 const char *perm, off_t offset,
nethercote31779c72004-07-30 21:50:15 +000069 int maj, int min, int ino, void* extra),
70 void* extra)
fitzhardinge7e343cd2003-12-16 02:14:00 +000071{
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
nethercote31779c72004-07-30 21:50:15 +0000110 if (!(*fn)(segstart, segend, perm, offset, maj, min, ino, extra))
fitzhardinge7e343cd2003-12-16 02:14:00 +0000111 break;
112 }
113}
114
nethercote31779c72004-07-30 21:50:15 +0000115typedef struct {
116 char* fillgap_start;
117 char* fillgap_end;
118 int fillgap_padfile;
119} fillgap_extra;
thughes4ad52d02004-06-27 17:37:21 +0000120
nethercote31779c72004-07-30 21:50:15 +0000121static int fillgap(char *segstart, char *segend, const char *perm, off_t off,
122 int maj, int min, int ino, void* e)
123{
124 fillgap_extra* extra = e;
125
126 if (segstart >= extra->fillgap_end)
thughes4ad52d02004-06-27 17:37:21 +0000127 return 0;
128
nethercote31779c72004-07-30 21:50:15 +0000129 if (segstart > extra->fillgap_start) {
130 void* res = mmap(extra->fillgap_start, segstart - extra->fillgap_start,
fitzhardinge72ddff62004-09-08 20:03:51 +0000131 PROT_NONE, MAP_FIXED|MAP_PRIVATE|MAP_NORESERVE,
nethercote31779c72004-07-30 21:50:15 +0000132 extra->fillgap_padfile, 0);
133 check_mmap(res, extra->fillgap_start, segstart - extra->fillgap_start);
nethercotebfed1c82004-07-17 12:57:44 +0000134 }
nethercote31779c72004-07-30 21:50:15 +0000135 extra->fillgap_start = segend;
thughes4ad52d02004-06-27 17:37:21 +0000136
137 return 1;
138}
139
nethercote31779c72004-07-30 21:50:15 +0000140// Choose a name for the padfile, open it.
141int as_openpadfile(void)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000142{
nethercote31779c72004-07-30 21:50:15 +0000143 char buf[256];
144 int padfile;
145 int seq = 1;
146 do {
147 snprintf(buf, 256, "/tmp/.pad.%d.%d", getpid(), seq++);
148 padfile = open(buf, O_RDWR|O_CREAT|O_EXCL, 0);
149 unlink(buf);
150 if (padfile == -1 && errno != EEXIST) {
151 fprintf(stderr, "valgrind: couldn't open padfile\n");
152 exit(44);
153 }
154 } while(padfile == -1);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000155
nethercote31779c72004-07-30 21:50:15 +0000156 return padfile;
157}
fitzhardinge7e343cd2003-12-16 02:14:00 +0000158
nethercote31779c72004-07-30 21:50:15 +0000159// Pad all the empty spaces in a range of address space to stop interlopers.
160void as_pad(void *start, void *end, int padfile)
161{
162 fillgap_extra extra;
163 extra.fillgap_start = start;
164 extra.fillgap_end = end;
165 extra.fillgap_padfile = padfile;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000166
nethercote31779c72004-07-30 21:50:15 +0000167 foreach_map(fillgap, &extra);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000168
nethercote31779c72004-07-30 21:50:15 +0000169 if (extra.fillgap_start < extra.fillgap_end) {
170 void* res = mmap(extra.fillgap_start,
171 extra.fillgap_end - extra.fillgap_start,
fitzhardinge72ddff62004-09-08 20:03:51 +0000172 PROT_NONE, MAP_FIXED|MAP_PRIVATE|MAP_NORESERVE, padfile, 0);
nethercote31779c72004-07-30 21:50:15 +0000173 check_mmap(res, extra.fillgap_start,
174 extra.fillgap_end - extra.fillgap_start);
nethercotebfed1c82004-07-17 12:57:44 +0000175 }
thughes4ad52d02004-06-27 17:37:21 +0000176}
177
nethercote31779c72004-07-30 21:50:15 +0000178typedef struct {
179 char* killpad_start;
180 char* killpad_end;
181 struct stat* killpad_padstat;
182} killpad_extra;
thughes4ad52d02004-06-27 17:37:21 +0000183
nethercote31779c72004-07-30 21:50:15 +0000184static int killpad(char *segstart, char *segend, const char *perm, off_t off,
185 int maj, int min, int ino, void* ex)
nethercotebfed1c82004-07-17 12:57:44 +0000186{
nethercote31779c72004-07-30 21:50:15 +0000187 killpad_extra* extra = ex;
thughes4ad52d02004-06-27 17:37:21 +0000188 void *b, *e;
nethercotebfed1c82004-07-17 12:57:44 +0000189 int res;
thughes4ad52d02004-06-27 17:37:21 +0000190
nethercote31779c72004-07-30 21:50:15 +0000191 assert(NULL != extra->killpad_padstat);
192
193 if (extra->killpad_padstat->st_dev != makedev(maj, min) ||
194 extra->killpad_padstat->st_ino != ino)
thughes4ad52d02004-06-27 17:37:21 +0000195 return 1;
196
nethercote31779c72004-07-30 21:50:15 +0000197 if (segend <= extra->killpad_start || segstart >= extra->killpad_end)
thughes4ad52d02004-06-27 17:37:21 +0000198 return 1;
199
nethercote31779c72004-07-30 21:50:15 +0000200 if (segstart <= extra->killpad_start)
201 b = extra->killpad_start;
thughes4ad52d02004-06-27 17:37:21 +0000202 else
203 b = segstart;
204
nethercote31779c72004-07-30 21:50:15 +0000205 if (segend >= extra->killpad_end)
206 e = extra->killpad_end;
thughes4ad52d02004-06-27 17:37:21 +0000207 else
208 e = segend;
209
nethercotebfed1c82004-07-17 12:57:44 +0000210 res = munmap(b, (char *)e-(char *)b);
211 assert(0 == res);
thughes4ad52d02004-06-27 17:37:21 +0000212
213 return 1;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000214}
215
nethercote31779c72004-07-30 21:50:15 +0000216// Remove padding of 'padfile' from a range of address space.
217void as_unpad(void *start, void *end, int padfile)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000218{
nethercote31779c72004-07-30 21:50:15 +0000219 static struct stat padstat;
220 killpad_extra extra;
221 int res;
222
223 assert(padfile > 0);
thughes4ad52d02004-06-27 17:37:21 +0000224
nethercote31779c72004-07-30 21:50:15 +0000225 res = fstat(padfile, &padstat);
226 assert(0 == res);
227 extra.killpad_padstat = &padstat;
228 extra.killpad_start = start;
229 extra.killpad_end = end;
230 foreach_map(killpad, &extra);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000231}
232
nethercote31779c72004-07-30 21:50:15 +0000233void as_closepadfile(int padfile)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000234{
nethercote31779c72004-07-30 21:50:15 +0000235 int res = close(padfile);
236 assert(0 == res);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000237}
238
nethercote31779c72004-07-30 21:50:15 +0000239/*------------------------------------------------------------*/
240/*--- Finding auxv on the stack ---*/
241/*------------------------------------------------------------*/
fitzhardinge7e343cd2003-12-16 02:14:00 +0000242
243struct ume_auxv *find_auxv(int *esp)
244{
245 esp++; /* skip argc */
246
247 while(*esp != 0) /* skip argv */
248 esp++;
249 esp++;
250
251 while(*esp != 0) /* skip env */
252 esp++;
253 esp++;
254
255 return (struct ume_auxv *)esp;
256}
257
nethercote31779c72004-07-30 21:50:15 +0000258/*------------------------------------------------------------*/
259/*--- Loading ELF files ---*/
260/*------------------------------------------------------------*/
fitzhardinge7e343cd2003-12-16 02:14:00 +0000261
262struct elfinfo *readelf(int fd, const char *filename)
263{
264 struct elfinfo *e = malloc(sizeof(*e));
265 int phsz;
266
nethercote7c018f42004-07-17 16:40:50 +0000267 assert(e);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000268 e->fd = fd;
269
270 if (pread(fd, &e->e, sizeof(e->e), 0) != sizeof(e->e)) {
nethercote08eaff32004-07-22 12:41:12 +0000271 fprintf(stderr, "valgrind: %s: can't read elf header: %s\n",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000272 filename, strerror(errno));
273 return NULL;
274 }
275
276 if (memcmp(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) {
nethercote08eaff32004-07-22 12:41:12 +0000277 fprintf(stderr, "valgrind: %s: bad ELF magic\n", filename);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000278 return NULL;
279 }
280 if (e->e.e_ident[EI_CLASS] != ELFCLASS32) {
nethercote08eaff32004-07-22 12:41:12 +0000281 fprintf(stderr, "valgrind: Can only handle 32-bit executables\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000282 return NULL;
283 }
284 if (e->e.e_ident[EI_DATA] != ELFDATA2LSB) {
nethercote08eaff32004-07-22 12:41:12 +0000285 fprintf(stderr, "valgrind: Expecting little-endian\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000286 return NULL;
287 }
288 if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) {
nethercote08eaff32004-07-22 12:41:12 +0000289 fprintf(stderr, "valgrind: need executable\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000290 return NULL;
291 }
292
293 if (e->e.e_machine != EM_386) {
nethercote08eaff32004-07-22 12:41:12 +0000294 fprintf(stderr, "valgrind: need x86\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000295 return NULL;
296 }
297
298 if (e->e.e_phentsize != sizeof(ESZ(Phdr))) {
nethercote08eaff32004-07-22 12:41:12 +0000299 fprintf(stderr, "valgrind: sizeof Phdr wrong\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000300 return NULL;
301 }
302
303 phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum;
304 e->p = malloc(phsz);
nethercote7c018f42004-07-17 16:40:50 +0000305 assert(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000306
307 if (pread(fd, e->p, phsz, e->e.e_phoff) != phsz) {
nethercote08eaff32004-07-22 12:41:12 +0000308 fprintf(stderr, "valgrind: can't read phdr: %s\n", strerror(errno));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000309 return NULL;
310 }
311
312 return e;
313}
314
fitzhardinge7e343cd2003-12-16 02:14:00 +0000315/* Map an ELF file. Returns the brk address. */
fitzhardingeb50068f2004-02-24 23:42:55 +0000316ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000317{
318 int i;
nethercotebfed1c82004-07-17 12:57:44 +0000319 void* res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000320 ESZ(Addr) elfbrk = 0;
321
322 for(i = 0; i < e->e.e_phnum; i++) {
323 ESZ(Phdr) *ph = &e->p[i];
324 ESZ(Addr) addr, brkaddr;
325 ESZ(Word) memsz;
326
327 if (ph->p_type != PT_LOAD)
328 continue;
329
330 addr = ph->p_vaddr+base;
331 memsz = ph->p_memsz;
332 brkaddr = addr+memsz;
333
334 if (brkaddr > elfbrk)
335 elfbrk = brkaddr;
336 }
337
fitzhardinge7e343cd2003-12-16 02:14:00 +0000338 for(i = 0; i < e->e.e_phnum; i++) {
339 ESZ(Phdr) *ph = &e->p[i];
340 ESZ(Addr) addr, bss, brkaddr;
341 ESZ(Off) off;
342 ESZ(Word) filesz;
343 ESZ(Word) memsz;
344 ESZ(Word) align;
345 unsigned prot = 0;
346
347 if (ph->p_type != PT_LOAD)
348 continue;
349
350 if (ph->p_flags & PF_X)
351 prot |= PROT_EXEC;
352 if (ph->p_flags & PF_W)
353 prot |= PROT_WRITE;
354 if (ph->p_flags & PF_R)
355 prot |= PROT_READ;
356
357 align = ph->p_align;
358
359 addr = ph->p_vaddr+base;
360 off = ph->p_offset;
361 filesz = ph->p_filesz;
362 bss = addr+filesz;
363 memsz = ph->p_memsz;
364 brkaddr = addr+memsz;
365
nethercotebfed1c82004-07-17 12:57:44 +0000366 res = mmap((char *)ROUNDDN(addr, align),
367 ROUNDUP(bss, align)-ROUNDDN(addr, align),
368 prot, MAP_FIXED|MAP_PRIVATE, e->fd, ROUNDDN(off, align));
369 check_mmap(res, (char*)ROUNDDN(addr,align),
370 ROUNDUP(bss, align)-ROUNDDN(addr, align));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000371
372 /* if memsz > filesz, then we need to fill the remainder with zeroed pages */
373 if (memsz > filesz) {
374 UInt bytes;
375
376 bytes = ROUNDUP(brkaddr, align)-ROUNDUP(bss, align);
nethercotebfed1c82004-07-17 12:57:44 +0000377 if (bytes > 0) {
378 res = mmap((char *)ROUNDUP(bss, align), bytes,
379 prot, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
380 check_mmap(res, (char*)ROUNDUP(bss,align), bytes);
381 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000382
383 bytes = bss & (VKI_BYTES_PER_PAGE - 1);
384 if (bytes > 0) {
385 bytes = VKI_BYTES_PER_PAGE - bytes;
386 memset((char *)bss, 0, bytes);
387 }
388 }
389 }
390
391 return elfbrk;
392}
393
nethercote31779c72004-07-30 21:50:15 +0000394// Forward declaration.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000395static int do_exec_inner(const char *exe, struct exeinfo *info);
396
fitzhardinge7e343cd2003-12-16 02:14:00 +0000397static int match_ELF(const char *hdr, int len)
398{
399 ESZ(Ehdr) *e = (ESZ(Ehdr) *)hdr;
400 return (len > sizeof(*e)) && memcmp(&e->e_ident[0], ELFMAG, SELFMAG) == 0;
401}
402
nethercote31779c72004-07-30 21:50:15 +0000403static int load_ELF(char *hdr, int len, int fd, const char *name,
404 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000405{
406 struct elfinfo *e;
407 struct elfinfo *interp = NULL;
fitzhardingeca9bd9c2004-09-08 20:05:02 +0000408 ESZ(Addr) exeoff = 0; /* offset between link address and load address */
409 ESZ(Addr) minaddr = ~0; /* lowest mapped address */
410 ESZ(Addr) maxaddr = 0; /* highest mapped address */
411 ESZ(Addr) interp_addr = 0; /* interpreter (ld.so) address */
412 ESZ(Word) interp_size = 0; /* interpreter size */
fitzhardinge7e343cd2003-12-16 02:14:00 +0000413 int i;
414 void *entry;
415
416 e = readelf(fd, name);
417
418 if (e == NULL)
419 return ENOEXEC;
420
421 info->phnum = e->e.e_phnum;
422 info->entry = e->e.e_entry;
423
424 for(i = 0; i < e->e.e_phnum; i++) {
425 ESZ(Phdr) *ph = &e->p[i];
426
427 switch(ph->p_type) {
428 case PT_PHDR:
429 info->phdr = ph->p_vaddr;
430 break;
431
432 case PT_LOAD:
433 if (ph->p_vaddr < minaddr)
434 minaddr = ph->p_vaddr;
435 if (ph->p_vaddr+ph->p_memsz > maxaddr)
436 maxaddr = ph->p_vaddr+ph->p_memsz;
437 break;
438
439 case PT_INTERP: {
440 char *buf = malloc(ph->p_filesz+1);
441 int j;
442 int intfd;
443 int baseaddr_set;
444
nethercote7c018f42004-07-17 16:40:50 +0000445 assert(buf);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000446 pread(fd, buf, ph->p_filesz, ph->p_offset);
447 buf[ph->p_filesz] = '\0';
448
449 intfd = open(buf, O_RDONLY);
450 if (intfd == -1) {
451 perror("open interp");
452 exit(1);
453 }
454
455 interp = readelf(intfd, buf);
456 if (interp == NULL) {
457 fprintf(stderr, "Can't read interpreter\n");
458 return 1;
459 }
460 free(buf);
461
462 baseaddr_set = 0;
463 for(j = 0; j < interp->e.e_phnum; j++) {
464 ESZ(Phdr) *iph = &interp->p[j];
465 ESZ(Addr) end;
466
467 if (iph->p_type != PT_LOAD)
468 continue;
469
470 if (!baseaddr_set) {
471 interp_addr = iph->p_vaddr;
472 baseaddr_set = 1;
473 }
474
475 /* assumes that all segments in the interp are close */
476 end = (iph->p_vaddr - interp_addr) + iph->p_memsz;
477
478 if (end > interp_size)
479 interp_size = end;
480 }
481 break;
nethercoteb24cbc82004-09-03 23:25:33 +0000482
483 default:
484 // do nothing
485 break;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000486 }
487 }
488 }
489
fitzhardingeca9bd9c2004-09-08 20:05:02 +0000490 if (e->e.e_type == ET_DYN) {
491 /* PIE executable */
492 exeoff = info->exe_base - minaddr;
493 }
494
495 minaddr += exeoff;
496 maxaddr += exeoff;
497 info->phdr += exeoff;
498 info->entry += exeoff;
499
fitzhardinge7e343cd2003-12-16 02:14:00 +0000500 if (info->exe_base != info->exe_end) {
501 if (minaddr >= maxaddr ||
502 (minaddr < info->exe_base ||
503 maxaddr > info->exe_end)) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000504 fprintf(stderr, "Executable range %p-%p is outside the\n"
505 "acceptable range %p-%p\n",
506 (void *)minaddr, (void *)maxaddr,
fitzhardinge7e343cd2003-12-16 02:14:00 +0000507 (void *)info->exe_base, (void *)info->exe_end);
508 return ENOMEM;
509 }
510 }
511
fitzhardingeca9bd9c2004-09-08 20:05:02 +0000512 info->brkbase = mapelf(e, exeoff); /* map the executable */
fitzhardinge7e343cd2003-12-16 02:14:00 +0000513
fitzhardinge92360792003-12-24 10:11:11 +0000514 if (info->brkbase == 0)
515 return ENOMEM;
516
fitzhardinge7e343cd2003-12-16 02:14:00 +0000517 if (interp != NULL) {
518 /* reserve a chunk of address space for interpreter */
nethercotebfed1c82004-07-17 12:57:44 +0000519 void* res;
520 char* base = (char *)info->exe_base;
521 char* baseoff;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000522 int flags = MAP_PRIVATE|MAP_ANONYMOUS;
523
524 if (info->map_base != 0) {
525 base = (char *)info->map_base;
526 flags |= MAP_FIXED;
527 }
528
nethercotebfed1c82004-07-17 12:57:44 +0000529 res = mmap(base, interp_size, PROT_NONE, flags, -1, 0);
530 check_mmap(res, base, interp_size);
531 base = res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000532
533 baseoff = base - interp_addr;
534
fitzhardingeb50068f2004-02-24 23:42:55 +0000535 mapelf(interp, (ESZ(Addr))baseoff);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000536
537 close(interp->fd);
538 free(interp);
539
540 entry = baseoff + interp->e.e_entry;
541 info->interp_base = (ESZ(Addr))base;
542 } else
fitzhardingeca9bd9c2004-09-08 20:05:02 +0000543 entry = (void *)e->e.e_entry + exeoff;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000544
545 info->exe_base = minaddr;
546 info->exe_end = maxaddr;
547
548 info->init_eip = (addr_t)entry;
549
550 free(e);
551
552 return 0;
553}
554
555
556static int match_script(const char *hdr, Int len)
557{
558 return (len > 2) && memcmp(hdr, "#!", 2) == 0;
559}
560
nethercote31779c72004-07-30 21:50:15 +0000561static int load_script(char *hdr, int len, int fd, const char *name,
562 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000563{
564 char *interp;
565 char *const end = hdr+len;
566 char *cp;
567 char *arg = NULL;
568 int eol;
569
570 interp = hdr + 2;
571 while(interp < end && (*interp == ' ' || *interp == '\t'))
572 interp++;
573
574 if (*interp != '/')
575 return ENOEXEC; /* absolute path only for interpreter */
576
577 /* skip over interpreter name */
578 for(cp = interp; cp < end && *cp != ' ' && *cp != '\t' && *cp != '\n'; cp++)
579 ;
580
581 eol = (*cp == '\n');
582
583 *cp++ = '\0';
584
585 if (!eol && cp < end) {
586 /* skip space before arg */
587 while (cp < end && (*cp == '\t' || *cp == ' '))
588 cp++;
589
590 /* arg is from here to eol */
591 arg = cp;
592 while (cp < end && *cp != '\n')
593 cp++;
594 *cp = '\0';
595 }
596
nethercoted6a56872004-07-26 15:32:47 +0000597 info->interp_name = strdup(interp);
598 assert(NULL != info->interp_name);
nethercote71980f02004-01-24 18:18:54 +0000599 if (arg != NULL && *arg != '\0') {
nethercoted6a56872004-07-26 15:32:47 +0000600 info->interp_args = strdup(arg);
601 assert(NULL != info->interp_args);
nethercote71980f02004-01-24 18:18:54 +0000602 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000603
604 if (info->argv && info->argv[0] != NULL)
605 info->argv[0] = (char *)name;
606
607 if (0)
nethercoted6a56872004-07-26 15:32:47 +0000608 printf("#! script: interp_name=\"%s\" interp_args=\"%s\"\n",
609 info->interp_name, info->interp_args);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000610
611 return do_exec_inner(interp, info);
612}
613
fitzhardingefd7da3a2004-09-08 20:05:29 +0000614/*
615 Emulate the normal Unix permissions checking algorithm.
616
617 If owner matches, then use the owner permissions, else
618 if group matches, then use the group permissions, else
619 use other permissions.
620
621 Note that we can't deal with SUID/SGID, so we refuse to run them
622 (otherwise the executable may misbehave if it doesn't have the
623 permissions it thinks it does).
624*/
625static int check_perms(int fd)
626{
627 struct stat st;
628
629 if (fstat(fd, &st) == -1)
630 return errno;
631
632 if (st.st_mode & (S_ISUID | S_ISGID)) {
633 //fprintf(stderr, "Can't execute suid/sgid executable %s\n", exe);
634 return EACCES;
635 }
636
637 if (geteuid() == st.st_uid) {
638 if (!(st.st_mode & S_IXUSR))
639 return EACCES;
640 } else {
641 int grpmatch = 0;
642
643 if (getegid() == st.st_gid)
644 grpmatch = 1;
645 else {
646 gid_t groups[32];
647 int ngrp = getgroups(32, groups);
648 int i;
649
650 for(i = 0; i < ngrp; i++)
651 if (groups[i] == st.st_gid) {
652 grpmatch = 1;
653 break;
654 }
655 }
656
657 if (grpmatch) {
658 if (!(st.st_mode & S_IXGRP))
659 return EACCES;
660 } else if (!(st.st_mode & S_IXOTH))
661 return EACCES;
662 }
663
664 return 0;
665}
666
fitzhardinge7e343cd2003-12-16 02:14:00 +0000667static int do_exec_inner(const char *exe, struct exeinfo *info)
668{
669 int fd;
670 char buf[VKI_BYTES_PER_PAGE];
671 int bufsz;
672 int i;
673 int ret;
nethercote31779c72004-07-30 21:50:15 +0000674 static const struct {
675 int (*match)(const char *hdr, int len);
676 int (*load) ( char *hdr, int len, int fd2, const char *name,
677 struct exeinfo *);
678 } formats[] = {
679 { match_ELF, load_ELF },
680 { match_script, load_script },
681 };
fitzhardinge7e343cd2003-12-16 02:14:00 +0000682
683 fd = open(exe, O_RDONLY);
684 if (fd == -1) {
685 if (0)
686 fprintf(stderr, "Can't open executable %s: %s\n",
687 exe, strerror(errno));
688 return errno;
689 }
690
fitzhardingefd7da3a2004-09-08 20:05:29 +0000691 int err = check_perms(fd);
692 if (err != 0) {
693 close(fd);
694 return err;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000695 }
696
697 bufsz = pread(fd, buf, sizeof(buf), 0);
698 if (bufsz < 0) {
699 fprintf(stderr, "Can't read executable header: %s\n",
700 strerror(errno));
701 close(fd);
702 return errno;
703 }
704
705 ret = ENOEXEC;
706 for(i = 0; i < sizeof(formats)/sizeof(*formats); i++) {
707 if ((formats[i].match)(buf, bufsz)) {
708 ret = (formats[i].load)(buf, bufsz, fd, exe, info);
709 break;
710 }
711 }
712
713 close(fd);
714
715 return ret;
716}
717
nethercoteea147e72004-07-26 15:43:57 +0000718// See ume.h for an indication of which entries of 'info' are inputs, which
719// are outputs, and which are both.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000720int do_exec(const char *exe, struct exeinfo *info)
721{
nethercoted6a56872004-07-26 15:32:47 +0000722 info->interp_name = NULL;
723 info->interp_args = NULL;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000724
725 return do_exec_inner(exe, info);
726}
nethercotebb1c9912004-01-04 16:43:23 +0000727
728/*--------------------------------------------------------------------*/
729/*--- end ume.c ---*/
730/*--------------------------------------------------------------------*/