blob: 735904d227bc9ed750dfd61bd31a303ba8b1e26f [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
nethercote1fe54502004-07-26 15:28:33 +000053struct elfinfo
54{
55 ESZ(Ehdr) e;
56 ESZ(Phdr) *p;
57 int fd;
58};
59
nethercote30d37842004-07-26 10:05:55 +000060static void check_mmap(void* res, void* base, int len)
nethercotebfed1c82004-07-17 12:57:44 +000061{
62 if ((void*)-1 == res) {
63 fprintf(stderr, "valgrind: mmap(%p, %d) failed during startup.\n"
64 "valgrind: is there a hard virtual memory limit set?\n",
65 base, len);
66 exit(1);
67 }
68}
69
nethercote31779c72004-07-30 21:50:15 +000070// 'extra' allows the caller to pass in extra args to 'fn', like free
71// variables to a closure.
72void foreach_map(int (*fn)(char *start, char *end,
fitzhardinge7e343cd2003-12-16 02:14:00 +000073 const char *perm, off_t offset,
nethercote31779c72004-07-30 21:50:15 +000074 int maj, int min, int ino, void* extra),
75 void* extra)
fitzhardinge7e343cd2003-12-16 02:14:00 +000076{
77 static char buf[10240];
78 char *bufptr = buf;
79 int ret, fd;
80
81 fd = open("/proc/self/maps", O_RDONLY);
82
83 if (fd == -1) {
84 perror("open /proc/self/maps");
85 return;
86 }
87
88 ret = read(fd, buf, sizeof(buf));
89
90 if (ret == -1) {
91 perror("read /proc/self/maps");
92 close(fd);
93 return;
94 }
95 close(fd);
96
97 if (ret == sizeof(buf)) {
98 fprintf(stderr, "buf too small\n");
99 return;
100 }
101
102 while(bufptr && bufptr < buf+ret) {
103 char perm[5];
104 off_t offset;
105 int maj, min;
106 int ino;
107 void *segstart, *segend;
108
109 sscanf(bufptr, "%p-%p %s %Lx %x:%x %d",
110 &segstart, &segend, perm, &offset, &maj, &min, &ino);
111 bufptr = strchr(bufptr, '\n');
112 if (bufptr != NULL)
113 bufptr++; /* skip \n */
114
nethercote31779c72004-07-30 21:50:15 +0000115 if (!(*fn)(segstart, segend, perm, offset, maj, min, ino, extra))
fitzhardinge7e343cd2003-12-16 02:14:00 +0000116 break;
117 }
118}
119
nethercote31779c72004-07-30 21:50:15 +0000120typedef struct {
121 char* fillgap_start;
122 char* fillgap_end;
123 int fillgap_padfile;
124} fillgap_extra;
thughes4ad52d02004-06-27 17:37:21 +0000125
nethercote31779c72004-07-30 21:50:15 +0000126static int fillgap(char *segstart, char *segend, const char *perm, off_t off,
127 int maj, int min, int ino, void* e)
128{
129 fillgap_extra* extra = e;
130
131 if (segstart >= extra->fillgap_end)
thughes4ad52d02004-06-27 17:37:21 +0000132 return 0;
133
nethercote31779c72004-07-30 21:50:15 +0000134 if (segstart > extra->fillgap_start) {
135 void* res = mmap(extra->fillgap_start, segstart - extra->fillgap_start,
136 PROT_NONE, MAP_FIXED|MAP_PRIVATE,
137 extra->fillgap_padfile, 0);
138 check_mmap(res, extra->fillgap_start, segstart - extra->fillgap_start);
nethercotebfed1c82004-07-17 12:57:44 +0000139 }
nethercote31779c72004-07-30 21:50:15 +0000140 extra->fillgap_start = segend;
thughes4ad52d02004-06-27 17:37:21 +0000141
142 return 1;
143}
144
nethercote31779c72004-07-30 21:50:15 +0000145// Choose a name for the padfile, open it.
146int as_openpadfile(void)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000147{
nethercote31779c72004-07-30 21:50:15 +0000148 char buf[256];
149 int padfile;
150 int seq = 1;
151 do {
152 snprintf(buf, 256, "/tmp/.pad.%d.%d", getpid(), seq++);
153 padfile = open(buf, O_RDWR|O_CREAT|O_EXCL, 0);
154 unlink(buf);
155 if (padfile == -1 && errno != EEXIST) {
156 fprintf(stderr, "valgrind: couldn't open padfile\n");
157 exit(44);
158 }
159 } while(padfile == -1);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000160
nethercote31779c72004-07-30 21:50:15 +0000161 return padfile;
162}
fitzhardinge7e343cd2003-12-16 02:14:00 +0000163
nethercote31779c72004-07-30 21:50:15 +0000164// Pad all the empty spaces in a range of address space to stop interlopers.
165void as_pad(void *start, void *end, int padfile)
166{
167 fillgap_extra extra;
168 extra.fillgap_start = start;
169 extra.fillgap_end = end;
170 extra.fillgap_padfile = padfile;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000171
nethercote31779c72004-07-30 21:50:15 +0000172 foreach_map(fillgap, &extra);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000173
nethercote31779c72004-07-30 21:50:15 +0000174 if (extra.fillgap_start < extra.fillgap_end) {
175 void* res = mmap(extra.fillgap_start,
176 extra.fillgap_end - extra.fillgap_start,
177 PROT_NONE, MAP_FIXED|MAP_PRIVATE, padfile, 0);
178 check_mmap(res, extra.fillgap_start,
179 extra.fillgap_end - extra.fillgap_start);
nethercotebfed1c82004-07-17 12:57:44 +0000180 }
thughes4ad52d02004-06-27 17:37:21 +0000181}
182
nethercote31779c72004-07-30 21:50:15 +0000183typedef struct {
184 char* killpad_start;
185 char* killpad_end;
186 struct stat* killpad_padstat;
187} killpad_extra;
thughes4ad52d02004-06-27 17:37:21 +0000188
nethercote31779c72004-07-30 21:50:15 +0000189static int killpad(char *segstart, char *segend, const char *perm, off_t off,
190 int maj, int min, int ino, void* ex)
nethercotebfed1c82004-07-17 12:57:44 +0000191{
nethercote31779c72004-07-30 21:50:15 +0000192 killpad_extra* extra = ex;
thughes4ad52d02004-06-27 17:37:21 +0000193 void *b, *e;
nethercotebfed1c82004-07-17 12:57:44 +0000194 int res;
thughes4ad52d02004-06-27 17:37:21 +0000195
nethercote31779c72004-07-30 21:50:15 +0000196 assert(NULL != extra->killpad_padstat);
197
198 if (extra->killpad_padstat->st_dev != makedev(maj, min) ||
199 extra->killpad_padstat->st_ino != ino)
thughes4ad52d02004-06-27 17:37:21 +0000200 return 1;
201
nethercote31779c72004-07-30 21:50:15 +0000202 if (segend <= extra->killpad_start || segstart >= extra->killpad_end)
thughes4ad52d02004-06-27 17:37:21 +0000203 return 1;
204
nethercote31779c72004-07-30 21:50:15 +0000205 if (segstart <= extra->killpad_start)
206 b = extra->killpad_start;
thughes4ad52d02004-06-27 17:37:21 +0000207 else
208 b = segstart;
209
nethercote31779c72004-07-30 21:50:15 +0000210 if (segend >= extra->killpad_end)
211 e = extra->killpad_end;
thughes4ad52d02004-06-27 17:37:21 +0000212 else
213 e = segend;
214
nethercotebfed1c82004-07-17 12:57:44 +0000215 res = munmap(b, (char *)e-(char *)b);
216 assert(0 == res);
thughes4ad52d02004-06-27 17:37:21 +0000217
218 return 1;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000219}
220
nethercote31779c72004-07-30 21:50:15 +0000221// Remove padding of 'padfile' from a range of address space.
222void as_unpad(void *start, void *end, int padfile)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000223{
nethercote31779c72004-07-30 21:50:15 +0000224 static struct stat padstat;
225 killpad_extra extra;
226 int res;
227
228 assert(padfile > 0);
thughes4ad52d02004-06-27 17:37:21 +0000229
nethercote31779c72004-07-30 21:50:15 +0000230 res = fstat(padfile, &padstat);
231 assert(0 == res);
232 extra.killpad_padstat = &padstat;
233 extra.killpad_start = start;
234 extra.killpad_end = end;
235 foreach_map(killpad, &extra);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000236}
237
nethercote31779c72004-07-30 21:50:15 +0000238void as_closepadfile(int padfile)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000239{
nethercote31779c72004-07-30 21:50:15 +0000240 int res = close(padfile);
241 assert(0 == res);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000242}
243
nethercote31779c72004-07-30 21:50:15 +0000244/*------------------------------------------------------------*/
245/*--- Finding auxv on the stack ---*/
246/*------------------------------------------------------------*/
fitzhardinge7e343cd2003-12-16 02:14:00 +0000247
248struct ume_auxv *find_auxv(int *esp)
249{
250 esp++; /* skip argc */
251
252 while(*esp != 0) /* skip argv */
253 esp++;
254 esp++;
255
256 while(*esp != 0) /* skip env */
257 esp++;
258 esp++;
259
260 return (struct ume_auxv *)esp;
261}
262
nethercote31779c72004-07-30 21:50:15 +0000263/*------------------------------------------------------------*/
264/*--- Loading ELF files ---*/
265/*------------------------------------------------------------*/
fitzhardinge7e343cd2003-12-16 02:14:00 +0000266
267struct elfinfo *readelf(int fd, const char *filename)
268{
269 struct elfinfo *e = malloc(sizeof(*e));
270 int phsz;
271
nethercote7c018f42004-07-17 16:40:50 +0000272 assert(e);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000273 e->fd = fd;
274
275 if (pread(fd, &e->e, sizeof(e->e), 0) != sizeof(e->e)) {
nethercote08eaff32004-07-22 12:41:12 +0000276 fprintf(stderr, "valgrind: %s: can't read elf header: %s\n",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000277 filename, strerror(errno));
278 return NULL;
279 }
280
281 if (memcmp(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) {
nethercote08eaff32004-07-22 12:41:12 +0000282 fprintf(stderr, "valgrind: %s: bad ELF magic\n", filename);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000283 return NULL;
284 }
285 if (e->e.e_ident[EI_CLASS] != ELFCLASS32) {
nethercote08eaff32004-07-22 12:41:12 +0000286 fprintf(stderr, "valgrind: Can only handle 32-bit executables\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000287 return NULL;
288 }
289 if (e->e.e_ident[EI_DATA] != ELFDATA2LSB) {
nethercote08eaff32004-07-22 12:41:12 +0000290 fprintf(stderr, "valgrind: Expecting little-endian\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000291 return NULL;
292 }
293 if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) {
nethercote08eaff32004-07-22 12:41:12 +0000294 fprintf(stderr, "valgrind: need executable\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000295 return NULL;
296 }
297
298 if (e->e.e_machine != EM_386) {
nethercote08eaff32004-07-22 12:41:12 +0000299 fprintf(stderr, "valgrind: need x86\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000300 return NULL;
301 }
302
303 if (e->e.e_phentsize != sizeof(ESZ(Phdr))) {
nethercote08eaff32004-07-22 12:41:12 +0000304 fprintf(stderr, "valgrind: sizeof Phdr wrong\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000305 return NULL;
306 }
307
308 phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum;
309 e->p = malloc(phsz);
nethercote7c018f42004-07-17 16:40:50 +0000310 assert(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000311
312 if (pread(fd, e->p, phsz, e->e.e_phoff) != phsz) {
nethercote08eaff32004-07-22 12:41:12 +0000313 fprintf(stderr, "valgrind: can't read phdr: %s\n", strerror(errno));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000314 return NULL;
315 }
316
317 return e;
318}
319
fitzhardinge7e343cd2003-12-16 02:14:00 +0000320/* Map an ELF file. Returns the brk address. */
fitzhardingeb50068f2004-02-24 23:42:55 +0000321ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000322{
323 int i;
nethercotebfed1c82004-07-17 12:57:44 +0000324 void* res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000325 ESZ(Addr) elfbrk = 0;
326
327 for(i = 0; i < e->e.e_phnum; i++) {
328 ESZ(Phdr) *ph = &e->p[i];
329 ESZ(Addr) addr, brkaddr;
330 ESZ(Word) memsz;
331
332 if (ph->p_type != PT_LOAD)
333 continue;
334
335 addr = ph->p_vaddr+base;
336 memsz = ph->p_memsz;
337 brkaddr = addr+memsz;
338
339 if (brkaddr > elfbrk)
340 elfbrk = brkaddr;
341 }
342
fitzhardinge7e343cd2003-12-16 02:14:00 +0000343 for(i = 0; i < e->e.e_phnum; i++) {
344 ESZ(Phdr) *ph = &e->p[i];
345 ESZ(Addr) addr, bss, brkaddr;
346 ESZ(Off) off;
347 ESZ(Word) filesz;
348 ESZ(Word) memsz;
349 ESZ(Word) align;
350 unsigned prot = 0;
351
352 if (ph->p_type != PT_LOAD)
353 continue;
354
355 if (ph->p_flags & PF_X)
356 prot |= PROT_EXEC;
357 if (ph->p_flags & PF_W)
358 prot |= PROT_WRITE;
359 if (ph->p_flags & PF_R)
360 prot |= PROT_READ;
361
362 align = ph->p_align;
363
364 addr = ph->p_vaddr+base;
365 off = ph->p_offset;
366 filesz = ph->p_filesz;
367 bss = addr+filesz;
368 memsz = ph->p_memsz;
369 brkaddr = addr+memsz;
370
nethercotebfed1c82004-07-17 12:57:44 +0000371 res = mmap((char *)ROUNDDN(addr, align),
372 ROUNDUP(bss, align)-ROUNDDN(addr, align),
373 prot, MAP_FIXED|MAP_PRIVATE, e->fd, ROUNDDN(off, align));
374 check_mmap(res, (char*)ROUNDDN(addr,align),
375 ROUNDUP(bss, align)-ROUNDDN(addr, align));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000376
377 /* if memsz > filesz, then we need to fill the remainder with zeroed pages */
378 if (memsz > filesz) {
379 UInt bytes;
380
381 bytes = ROUNDUP(brkaddr, align)-ROUNDUP(bss, align);
nethercotebfed1c82004-07-17 12:57:44 +0000382 if (bytes > 0) {
383 res = mmap((char *)ROUNDUP(bss, align), bytes,
384 prot, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
385 check_mmap(res, (char*)ROUNDUP(bss,align), bytes);
386 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000387
388 bytes = bss & (VKI_BYTES_PER_PAGE - 1);
389 if (bytes > 0) {
390 bytes = VKI_BYTES_PER_PAGE - bytes;
391 memset((char *)bss, 0, bytes);
392 }
393 }
394 }
395
396 return elfbrk;
397}
398
nethercote31779c72004-07-30 21:50:15 +0000399// Forward declaration.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000400static int do_exec_inner(const char *exe, struct exeinfo *info);
401
fitzhardinge7e343cd2003-12-16 02:14:00 +0000402static int match_ELF(const char *hdr, int len)
403{
404 ESZ(Ehdr) *e = (ESZ(Ehdr) *)hdr;
405 return (len > sizeof(*e)) && memcmp(&e->e_ident[0], ELFMAG, SELFMAG) == 0;
406}
407
nethercote31779c72004-07-30 21:50:15 +0000408static int load_ELF(char *hdr, int len, int fd, const char *name,
409 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000410{
411 struct elfinfo *e;
412 struct elfinfo *interp = NULL;
413 ESZ(Addr) minaddr = ~0;
414 ESZ(Addr) maxaddr = 0;
415 ESZ(Addr) interp_addr = 0;
416 ESZ(Word) interp_size = 0;
417 int i;
418 void *entry;
419
420 e = readelf(fd, name);
421
422 if (e == NULL)
423 return ENOEXEC;
424
425 info->phnum = e->e.e_phnum;
426 info->entry = e->e.e_entry;
427
428 for(i = 0; i < e->e.e_phnum; i++) {
429 ESZ(Phdr) *ph = &e->p[i];
430
431 switch(ph->p_type) {
432 case PT_PHDR:
433 info->phdr = ph->p_vaddr;
434 break;
435
436 case PT_LOAD:
437 if (ph->p_vaddr < minaddr)
438 minaddr = ph->p_vaddr;
439 if (ph->p_vaddr+ph->p_memsz > maxaddr)
440 maxaddr = ph->p_vaddr+ph->p_memsz;
441 break;
442
443 case PT_INTERP: {
444 char *buf = malloc(ph->p_filesz+1);
445 int j;
446 int intfd;
447 int baseaddr_set;
448
nethercote7c018f42004-07-17 16:40:50 +0000449 assert(buf);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000450 pread(fd, buf, ph->p_filesz, ph->p_offset);
451 buf[ph->p_filesz] = '\0';
452
453 intfd = open(buf, O_RDONLY);
454 if (intfd == -1) {
455 perror("open interp");
456 exit(1);
457 }
458
459 interp = readelf(intfd, buf);
460 if (interp == NULL) {
461 fprintf(stderr, "Can't read interpreter\n");
462 return 1;
463 }
464 free(buf);
465
466 baseaddr_set = 0;
467 for(j = 0; j < interp->e.e_phnum; j++) {
468 ESZ(Phdr) *iph = &interp->p[j];
469 ESZ(Addr) end;
470
471 if (iph->p_type != PT_LOAD)
472 continue;
473
474 if (!baseaddr_set) {
475 interp_addr = iph->p_vaddr;
476 baseaddr_set = 1;
477 }
478
479 /* assumes that all segments in the interp are close */
480 end = (iph->p_vaddr - interp_addr) + iph->p_memsz;
481
482 if (end > interp_size)
483 interp_size = end;
484 }
485 break;
486 }
487 }
488 }
489
490 if (info->exe_base != info->exe_end) {
491 if (minaddr >= maxaddr ||
492 (minaddr < info->exe_base ||
493 maxaddr > info->exe_end)) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000494 fprintf(stderr, "Executable range %p-%p is outside the\n"
495 "acceptable range %p-%p\n",
496 (void *)minaddr, (void *)maxaddr,
fitzhardinge7e343cd2003-12-16 02:14:00 +0000497 (void *)info->exe_base, (void *)info->exe_end);
498 return ENOMEM;
499 }
500 }
501
fitzhardingeb50068f2004-02-24 23:42:55 +0000502 info->brkbase = mapelf(e, 0); /* map the executable */
fitzhardinge7e343cd2003-12-16 02:14:00 +0000503
fitzhardinge92360792003-12-24 10:11:11 +0000504 if (info->brkbase == 0)
505 return ENOMEM;
506
fitzhardinge7e343cd2003-12-16 02:14:00 +0000507 if (interp != NULL) {
508 /* reserve a chunk of address space for interpreter */
nethercotebfed1c82004-07-17 12:57:44 +0000509 void* res;
510 char* base = (char *)info->exe_base;
511 char* baseoff;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000512 int flags = MAP_PRIVATE|MAP_ANONYMOUS;
513
514 if (info->map_base != 0) {
515 base = (char *)info->map_base;
516 flags |= MAP_FIXED;
517 }
518
nethercotebfed1c82004-07-17 12:57:44 +0000519 res = mmap(base, interp_size, PROT_NONE, flags, -1, 0);
520 check_mmap(res, base, interp_size);
521 base = res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000522
523 baseoff = base - interp_addr;
524
fitzhardingeb50068f2004-02-24 23:42:55 +0000525 mapelf(interp, (ESZ(Addr))baseoff);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000526
527 close(interp->fd);
528 free(interp);
529
530 entry = baseoff + interp->e.e_entry;
531 info->interp_base = (ESZ(Addr))base;
532 } else
533 entry = (void *)e->e.e_entry;
534
535 info->exe_base = minaddr;
536 info->exe_end = maxaddr;
537
538 info->init_eip = (addr_t)entry;
539
540 free(e);
541
542 return 0;
543}
544
545
546static int match_script(const char *hdr, Int len)
547{
548 return (len > 2) && memcmp(hdr, "#!", 2) == 0;
549}
550
nethercote31779c72004-07-30 21:50:15 +0000551static int load_script(char *hdr, int len, int fd, const char *name,
552 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000553{
554 char *interp;
555 char *const end = hdr+len;
556 char *cp;
557 char *arg = NULL;
558 int eol;
559
560 interp = hdr + 2;
561 while(interp < end && (*interp == ' ' || *interp == '\t'))
562 interp++;
563
564 if (*interp != '/')
565 return ENOEXEC; /* absolute path only for interpreter */
566
567 /* skip over interpreter name */
568 for(cp = interp; cp < end && *cp != ' ' && *cp != '\t' && *cp != '\n'; cp++)
569 ;
570
571 eol = (*cp == '\n');
572
573 *cp++ = '\0';
574
575 if (!eol && cp < end) {
576 /* skip space before arg */
577 while (cp < end && (*cp == '\t' || *cp == ' '))
578 cp++;
579
580 /* arg is from here to eol */
581 arg = cp;
582 while (cp < end && *cp != '\n')
583 cp++;
584 *cp = '\0';
585 }
586
nethercoted6a56872004-07-26 15:32:47 +0000587 info->interp_name = strdup(interp);
588 assert(NULL != info->interp_name);
nethercote71980f02004-01-24 18:18:54 +0000589 if (arg != NULL && *arg != '\0') {
nethercoted6a56872004-07-26 15:32:47 +0000590 info->interp_args = strdup(arg);
591 assert(NULL != info->interp_args);
nethercote71980f02004-01-24 18:18:54 +0000592 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000593
594 if (info->argv && info->argv[0] != NULL)
595 info->argv[0] = (char *)name;
596
597 if (0)
nethercoted6a56872004-07-26 15:32:47 +0000598 printf("#! script: interp_name=\"%s\" interp_args=\"%s\"\n",
599 info->interp_name, info->interp_args);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000600
601 return do_exec_inner(interp, info);
602}
603
fitzhardinge7e343cd2003-12-16 02:14:00 +0000604static int do_exec_inner(const char *exe, struct exeinfo *info)
605{
606 int fd;
607 char buf[VKI_BYTES_PER_PAGE];
608 int bufsz;
609 int i;
610 int ret;
611 struct stat st;
nethercote31779c72004-07-30 21:50:15 +0000612 static const struct {
613 int (*match)(const char *hdr, int len);
614 int (*load) ( char *hdr, int len, int fd2, const char *name,
615 struct exeinfo *);
616 } formats[] = {
617 { match_ELF, load_ELF },
618 { match_script, load_script },
619 };
fitzhardinge7e343cd2003-12-16 02:14:00 +0000620
621 fd = open(exe, O_RDONLY);
622 if (fd == -1) {
623 if (0)
624 fprintf(stderr, "Can't open executable %s: %s\n",
625 exe, strerror(errno));
626 return errno;
627 }
628
629 if (fstat(fd, &st) == -1)
630 return errno;
631 else {
632 uid_t uid = geteuid();
633 gid_t gid = getegid();
634 gid_t groups[32];
635 int ngrp = getgroups(32, groups);
636
fitzhardingea49f9b52003-12-16 22:26:45 +0000637 if (st.st_mode & (S_ISUID | S_ISGID)) {
638 fprintf(stderr, "Can't execute suid/sgid executable %s\n", exe);
639 return EACCES;
640 }
641
fitzhardinge6d5dafa2004-01-04 23:10:07 +0000642 if (uid == st.st_uid) {
643 if (!(st.st_mode & S_IXUSR))
fitzhardinge7e343cd2003-12-16 02:14:00 +0000644 return EACCES;
fitzhardinge6d5dafa2004-01-04 23:10:07 +0000645 } else {
646 int grpmatch = 0;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000647
fitzhardinge6d5dafa2004-01-04 23:10:07 +0000648 if (gid == st.st_gid)
649 grpmatch = 1;
650 else
651 for(i = 0; i < ngrp; i++)
652 if (groups[i] == st.st_gid) {
653 grpmatch = 1;
654 break;
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 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000663 }
664
665 bufsz = pread(fd, buf, sizeof(buf), 0);
666 if (bufsz < 0) {
667 fprintf(stderr, "Can't read executable header: %s\n",
668 strerror(errno));
669 close(fd);
670 return errno;
671 }
672
673 ret = ENOEXEC;
674 for(i = 0; i < sizeof(formats)/sizeof(*formats); i++) {
675 if ((formats[i].match)(buf, bufsz)) {
676 ret = (formats[i].load)(buf, bufsz, fd, exe, info);
677 break;
678 }
679 }
680
681 close(fd);
682
683 return ret;
684}
685
nethercoteea147e72004-07-26 15:43:57 +0000686// See ume.h for an indication of which entries of 'info' are inputs, which
687// are outputs, and which are both.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000688int do_exec(const char *exe, struct exeinfo *info)
689{
nethercoted6a56872004-07-26 15:32:47 +0000690 info->interp_name = NULL;
691 info->interp_args = NULL;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000692
693 return do_exec_inner(exe, info);
694}
nethercotebb1c9912004-01-04 16:43:23 +0000695
696/*--------------------------------------------------------------------*/
697/*--- end ume.c ---*/
698/*--------------------------------------------------------------------*/