blob: 2b582ca10c8eaa761a0bfbda2476b21d524953dc [file] [log] [blame]
jseward2886b0e2004-01-04 03:46:11 +00001
nethercotebb1c9912004-01-04 16:43:23 +00002/*--------------------------------------------------------------------*/
nethercote107e1c02004-10-13 17:55:31 +00003/*--- User-mode execve(), and other stuff shared between stage1 ---*/
4/*--- and stage2. ume.c ---*/
nethercotebb1c9912004-01-04 16:43:23 +00005/*--------------------------------------------------------------------*/
6
jseward2886b0e2004-01-04 03:46:11 +00007/*
njnb9c427c2004-12-01 14:14:42 +00008 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
jseward2886b0e2004-01-04 03:46:11 +000010
njn53612422005-03-12 16:22:54 +000011 Copyright (C) 2000-2005 Julian Seward
jseward2886b0e2004-01-04 03:46:11 +000012 jseward@acm.org
13
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30*/
31
fitzhardinge7e343cd2003-12-16 02:14:00 +000032
33#define _GNU_SOURCE
34#define _FILE_OFFSET_BITS 64
35
njnf844cb62005-06-19 16:07:49 +000036// It seems that on SuSE 9.1 (x86) something in <fcntl.h> messes up stuff
37// acquired indirectly from vki-x86-linux.h. Therefore our headers must be
38// included ahead of the glibc ones. This fix is a kludge; the right
39// solution is to entirely remove the glibc dependency.
sewardj4b0c0712005-06-19 15:58:33 +000040#include "pub_core_basics.h"
41#include "pub_core_libcbase.h"
42#include "pub_core_machine.h"
43#include "ume.h"
44
fitzhardinge7e343cd2003-12-16 02:14:00 +000045#include <sys/mman.h>
46#include <fcntl.h>
47#include <errno.h>
fitzhardinge7e343cd2003-12-16 02:14:00 +000048#include <stdio.h>
49#include <string.h>
50#include <stdlib.h>
51#include <unistd.h>
fitzhardinge7e343cd2003-12-16 02:14:00 +000052#include <assert.h>
53
nethercote3f458152004-11-01 18:42:23 +000054#if ELFSZ == 64
55#define ESZ(x) Elf64_##x
56#elif ELFSZ == 32
57#define ESZ(x) Elf32_##x
58#else
59#error ELFSZ needs to ==32 or ==64
60#endif
61
nethercote1fe54502004-07-26 15:28:33 +000062struct elfinfo
63{
64 ESZ(Ehdr) e;
65 ESZ(Phdr) *p;
66 int fd;
67};
68
nethercote30d37842004-07-26 10:05:55 +000069static void check_mmap(void* res, void* base, int len)
nethercotebfed1c82004-07-17 12:57:44 +000070{
71 if ((void*)-1 == res) {
nethercote969ecf12004-10-13 17:29:01 +000072 fprintf(stderr, "valgrind: mmap(%p, %d) failed in UME.\n", base, len);
nethercotebfed1c82004-07-17 12:57:44 +000073 exit(1);
74 }
75}
76
nethercote31779c72004-07-30 21:50:15 +000077// 'extra' allows the caller to pass in extra args to 'fn', like free
78// variables to a closure.
79void foreach_map(int (*fn)(char *start, char *end,
fitzhardinge7e343cd2003-12-16 02:14:00 +000080 const char *perm, off_t offset,
nethercote31779c72004-07-30 21:50:15 +000081 int maj, int min, int ino, void* extra),
82 void* extra)
fitzhardinge7e343cd2003-12-16 02:14:00 +000083{
84 static char buf[10240];
85 char *bufptr = buf;
86 int ret, fd;
87
88 fd = open("/proc/self/maps", O_RDONLY);
89
90 if (fd == -1) {
91 perror("open /proc/self/maps");
92 return;
93 }
94
95 ret = read(fd, buf, sizeof(buf));
96
97 if (ret == -1) {
98 perror("read /proc/self/maps");
99 close(fd);
100 return;
101 }
102 close(fd);
103
104 if (ret == sizeof(buf)) {
105 fprintf(stderr, "buf too small\n");
106 return;
107 }
108
109 while(bufptr && bufptr < buf+ret) {
110 char perm[5];
njnc6168192004-11-29 13:54:10 +0000111 ULong offset;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000112 int maj, min;
113 int ino;
114 void *segstart, *segend;
115
nethercote545fe672004-11-01 16:52:43 +0000116 sscanf(bufptr, "%p-%p %s %llx %x:%x %d",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000117 &segstart, &segend, perm, &offset, &maj, &min, &ino);
118 bufptr = strchr(bufptr, '\n');
119 if (bufptr != NULL)
120 bufptr++; /* skip \n */
121
nethercote31779c72004-07-30 21:50:15 +0000122 if (!(*fn)(segstart, segend, perm, offset, maj, min, ino, extra))
fitzhardinge7e343cd2003-12-16 02:14:00 +0000123 break;
124 }
125}
126
nethercote31779c72004-07-30 21:50:15 +0000127/*------------------------------------------------------------*/
njnfcb7c3e2005-06-18 15:54:25 +0000128/*--- Stack switching ---*/
129/*------------------------------------------------------------*/
130
131// __attribute__((noreturn))
132// void jump_and_switch_stacks ( Addr stack, Addr dst );
133#if defined(VGA_x86)
134// 4(%esp) == stack
135// 8(%esp) == dst
136asm(
137".global jump_and_switch_stacks\n"
138"jump_and_switch_stacks:\n"
139" movl %esp, %esi\n" // remember old stack pointer
140" movl 4(%esi), %esp\n" // set stack
141" pushl 8(%esi)\n" // dst to stack
142" movl $0, %eax\n" // zero all GP regs
143" movl $0, %ebx\n"
144" movl $0, %ecx\n"
145" movl $0, %edx\n"
146" movl $0, %esi\n"
147" movl $0, %edi\n"
148" movl $0, %ebp\n"
149" ret\n" // jump to dst
150" ud2\n" // should never get here
151);
152#elif defined(VGA_amd64)
153// %rdi == stack
154// %rsi == dst
155asm(
156".global jump_and_switch_stacks\n"
157"jump_and_switch_stacks:\n"
158" movq %rdi, %rsp\n" // set stack
159" pushq %rsi\n" // dst to stack
160" movq $0, %rax\n" // zero all GP regs
161" movq $0, %rbx\n"
162" movq $0, %rcx\n"
163" movq $0, %rdx\n"
164" movq $0, %rsi\n"
165" movq $0, %rdi\n"
166" movq $0, %rbp\n"
167" movq $0, %r8\n"\
168" movq $0, %r9\n"\
169" movq $0, %r10\n"
170" movq $0, %r11\n"
171" movq $0, %r12\n"
172" movq $0, %r13\n"
173" movq $0, %r14\n"
174" movq $0, %r15\n"
175" ret\n" // jump to dst
176" ud2\n" // should never get here
177);
178#else
179# error Unknown architecture
180#endif
181
182/*------------------------------------------------------------*/
nethercote31779c72004-07-30 21:50:15 +0000183/*--- Finding auxv on the stack ---*/
184/*------------------------------------------------------------*/
fitzhardinge7e343cd2003-12-16 02:14:00 +0000185
nethercoteebf1d862004-11-01 18:22:05 +0000186struct ume_auxv *find_auxv(UWord* sp)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000187{
nethercoteebf1d862004-11-01 18:22:05 +0000188 sp++; // skip argc (Nb: is word-sized, not int-sized!)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000189
nethercoteebf1d862004-11-01 18:22:05 +0000190 while (*sp != 0) // skip argv
191 sp++;
192 sp++;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000193
nethercoteebf1d862004-11-01 18:22:05 +0000194 while (*sp != 0) // skip env
195 sp++;
196 sp++;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000197
nethercoteebf1d862004-11-01 18:22:05 +0000198 return (struct ume_auxv *)sp;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000199}
200
nethercote31779c72004-07-30 21:50:15 +0000201/*------------------------------------------------------------*/
202/*--- Loading ELF files ---*/
203/*------------------------------------------------------------*/
fitzhardinge7e343cd2003-12-16 02:14:00 +0000204
sewardj2c5ffbe2005-03-12 13:32:06 +0000205static
fitzhardinge7e343cd2003-12-16 02:14:00 +0000206struct elfinfo *readelf(int fd, const char *filename)
207{
208 struct elfinfo *e = malloc(sizeof(*e));
209 int phsz;
210
nethercote7c018f42004-07-17 16:40:50 +0000211 assert(e);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000212 e->fd = fd;
213
214 if (pread(fd, &e->e, sizeof(e->e), 0) != sizeof(e->e)) {
sewardj703eec52005-04-07 02:24:23 +0000215 fprintf(stderr, "valgrind: %s: can't read ELF header: %s\n",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000216 filename, strerror(errno));
217 return NULL;
218 }
219
220 if (memcmp(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) {
sewardj703eec52005-04-07 02:24:23 +0000221 fprintf(stderr, "valgrind: %s: bad ELF magic number\n", filename);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000222 return NULL;
223 }
njn35172bc2005-03-26 00:04:03 +0000224 if (e->e.e_ident[EI_CLASS] != VGA_ELF_CLASS) {
sewardj703eec52005-04-07 02:24:23 +0000225 fprintf(stderr,
226 "valgrind: wrong ELF executable class "
227 "(eg. 32-bit instead of 64-bit)\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000228 return NULL;
229 }
njn35172bc2005-03-26 00:04:03 +0000230 if (e->e.e_ident[EI_DATA] != VGA_ELF_ENDIANNESS) {
sewardj703eec52005-04-07 02:24:23 +0000231 fprintf(stderr, "valgrind: executable has wrong endian-ness\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000232 return NULL;
233 }
234 if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) {
sewardj703eec52005-04-07 02:24:23 +0000235 fprintf(stderr, "valgrind: this is not an executable\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000236 return NULL;
237 }
238
njn35172bc2005-03-26 00:04:03 +0000239 if (e->e.e_machine != VGA_ELF_MACHINE) {
sewardj703eec52005-04-07 02:24:23 +0000240 fprintf(stderr, "valgrind: executable is not for "
241 "this architecture\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000242 return NULL;
243 }
244
245 if (e->e.e_phentsize != sizeof(ESZ(Phdr))) {
sewardj703eec52005-04-07 02:24:23 +0000246 fprintf(stderr, "valgrind: sizeof ELF Phdr wrong\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000247 return NULL;
248 }
249
250 phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum;
251 e->p = malloc(phsz);
nethercote7c018f42004-07-17 16:40:50 +0000252 assert(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000253
254 if (pread(fd, e->p, phsz, e->e.e_phoff) != phsz) {
nethercote08eaff32004-07-22 12:41:12 +0000255 fprintf(stderr, "valgrind: can't read phdr: %s\n", strerror(errno));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000256 return NULL;
257 }
258
259 return e;
260}
261
fitzhardinge7e343cd2003-12-16 02:14:00 +0000262/* Map an ELF file. Returns the brk address. */
sewardj2c5ffbe2005-03-12 13:32:06 +0000263static
fitzhardingeb50068f2004-02-24 23:42:55 +0000264ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000265{
266 int i;
nethercotebfed1c82004-07-17 12:57:44 +0000267 void* res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000268 ESZ(Addr) elfbrk = 0;
269
270 for(i = 0; i < e->e.e_phnum; i++) {
271 ESZ(Phdr) *ph = &e->p[i];
272 ESZ(Addr) addr, brkaddr;
273 ESZ(Word) memsz;
274
275 if (ph->p_type != PT_LOAD)
276 continue;
277
nethercote6c3cf412004-10-26 13:32:11 +0000278 addr = ph->p_vaddr+base;
279 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000280 brkaddr = addr+memsz;
281
282 if (brkaddr > elfbrk)
283 elfbrk = brkaddr;
284 }
285
fitzhardinge7e343cd2003-12-16 02:14:00 +0000286 for(i = 0; i < e->e.e_phnum; i++) {
287 ESZ(Phdr) *ph = &e->p[i];
288 ESZ(Addr) addr, bss, brkaddr;
289 ESZ(Off) off;
290 ESZ(Word) filesz;
291 ESZ(Word) memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000292 unsigned prot = 0;
293
294 if (ph->p_type != PT_LOAD)
295 continue;
296
nethercote6c3cf412004-10-26 13:32:11 +0000297 if (ph->p_flags & PF_X) prot |= PROT_EXEC;
298 if (ph->p_flags & PF_W) prot |= PROT_WRITE;
299 if (ph->p_flags & PF_R) prot |= PROT_READ;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000300
nethercote6c3cf412004-10-26 13:32:11 +0000301 addr = ph->p_vaddr+base;
302 off = ph->p_offset;
303 filesz = ph->p_filesz;
304 bss = addr+filesz;
305 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000306 brkaddr = addr+memsz;
307
njnf7fbe6c2004-11-30 11:40:24 +0000308 // Tom says: In the following, do what the Linux kernel does and only
309 // map the pages that are required instead of rounding everything to
310 // the specified alignment (ph->p_align). (AMD64 doesn't work if you
311 // use ph->p_align -- part of stage2's memory gets trashed somehow.)
njn098da062005-03-26 16:22:43 +0000312 //
313 // The condition handles the case of a zero-length segment.
njn13bfd852005-06-02 03:52:53 +0000314 if (VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr) > 0) {
315 res = mmap((char *)VG_PGROUNDDN(addr),
316 VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr),
317 prot, MAP_FIXED|MAP_PRIVATE, e->fd, VG_PGROUNDDN(off));
318 check_mmap(res, (char*)VG_PGROUNDDN(addr),
319 VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr));
njn098da062005-03-26 16:22:43 +0000320 }
njnf7fbe6c2004-11-30 11:40:24 +0000321
322 // if memsz > filesz, fill the remainder with zeroed pages
fitzhardinge7e343cd2003-12-16 02:14:00 +0000323 if (memsz > filesz) {
324 UInt bytes;
325
njn13bfd852005-06-02 03:52:53 +0000326 bytes = VG_PGROUNDUP(brkaddr)-VG_PGROUNDUP(bss);
nethercotebfed1c82004-07-17 12:57:44 +0000327 if (bytes > 0) {
njn13bfd852005-06-02 03:52:53 +0000328 res = mmap((char *)VG_PGROUNDUP(bss), bytes,
nethercotebfed1c82004-07-17 12:57:44 +0000329 prot, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
njn13bfd852005-06-02 03:52:53 +0000330 check_mmap(res, (char*)VG_PGROUNDUP(bss), bytes);
nethercotebfed1c82004-07-17 12:57:44 +0000331 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000332
nethercote73b526f2004-10-31 18:48:21 +0000333 bytes = bss & (VKI_PAGE_SIZE - 1);
njn098da062005-03-26 16:22:43 +0000334
335 // The 'prot' condition allows for a read-only bss
336 if ((prot & PROT_WRITE) && (bytes > 0)) {
nethercote73b526f2004-10-31 18:48:21 +0000337 bytes = VKI_PAGE_SIZE - bytes;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000338 memset((char *)bss, 0, bytes);
339 }
340 }
341 }
342
343 return elfbrk;
344}
345
nethercote31779c72004-07-30 21:50:15 +0000346// Forward declaration.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000347static int do_exec_inner(const char *exe, struct exeinfo *info);
348
fitzhardinge7e343cd2003-12-16 02:14:00 +0000349static int match_ELF(const char *hdr, int len)
350{
351 ESZ(Ehdr) *e = (ESZ(Ehdr) *)hdr;
352 return (len > sizeof(*e)) && memcmp(&e->e_ident[0], ELFMAG, SELFMAG) == 0;
353}
354
nethercote31779c72004-07-30 21:50:15 +0000355static int load_ELF(char *hdr, int len, int fd, const char *name,
356 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000357{
358 struct elfinfo *e;
359 struct elfinfo *interp = NULL;
fitzhardingeca9bd9c2004-09-08 20:05:02 +0000360 ESZ(Addr) minaddr = ~0; /* lowest mapped address */
361 ESZ(Addr) maxaddr = 0; /* highest mapped address */
362 ESZ(Addr) interp_addr = 0; /* interpreter (ld.so) address */
363 ESZ(Word) interp_size = 0; /* interpreter size */
nethercote73b526f2004-10-31 18:48:21 +0000364 ESZ(Word) interp_align = VKI_PAGE_SIZE;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000365 int i;
366 void *entry;
nethercote7f390022004-10-25 17:18:24 +0000367 ESZ(Addr) ebase = 0;
368
369#ifdef HAVE_PIE
370 ebase = info->exe_base;
371#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000372
373 e = readelf(fd, name);
374
375 if (e == NULL)
376 return ENOEXEC;
377
378 info->phnum = e->e.e_phnum;
nethercote7f390022004-10-25 17:18:24 +0000379 info->entry = e->e.e_entry + ebase;
sewardjb5f6f512005-03-10 23:59:00 +0000380 info->phdr = 0;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000381
382 for(i = 0; i < e->e.e_phnum; i++) {
383 ESZ(Phdr) *ph = &e->p[i];
384
385 switch(ph->p_type) {
386 case PT_PHDR:
nethercote7f390022004-10-25 17:18:24 +0000387 info->phdr = ph->p_vaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000388 break;
389
390 case PT_LOAD:
391 if (ph->p_vaddr < minaddr)
392 minaddr = ph->p_vaddr;
393 if (ph->p_vaddr+ph->p_memsz > maxaddr)
394 maxaddr = ph->p_vaddr+ph->p_memsz;
395 break;
396
397 case PT_INTERP: {
398 char *buf = malloc(ph->p_filesz+1);
399 int j;
400 int intfd;
401 int baseaddr_set;
402
nethercote7c018f42004-07-17 16:40:50 +0000403 assert(buf);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000404 pread(fd, buf, ph->p_filesz, ph->p_offset);
405 buf[ph->p_filesz] = '\0';
406
407 intfd = open(buf, O_RDONLY);
408 if (intfd == -1) {
409 perror("open interp");
410 exit(1);
411 }
412
413 interp = readelf(intfd, buf);
414 if (interp == NULL) {
415 fprintf(stderr, "Can't read interpreter\n");
416 return 1;
417 }
418 free(buf);
419
420 baseaddr_set = 0;
421 for(j = 0; j < interp->e.e_phnum; j++) {
422 ESZ(Phdr) *iph = &interp->p[j];
423 ESZ(Addr) end;
424
425 if (iph->p_type != PT_LOAD)
426 continue;
427
428 if (!baseaddr_set) {
nethercote7f390022004-10-25 17:18:24 +0000429 interp_addr = iph->p_vaddr;
430 interp_align = iph->p_align;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000431 baseaddr_set = 1;
432 }
433
434 /* assumes that all segments in the interp are close */
435 end = (iph->p_vaddr - interp_addr) + iph->p_memsz;
436
437 if (end > interp_size)
438 interp_size = end;
439 }
440 break;
nethercoteb24cbc82004-09-03 23:25:33 +0000441
442 default:
443 // do nothing
444 break;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000445 }
446 }
447 }
448
sewardjb5f6f512005-03-10 23:59:00 +0000449 if (info->phdr == 0)
450 info->phdr = minaddr + e->e.e_phoff;
451
fitzhardinge7e343cd2003-12-16 02:14:00 +0000452 if (info->exe_base != info->exe_end) {
453 if (minaddr >= maxaddr ||
nethercote7f390022004-10-25 17:18:24 +0000454 (minaddr + ebase < info->exe_base ||
455 maxaddr + ebase > info->exe_end)) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000456 fprintf(stderr, "Executable range %p-%p is outside the\n"
457 "acceptable range %p-%p\n",
nethercote7f390022004-10-25 17:18:24 +0000458 (void *)minaddr + ebase, (void *)maxaddr + ebase,
459 (void *)info->exe_base, (void *)info->exe_end);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000460 return ENOMEM;
461 }
462 }
463
nethercote7f390022004-10-25 17:18:24 +0000464 info->brkbase = mapelf(e, ebase); /* map the executable */
fitzhardinge7e343cd2003-12-16 02:14:00 +0000465
fitzhardinge92360792003-12-24 10:11:11 +0000466 if (info->brkbase == 0)
467 return ENOMEM;
468
fitzhardinge7e343cd2003-12-16 02:14:00 +0000469 if (interp != NULL) {
470 /* reserve a chunk of address space for interpreter */
nethercotebfed1c82004-07-17 12:57:44 +0000471 void* res;
472 char* base = (char *)info->exe_base;
473 char* baseoff;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000474 int flags = MAP_PRIVATE|MAP_ANONYMOUS;
475
476 if (info->map_base != 0) {
njn13bfd852005-06-02 03:52:53 +0000477 base = (char *)VG_ROUNDUP(info->map_base, interp_align);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000478 flags |= MAP_FIXED;
479 }
480
nethercotebfed1c82004-07-17 12:57:44 +0000481 res = mmap(base, interp_size, PROT_NONE, flags, -1, 0);
482 check_mmap(res, base, interp_size);
483 base = res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000484
485 baseoff = base - interp_addr;
486
fitzhardingeb50068f2004-02-24 23:42:55 +0000487 mapelf(interp, (ESZ(Addr))baseoff);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000488
489 close(interp->fd);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000490
491 entry = baseoff + interp->e.e_entry;
492 info->interp_base = (ESZ(Addr))base;
thughes54d08592004-09-26 14:42:47 +0000493
sewardjb5f6f512005-03-10 23:59:00 +0000494 free(interp->p);
thughes54d08592004-09-26 14:42:47 +0000495 free(interp);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000496 } else
nethercote7f390022004-10-25 17:18:24 +0000497 entry = (void *)e->e.e_entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000498
nethercote7f390022004-10-25 17:18:24 +0000499 info->exe_base = minaddr + ebase;
500 info->exe_end = maxaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000501
nethercotea3c3cf22004-11-01 18:38:00 +0000502 info->init_eip = (Addr)entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000503
sewardjb5f6f512005-03-10 23:59:00 +0000504 free(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000505 free(e);
506
507 return 0;
508}
509
510
511static int match_script(const char *hdr, Int len)
512{
513 return (len > 2) && memcmp(hdr, "#!", 2) == 0;
514}
515
nethercote31779c72004-07-30 21:50:15 +0000516static int load_script(char *hdr, int len, int fd, const char *name,
517 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000518{
519 char *interp;
520 char *const end = hdr+len;
521 char *cp;
522 char *arg = NULL;
523 int eol;
524
525 interp = hdr + 2;
526 while(interp < end && (*interp == ' ' || *interp == '\t'))
527 interp++;
528
529 if (*interp != '/')
530 return ENOEXEC; /* absolute path only for interpreter */
531
532 /* skip over interpreter name */
533 for(cp = interp; cp < end && *cp != ' ' && *cp != '\t' && *cp != '\n'; cp++)
534 ;
535
536 eol = (*cp == '\n');
537
538 *cp++ = '\0';
539
540 if (!eol && cp < end) {
541 /* skip space before arg */
542 while (cp < end && (*cp == '\t' || *cp == ' '))
543 cp++;
544
545 /* arg is from here to eol */
546 arg = cp;
547 while (cp < end && *cp != '\n')
548 cp++;
549 *cp = '\0';
550 }
551
nethercoted6a56872004-07-26 15:32:47 +0000552 info->interp_name = strdup(interp);
553 assert(NULL != info->interp_name);
nethercote71980f02004-01-24 18:18:54 +0000554 if (arg != NULL && *arg != '\0') {
nethercoted6a56872004-07-26 15:32:47 +0000555 info->interp_args = strdup(arg);
556 assert(NULL != info->interp_args);
nethercote71980f02004-01-24 18:18:54 +0000557 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000558
559 if (info->argv && info->argv[0] != NULL)
560 info->argv[0] = (char *)name;
561
562 if (0)
nethercoted6a56872004-07-26 15:32:47 +0000563 printf("#! script: interp_name=\"%s\" interp_args=\"%s\"\n",
564 info->interp_name, info->interp_args);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000565
566 return do_exec_inner(interp, info);
567}
568
fitzhardingefd7da3a2004-09-08 20:05:29 +0000569/*
570 Emulate the normal Unix permissions checking algorithm.
571
572 If owner matches, then use the owner permissions, else
573 if group matches, then use the group permissions, else
574 use other permissions.
575
576 Note that we can't deal with SUID/SGID, so we refuse to run them
577 (otherwise the executable may misbehave if it doesn't have the
578 permissions it thinks it does).
579*/
580static int check_perms(int fd)
581{
582 struct stat st;
583
584 if (fstat(fd, &st) == -1)
585 return errno;
586
587 if (st.st_mode & (S_ISUID | S_ISGID)) {
588 //fprintf(stderr, "Can't execute suid/sgid executable %s\n", exe);
589 return EACCES;
590 }
591
592 if (geteuid() == st.st_uid) {
593 if (!(st.st_mode & S_IXUSR))
594 return EACCES;
595 } else {
596 int grpmatch = 0;
597
598 if (getegid() == st.st_gid)
599 grpmatch = 1;
600 else {
601 gid_t groups[32];
602 int ngrp = getgroups(32, groups);
603 int i;
604
605 for(i = 0; i < ngrp; i++)
606 if (groups[i] == st.st_gid) {
607 grpmatch = 1;
608 break;
609 }
610 }
611
612 if (grpmatch) {
613 if (!(st.st_mode & S_IXGRP))
614 return EACCES;
615 } else if (!(st.st_mode & S_IXOTH))
616 return EACCES;
617 }
618
619 return 0;
620}
621
fitzhardinge7e343cd2003-12-16 02:14:00 +0000622static int do_exec_inner(const char *exe, struct exeinfo *info)
623{
624 int fd;
fitzhardinged2e37112004-09-09 08:10:42 +0000625 int err;
nethercote73b526f2004-10-31 18:48:21 +0000626 char buf[VKI_PAGE_SIZE];
fitzhardinge7e343cd2003-12-16 02:14:00 +0000627 int bufsz;
628 int i;
629 int ret;
nethercote31779c72004-07-30 21:50:15 +0000630 static const struct {
631 int (*match)(const char *hdr, int len);
632 int (*load) ( char *hdr, int len, int fd2, const char *name,
633 struct exeinfo *);
634 } formats[] = {
635 { match_ELF, load_ELF },
636 { match_script, load_script },
637 };
fitzhardinge7e343cd2003-12-16 02:14:00 +0000638
639 fd = open(exe, O_RDONLY);
640 if (fd == -1) {
641 if (0)
642 fprintf(stderr, "Can't open executable %s: %s\n",
643 exe, strerror(errno));
644 return errno;
645 }
646
fitzhardinged2e37112004-09-09 08:10:42 +0000647 err = check_perms(fd);
fitzhardingefd7da3a2004-09-08 20:05:29 +0000648 if (err != 0) {
649 close(fd);
650 return err;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000651 }
652
653 bufsz = pread(fd, buf, sizeof(buf), 0);
654 if (bufsz < 0) {
655 fprintf(stderr, "Can't read executable header: %s\n",
656 strerror(errno));
657 close(fd);
658 return errno;
659 }
660
661 ret = ENOEXEC;
662 for(i = 0; i < sizeof(formats)/sizeof(*formats); i++) {
663 if ((formats[i].match)(buf, bufsz)) {
664 ret = (formats[i].load)(buf, bufsz, fd, exe, info);
665 break;
666 }
667 }
668
669 close(fd);
670
671 return ret;
672}
673
nethercoteea147e72004-07-26 15:43:57 +0000674// See ume.h for an indication of which entries of 'info' are inputs, which
675// are outputs, and which are both.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000676int do_exec(const char *exe, struct exeinfo *info)
677{
nethercoted6a56872004-07-26 15:32:47 +0000678 info->interp_name = NULL;
679 info->interp_args = NULL;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000680
681 return do_exec_inner(exe, info);
682}
nethercotebb1c9912004-01-04 16:43:23 +0000683
684/*--------------------------------------------------------------------*/
685/*--- end ume.c ---*/
686/*--------------------------------------------------------------------*/