blob: c27a0037886f444bf9b9471e1f2509bea70a3585 [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 ---*/
njn08a2e172005-06-21 22:47:54 +00004/*--- and stage2. m_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"
njn08a2e172005-06-21 22:47:54 +000043#include "pub_core_ume.h"
sewardj4b0c0712005-06-19 15:58:33 +000044
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
sewardjfbd78b22005-06-19 16:14:06 +000054#if VG_WORDSIZE == 8
nethercote3f458152004-11-01 18:42:23 +000055#define ESZ(x) Elf64_##x
sewardjfbd78b22005-06-19 16:14:06 +000056#elif VG_WORDSIZE == 4
nethercote3f458152004-11-01 18:42:23 +000057#define ESZ(x) Elf32_##x
58#else
sewardjfbd78b22005-06-19 16:14:06 +000059#error VG_WORDSIZE needs to ==4 or ==8
nethercote3f458152004-11-01 18:42:23 +000060#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.
njn62ff0f22005-06-21 23:03:36 +000079void VG_(foreach_map)(int (*fn)(char *start, char *end,
80 const char *perm, off_t offset,
81 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))
njn62ff0f22005-06-21 23:03:36 +0000132// void VG_(jump_and_switch_stacks) ( Addr stack, Addr dst );
njnfcb7c3e2005-06-18 15:54:25 +0000133#if defined(VGA_x86)
134// 4(%esp) == stack
135// 8(%esp) == dst
136asm(
njn62ff0f22005-06-21 23:03:36 +0000137".global vgPlain_jump_and_switch_stacks\n"
138"vgPlain_jump_and_switch_stacks:\n"
njnfcb7c3e2005-06-18 15:54:25 +0000139" 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(
njn62ff0f22005-06-21 23:03:36 +0000156".global vgPlain_jump_and_switch_stacks\n"
157"vgPlain_jump_and_switch_stacks:\n"
njnfcb7c3e2005-06-18 15:54:25 +0000158" 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);
cerion85665ca2005-06-20 15:51:07 +0000178
179#elif defined(VGA_ppc32)
180/* Jump to 'dst', but first set the stack pointer to 'stack'. Also,
181 clear all the integer registers before entering 'dst'. It's
182 important that the stack pointer is set to exactly 'stack' and not
183 (eg) stack - apparently_harmless_looking_small_offset. Basically
184 because the code at 'dst' might be wanting to scan the area above
185 'stack' (viz, the auxv array), and putting spurious words on the
186 stack confuses it.
187*/
188// %r3 == stack
189// %r4 == dst
190asm(
njn62ff0f22005-06-21 23:03:36 +0000191".global vgPlain_jump_and_switch_stacks\n"
192"vgPlain_jump_and_switch_stacks:\n"
cerion85665ca2005-06-20 15:51:07 +0000193" mtctr %r4\n\t" // dst to %ctr
194" mr %r1,%r3\n\t" // stack to %sp
195" li 0,0\n\t" // zero all GP regs
196" li 3,0\n\t"
197" li 4,0\n\t"
198" li 5,0\n\t"
199" li 6,0\n\t"
200" li 7,0\n\t"
201" li 8,0\n\t"
202" li 9,0\n\t"
203" li 10,0\n\t"
204" li 11,0\n\t"
205" li 12,0\n\t"
206" li 13,0\n\t" // CAB: This right? r13 = small data area ptr
207" li 14,0\n\t"
208" li 15,0\n\t"
209" li 16,0\n\t"
210" li 17,0\n\t"
211" li 18,0\n\t"
212" li 19,0\n\t"
213" li 20,0\n\t"
214" li 21,0\n\t"
215" li 22,0\n\t"
216" li 23,0\n\t"
217" li 24,0\n\t"
218" li 25,0\n\t"
219" li 26,0\n\t"
220" li 27,0\n\t"
221" li 28,0\n\t"
222" li 29,0\n\t"
223" li 30,0\n\t"
224" li 31,0\n\t"
225" mtxer 0\n\t"
226" mtcr 0\n\t"
227" mtlr %r0\n\t"
228" bctr\n\t" // jump to dst
229" trap\n" // should never get here
230);
231
njnfcb7c3e2005-06-18 15:54:25 +0000232#else
233# error Unknown architecture
234#endif
235
236/*------------------------------------------------------------*/
nethercote31779c72004-07-30 21:50:15 +0000237/*--- Finding auxv on the stack ---*/
238/*------------------------------------------------------------*/
fitzhardinge7e343cd2003-12-16 02:14:00 +0000239
njn62ff0f22005-06-21 23:03:36 +0000240struct ume_auxv *VG_(find_auxv)(UWord* sp)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000241{
nethercoteebf1d862004-11-01 18:22:05 +0000242 sp++; // skip argc (Nb: is word-sized, not int-sized!)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000243
nethercoteebf1d862004-11-01 18:22:05 +0000244 while (*sp != 0) // skip argv
245 sp++;
246 sp++;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000247
nethercoteebf1d862004-11-01 18:22:05 +0000248 while (*sp != 0) // skip env
249 sp++;
250 sp++;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000251
cerion85665ca2005-06-20 15:51:07 +0000252#if defined(VGA_ppc32)
253# if defined AT_IGNOREPPC
254 while (*sp == AT_IGNOREPPC) // skip AT_IGNOREPPC entries
255 sp += 2;
256# endif
257#endif
258
nethercoteebf1d862004-11-01 18:22:05 +0000259 return (struct ume_auxv *)sp;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000260}
261
nethercote31779c72004-07-30 21:50:15 +0000262/*------------------------------------------------------------*/
263/*--- Loading ELF files ---*/
264/*------------------------------------------------------------*/
fitzhardinge7e343cd2003-12-16 02:14:00 +0000265
sewardj2c5ffbe2005-03-12 13:32:06 +0000266static
fitzhardinge7e343cd2003-12-16 02:14:00 +0000267struct 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)) {
sewardj703eec52005-04-07 02:24:23 +0000276 fprintf(stderr, "valgrind: %s: can't read ELF header: %s\n",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000277 filename, strerror(errno));
njn12f266f2005-06-28 19:20:46 +0000278 goto bad;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000279 }
280
281 if (memcmp(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) {
sewardj703eec52005-04-07 02:24:23 +0000282 fprintf(stderr, "valgrind: %s: bad ELF magic number\n", filename);
njn12f266f2005-06-28 19:20:46 +0000283 goto bad;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000284 }
njnaf839f52005-06-23 03:27:57 +0000285 if (e->e.e_ident[EI_CLASS] != VG_ELF_CLASS) {
sewardj703eec52005-04-07 02:24:23 +0000286 fprintf(stderr,
287 "valgrind: wrong ELF executable class "
288 "(eg. 32-bit instead of 64-bit)\n");
njn12f266f2005-06-28 19:20:46 +0000289 goto bad;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000290 }
sewardj6e340c72005-07-10 00:53:42 +0000291 if (e->e.e_ident[EI_DATA] != VG_ELF_DATA2XXX) {
sewardj703eec52005-04-07 02:24:23 +0000292 fprintf(stderr, "valgrind: executable has wrong endian-ness\n");
njn12f266f2005-06-28 19:20:46 +0000293 goto bad;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000294 }
295 if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) {
sewardj703eec52005-04-07 02:24:23 +0000296 fprintf(stderr, "valgrind: this is not an executable\n");
njn12f266f2005-06-28 19:20:46 +0000297 goto bad;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000298 }
299
njnaf839f52005-06-23 03:27:57 +0000300 if (e->e.e_machine != VG_ELF_MACHINE) {
sewardj703eec52005-04-07 02:24:23 +0000301 fprintf(stderr, "valgrind: executable is not for "
302 "this architecture\n");
njn12f266f2005-06-28 19:20:46 +0000303 goto bad;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000304 }
305
306 if (e->e.e_phentsize != sizeof(ESZ(Phdr))) {
sewardj703eec52005-04-07 02:24:23 +0000307 fprintf(stderr, "valgrind: sizeof ELF Phdr wrong\n");
njn12f266f2005-06-28 19:20:46 +0000308 goto bad;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000309 }
310
311 phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum;
312 e->p = malloc(phsz);
nethercote7c018f42004-07-17 16:40:50 +0000313 assert(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000314
315 if (pread(fd, e->p, phsz, e->e.e_phoff) != phsz) {
nethercote08eaff32004-07-22 12:41:12 +0000316 fprintf(stderr, "valgrind: can't read phdr: %s\n", strerror(errno));
njn12f266f2005-06-28 19:20:46 +0000317 free(e->p);
318 goto bad;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000319 }
320
321 return e;
njn12f266f2005-06-28 19:20:46 +0000322
323 bad:
324 free(e);
325 return NULL;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000326}
327
fitzhardinge7e343cd2003-12-16 02:14:00 +0000328/* Map an ELF file. Returns the brk address. */
sewardj2c5ffbe2005-03-12 13:32:06 +0000329static
fitzhardingeb50068f2004-02-24 23:42:55 +0000330ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000331{
332 int i;
nethercotebfed1c82004-07-17 12:57:44 +0000333 void* res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000334 ESZ(Addr) elfbrk = 0;
335
336 for(i = 0; i < e->e.e_phnum; i++) {
337 ESZ(Phdr) *ph = &e->p[i];
338 ESZ(Addr) addr, brkaddr;
339 ESZ(Word) memsz;
340
341 if (ph->p_type != PT_LOAD)
342 continue;
343
nethercote6c3cf412004-10-26 13:32:11 +0000344 addr = ph->p_vaddr+base;
345 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000346 brkaddr = addr+memsz;
347
348 if (brkaddr > elfbrk)
349 elfbrk = brkaddr;
350 }
351
fitzhardinge7e343cd2003-12-16 02:14:00 +0000352 for(i = 0; i < e->e.e_phnum; i++) {
353 ESZ(Phdr) *ph = &e->p[i];
354 ESZ(Addr) addr, bss, brkaddr;
355 ESZ(Off) off;
356 ESZ(Word) filesz;
357 ESZ(Word) memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000358 unsigned prot = 0;
359
360 if (ph->p_type != PT_LOAD)
361 continue;
362
nethercote6c3cf412004-10-26 13:32:11 +0000363 if (ph->p_flags & PF_X) prot |= PROT_EXEC;
364 if (ph->p_flags & PF_W) prot |= PROT_WRITE;
365 if (ph->p_flags & PF_R) prot |= PROT_READ;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000366
nethercote6c3cf412004-10-26 13:32:11 +0000367 addr = ph->p_vaddr+base;
368 off = ph->p_offset;
369 filesz = ph->p_filesz;
370 bss = addr+filesz;
371 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000372 brkaddr = addr+memsz;
373
njnf7fbe6c2004-11-30 11:40:24 +0000374 // Tom says: In the following, do what the Linux kernel does and only
375 // map the pages that are required instead of rounding everything to
376 // the specified alignment (ph->p_align). (AMD64 doesn't work if you
377 // use ph->p_align -- part of stage2's memory gets trashed somehow.)
njn098da062005-03-26 16:22:43 +0000378 //
379 // The condition handles the case of a zero-length segment.
njn13bfd852005-06-02 03:52:53 +0000380 if (VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr) > 0) {
381 res = mmap((char *)VG_PGROUNDDN(addr),
382 VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr),
383 prot, MAP_FIXED|MAP_PRIVATE, e->fd, VG_PGROUNDDN(off));
384 check_mmap(res, (char*)VG_PGROUNDDN(addr),
385 VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr));
njn098da062005-03-26 16:22:43 +0000386 }
njnf7fbe6c2004-11-30 11:40:24 +0000387
388 // if memsz > filesz, fill the remainder with zeroed pages
fitzhardinge7e343cd2003-12-16 02:14:00 +0000389 if (memsz > filesz) {
390 UInt bytes;
391
njn13bfd852005-06-02 03:52:53 +0000392 bytes = VG_PGROUNDUP(brkaddr)-VG_PGROUNDUP(bss);
nethercotebfed1c82004-07-17 12:57:44 +0000393 if (bytes > 0) {
njn13bfd852005-06-02 03:52:53 +0000394 res = mmap((char *)VG_PGROUNDUP(bss), bytes,
nethercotebfed1c82004-07-17 12:57:44 +0000395 prot, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
njn13bfd852005-06-02 03:52:53 +0000396 check_mmap(res, (char*)VG_PGROUNDUP(bss), bytes);
nethercotebfed1c82004-07-17 12:57:44 +0000397 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000398
nethercote73b526f2004-10-31 18:48:21 +0000399 bytes = bss & (VKI_PAGE_SIZE - 1);
njn098da062005-03-26 16:22:43 +0000400
401 // The 'prot' condition allows for a read-only bss
402 if ((prot & PROT_WRITE) && (bytes > 0)) {
nethercote73b526f2004-10-31 18:48:21 +0000403 bytes = VKI_PAGE_SIZE - bytes;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000404 memset((char *)bss, 0, bytes);
405 }
406 }
407 }
408
409 return elfbrk;
410}
411
nethercote31779c72004-07-30 21:50:15 +0000412// Forward declaration.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000413static int do_exec_inner(const char *exe, struct exeinfo *info);
414
fitzhardinge7e343cd2003-12-16 02:14:00 +0000415static 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
nethercote31779c72004-07-30 21:50:15 +0000421static int load_ELF(char *hdr, int len, int fd, const char *name,
422 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000423{
424 struct elfinfo *e;
425 struct elfinfo *interp = NULL;
fitzhardingeca9bd9c2004-09-08 20:05:02 +0000426 ESZ(Addr) minaddr = ~0; /* lowest mapped address */
427 ESZ(Addr) maxaddr = 0; /* highest mapped address */
428 ESZ(Addr) interp_addr = 0; /* interpreter (ld.so) address */
429 ESZ(Word) interp_size = 0; /* interpreter size */
nethercote73b526f2004-10-31 18:48:21 +0000430 ESZ(Word) interp_align = VKI_PAGE_SIZE;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000431 int i;
432 void *entry;
nethercote7f390022004-10-25 17:18:24 +0000433 ESZ(Addr) ebase = 0;
434
435#ifdef HAVE_PIE
436 ebase = info->exe_base;
437#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000438
439 e = readelf(fd, name);
440
441 if (e == NULL)
442 return ENOEXEC;
443
tomd6dd9912005-07-18 15:52:30 +0000444 /* The kernel maps position-independent executables at TASK_SIZE*2/3;
445 duplicate this behavior as close as we can. */
446 if (e->e.e_type == ET_DYN && ebase == 0) {
447 ebase = VG_PGROUNDDN(info->exe_base + (info->exe_end - info->exe_base) * 2 / 3);
448 }
449
fitzhardinge7e343cd2003-12-16 02:14:00 +0000450 info->phnum = e->e.e_phnum;
nethercote7f390022004-10-25 17:18:24 +0000451 info->entry = e->e.e_entry + ebase;
sewardjb5f6f512005-03-10 23:59:00 +0000452 info->phdr = 0;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000453
454 for(i = 0; i < e->e.e_phnum; i++) {
455 ESZ(Phdr) *ph = &e->p[i];
456
457 switch(ph->p_type) {
458 case PT_PHDR:
nethercote7f390022004-10-25 17:18:24 +0000459 info->phdr = ph->p_vaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000460 break;
461
462 case PT_LOAD:
463 if (ph->p_vaddr < minaddr)
464 minaddr = ph->p_vaddr;
465 if (ph->p_vaddr+ph->p_memsz > maxaddr)
466 maxaddr = ph->p_vaddr+ph->p_memsz;
467 break;
468
469 case PT_INTERP: {
470 char *buf = malloc(ph->p_filesz+1);
471 int j;
472 int intfd;
473 int baseaddr_set;
474
nethercote7c018f42004-07-17 16:40:50 +0000475 assert(buf);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000476 pread(fd, buf, ph->p_filesz, ph->p_offset);
477 buf[ph->p_filesz] = '\0';
478
479 intfd = open(buf, O_RDONLY);
480 if (intfd == -1) {
481 perror("open interp");
482 exit(1);
483 }
484
485 interp = readelf(intfd, buf);
486 if (interp == NULL) {
487 fprintf(stderr, "Can't read interpreter\n");
488 return 1;
489 }
490 free(buf);
491
492 baseaddr_set = 0;
493 for(j = 0; j < interp->e.e_phnum; j++) {
494 ESZ(Phdr) *iph = &interp->p[j];
495 ESZ(Addr) end;
496
497 if (iph->p_type != PT_LOAD)
498 continue;
499
500 if (!baseaddr_set) {
nethercote7f390022004-10-25 17:18:24 +0000501 interp_addr = iph->p_vaddr;
502 interp_align = iph->p_align;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000503 baseaddr_set = 1;
504 }
505
506 /* assumes that all segments in the interp are close */
507 end = (iph->p_vaddr - interp_addr) + iph->p_memsz;
508
509 if (end > interp_size)
510 interp_size = end;
511 }
512 break;
nethercoteb24cbc82004-09-03 23:25:33 +0000513
514 default:
515 // do nothing
516 break;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000517 }
518 }
519 }
520
sewardjb5f6f512005-03-10 23:59:00 +0000521 if (info->phdr == 0)
tomd6dd9912005-07-18 15:52:30 +0000522 info->phdr = minaddr + ebase + e->e.e_phoff;
sewardjb5f6f512005-03-10 23:59:00 +0000523
fitzhardinge7e343cd2003-12-16 02:14:00 +0000524 if (info->exe_base != info->exe_end) {
525 if (minaddr >= maxaddr ||
nethercote7f390022004-10-25 17:18:24 +0000526 (minaddr + ebase < info->exe_base ||
527 maxaddr + ebase > info->exe_end)) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000528 fprintf(stderr, "Executable range %p-%p is outside the\n"
529 "acceptable range %p-%p\n",
nethercote7f390022004-10-25 17:18:24 +0000530 (void *)minaddr + ebase, (void *)maxaddr + ebase,
531 (void *)info->exe_base, (void *)info->exe_end);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000532 return ENOMEM;
533 }
534 }
535
nethercote7f390022004-10-25 17:18:24 +0000536 info->brkbase = mapelf(e, ebase); /* map the executable */
fitzhardinge7e343cd2003-12-16 02:14:00 +0000537
fitzhardinge92360792003-12-24 10:11:11 +0000538 if (info->brkbase == 0)
539 return ENOMEM;
540
fitzhardinge7e343cd2003-12-16 02:14:00 +0000541 if (interp != NULL) {
542 /* reserve a chunk of address space for interpreter */
nethercotebfed1c82004-07-17 12:57:44 +0000543 void* res;
544 char* base = (char *)info->exe_base;
545 char* baseoff;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000546 int flags = MAP_PRIVATE|MAP_ANONYMOUS;
547
548 if (info->map_base != 0) {
njn13bfd852005-06-02 03:52:53 +0000549 base = (char *)VG_ROUNDUP(info->map_base, interp_align);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000550 flags |= MAP_FIXED;
551 }
552
nethercotebfed1c82004-07-17 12:57:44 +0000553 res = mmap(base, interp_size, PROT_NONE, flags, -1, 0);
554 check_mmap(res, base, interp_size);
555 base = res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000556
557 baseoff = base - interp_addr;
558
fitzhardingeb50068f2004-02-24 23:42:55 +0000559 mapelf(interp, (ESZ(Addr))baseoff);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000560
561 close(interp->fd);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000562
563 entry = baseoff + interp->e.e_entry;
564 info->interp_base = (ESZ(Addr))base;
thughes54d08592004-09-26 14:42:47 +0000565
sewardjb5f6f512005-03-10 23:59:00 +0000566 free(interp->p);
thughes54d08592004-09-26 14:42:47 +0000567 free(interp);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000568 } else
tomd6dd9912005-07-18 15:52:30 +0000569 entry = (void *)(ebase + e->e.e_entry);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000570
nethercote7f390022004-10-25 17:18:24 +0000571 info->exe_base = minaddr + ebase;
572 info->exe_end = maxaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000573
nethercotea3c3cf22004-11-01 18:38:00 +0000574 info->init_eip = (Addr)entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000575
sewardjb5f6f512005-03-10 23:59:00 +0000576 free(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000577 free(e);
578
579 return 0;
580}
581
582
583static int match_script(const char *hdr, Int len)
584{
585 return (len > 2) && memcmp(hdr, "#!", 2) == 0;
586}
587
nethercote31779c72004-07-30 21:50:15 +0000588static int load_script(char *hdr, int len, int fd, const char *name,
589 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000590{
591 char *interp;
592 char *const end = hdr+len;
593 char *cp;
594 char *arg = NULL;
595 int eol;
596
597 interp = hdr + 2;
598 while(interp < end && (*interp == ' ' || *interp == '\t'))
599 interp++;
600
601 if (*interp != '/')
602 return ENOEXEC; /* absolute path only for interpreter */
603
604 /* skip over interpreter name */
605 for(cp = interp; cp < end && *cp != ' ' && *cp != '\t' && *cp != '\n'; cp++)
606 ;
607
608 eol = (*cp == '\n');
609
610 *cp++ = '\0';
611
612 if (!eol && cp < end) {
613 /* skip space before arg */
614 while (cp < end && (*cp == '\t' || *cp == ' '))
615 cp++;
616
617 /* arg is from here to eol */
618 arg = cp;
619 while (cp < end && *cp != '\n')
620 cp++;
621 *cp = '\0';
622 }
623
nethercoted6a56872004-07-26 15:32:47 +0000624 info->interp_name = strdup(interp);
625 assert(NULL != info->interp_name);
nethercote71980f02004-01-24 18:18:54 +0000626 if (arg != NULL && *arg != '\0') {
nethercoted6a56872004-07-26 15:32:47 +0000627 info->interp_args = strdup(arg);
628 assert(NULL != info->interp_args);
nethercote71980f02004-01-24 18:18:54 +0000629 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000630
631 if (info->argv && info->argv[0] != NULL)
632 info->argv[0] = (char *)name;
633
634 if (0)
nethercoted6a56872004-07-26 15:32:47 +0000635 printf("#! script: interp_name=\"%s\" interp_args=\"%s\"\n",
636 info->interp_name, info->interp_args);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000637
638 return do_exec_inner(interp, info);
639}
640
fitzhardingefd7da3a2004-09-08 20:05:29 +0000641/*
642 Emulate the normal Unix permissions checking algorithm.
643
644 If owner matches, then use the owner permissions, else
645 if group matches, then use the group permissions, else
646 use other permissions.
647
648 Note that we can't deal with SUID/SGID, so we refuse to run them
649 (otherwise the executable may misbehave if it doesn't have the
650 permissions it thinks it does).
651*/
652static int check_perms(int fd)
653{
654 struct stat st;
655
656 if (fstat(fd, &st) == -1)
657 return errno;
658
659 if (st.st_mode & (S_ISUID | S_ISGID)) {
660 //fprintf(stderr, "Can't execute suid/sgid executable %s\n", exe);
661 return EACCES;
662 }
663
664 if (geteuid() == st.st_uid) {
665 if (!(st.st_mode & S_IXUSR))
666 return EACCES;
667 } else {
668 int grpmatch = 0;
669
670 if (getegid() == st.st_gid)
671 grpmatch = 1;
672 else {
673 gid_t groups[32];
674 int ngrp = getgroups(32, groups);
675 int i;
676
677 for(i = 0; i < ngrp; i++)
678 if (groups[i] == st.st_gid) {
679 grpmatch = 1;
680 break;
681 }
682 }
683
684 if (grpmatch) {
685 if (!(st.st_mode & S_IXGRP))
686 return EACCES;
687 } else if (!(st.st_mode & S_IXOTH))
688 return EACCES;
689 }
690
691 return 0;
692}
693
fitzhardinge7e343cd2003-12-16 02:14:00 +0000694static int do_exec_inner(const char *exe, struct exeinfo *info)
695{
696 int fd;
fitzhardinged2e37112004-09-09 08:10:42 +0000697 int err;
nethercote73b526f2004-10-31 18:48:21 +0000698 char buf[VKI_PAGE_SIZE];
fitzhardinge7e343cd2003-12-16 02:14:00 +0000699 int bufsz;
700 int i;
701 int ret;
nethercote31779c72004-07-30 21:50:15 +0000702 static const struct {
703 int (*match)(const char *hdr, int len);
704 int (*load) ( char *hdr, int len, int fd2, const char *name,
705 struct exeinfo *);
706 } formats[] = {
707 { match_ELF, load_ELF },
708 { match_script, load_script },
709 };
fitzhardinge7e343cd2003-12-16 02:14:00 +0000710
711 fd = open(exe, O_RDONLY);
712 if (fd == -1) {
713 if (0)
714 fprintf(stderr, "Can't open executable %s: %s\n",
715 exe, strerror(errno));
716 return errno;
717 }
718
fitzhardinged2e37112004-09-09 08:10:42 +0000719 err = check_perms(fd);
fitzhardingefd7da3a2004-09-08 20:05:29 +0000720 if (err != 0) {
721 close(fd);
722 return err;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000723 }
724
725 bufsz = pread(fd, buf, sizeof(buf), 0);
726 if (bufsz < 0) {
727 fprintf(stderr, "Can't read executable header: %s\n",
728 strerror(errno));
729 close(fd);
730 return errno;
731 }
732
733 ret = ENOEXEC;
734 for(i = 0; i < sizeof(formats)/sizeof(*formats); i++) {
735 if ((formats[i].match)(buf, bufsz)) {
736 ret = (formats[i].load)(buf, bufsz, fd, exe, info);
737 break;
738 }
739 }
740
741 close(fd);
742
743 return ret;
744}
745
nethercoteea147e72004-07-26 15:43:57 +0000746// See ume.h for an indication of which entries of 'info' are inputs, which
747// are outputs, and which are both.
njn62ff0f22005-06-21 23:03:36 +0000748int VG_(do_exec)(const char *exe, struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000749{
nethercoted6a56872004-07-26 15:32:47 +0000750 info->interp_name = NULL;
751 info->interp_args = NULL;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000752
753 return do_exec_inner(exe, info);
754}
nethercotebb1c9912004-01-04 16:43:23 +0000755
756/*--------------------------------------------------------------------*/
njn08a2e172005-06-21 22:47:54 +0000757/*--- end ---*/
nethercotebb1c9912004-01-04 16:43:23 +0000758/*--------------------------------------------------------------------*/