blob: 2aaf6e04bf839dd276f4aff55d23d86aad426840 [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.
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);
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(
191".global jump_and_switch_stacks\n"
192"jump_and_switch_stacks:\n"
193" 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
nethercoteebf1d862004-11-01 18:22:05 +0000240struct ume_auxv *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));
278 return NULL;
279 }
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);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000283 return NULL;
284 }
njn35172bc2005-03-26 00:04:03 +0000285 if (e->e.e_ident[EI_CLASS] != VGA_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");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000289 return NULL;
290 }
njn35172bc2005-03-26 00:04:03 +0000291 if (e->e.e_ident[EI_DATA] != VGA_ELF_ENDIANNESS) {
sewardj703eec52005-04-07 02:24:23 +0000292 fprintf(stderr, "valgrind: executable has wrong endian-ness\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000293 return NULL;
294 }
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");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000297 return NULL;
298 }
299
njn35172bc2005-03-26 00:04:03 +0000300 if (e->e.e_machine != VGA_ELF_MACHINE) {
sewardj703eec52005-04-07 02:24:23 +0000301 fprintf(stderr, "valgrind: executable is not for "
302 "this architecture\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000303 return NULL;
304 }
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");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000308 return NULL;
309 }
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));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000317 return NULL;
318 }
319
320 return e;
321}
322
fitzhardinge7e343cd2003-12-16 02:14:00 +0000323/* Map an ELF file. Returns the brk address. */
sewardj2c5ffbe2005-03-12 13:32:06 +0000324static
fitzhardingeb50068f2004-02-24 23:42:55 +0000325ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000326{
327 int i;
nethercotebfed1c82004-07-17 12:57:44 +0000328 void* res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000329 ESZ(Addr) elfbrk = 0;
330
331 for(i = 0; i < e->e.e_phnum; i++) {
332 ESZ(Phdr) *ph = &e->p[i];
333 ESZ(Addr) addr, brkaddr;
334 ESZ(Word) memsz;
335
336 if (ph->p_type != PT_LOAD)
337 continue;
338
nethercote6c3cf412004-10-26 13:32:11 +0000339 addr = ph->p_vaddr+base;
340 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000341 brkaddr = addr+memsz;
342
343 if (brkaddr > elfbrk)
344 elfbrk = brkaddr;
345 }
346
fitzhardinge7e343cd2003-12-16 02:14:00 +0000347 for(i = 0; i < e->e.e_phnum; i++) {
348 ESZ(Phdr) *ph = &e->p[i];
349 ESZ(Addr) addr, bss, brkaddr;
350 ESZ(Off) off;
351 ESZ(Word) filesz;
352 ESZ(Word) memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000353 unsigned prot = 0;
354
355 if (ph->p_type != PT_LOAD)
356 continue;
357
nethercote6c3cf412004-10-26 13:32:11 +0000358 if (ph->p_flags & PF_X) prot |= PROT_EXEC;
359 if (ph->p_flags & PF_W) prot |= PROT_WRITE;
360 if (ph->p_flags & PF_R) prot |= PROT_READ;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000361
nethercote6c3cf412004-10-26 13:32:11 +0000362 addr = ph->p_vaddr+base;
363 off = ph->p_offset;
364 filesz = ph->p_filesz;
365 bss = addr+filesz;
366 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000367 brkaddr = addr+memsz;
368
njnf7fbe6c2004-11-30 11:40:24 +0000369 // Tom says: In the following, do what the Linux kernel does and only
370 // map the pages that are required instead of rounding everything to
371 // the specified alignment (ph->p_align). (AMD64 doesn't work if you
372 // use ph->p_align -- part of stage2's memory gets trashed somehow.)
njn098da062005-03-26 16:22:43 +0000373 //
374 // The condition handles the case of a zero-length segment.
njn13bfd852005-06-02 03:52:53 +0000375 if (VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr) > 0) {
376 res = mmap((char *)VG_PGROUNDDN(addr),
377 VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr),
378 prot, MAP_FIXED|MAP_PRIVATE, e->fd, VG_PGROUNDDN(off));
379 check_mmap(res, (char*)VG_PGROUNDDN(addr),
380 VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr));
njn098da062005-03-26 16:22:43 +0000381 }
njnf7fbe6c2004-11-30 11:40:24 +0000382
383 // if memsz > filesz, fill the remainder with zeroed pages
fitzhardinge7e343cd2003-12-16 02:14:00 +0000384 if (memsz > filesz) {
385 UInt bytes;
386
njn13bfd852005-06-02 03:52:53 +0000387 bytes = VG_PGROUNDUP(brkaddr)-VG_PGROUNDUP(bss);
nethercotebfed1c82004-07-17 12:57:44 +0000388 if (bytes > 0) {
njn13bfd852005-06-02 03:52:53 +0000389 res = mmap((char *)VG_PGROUNDUP(bss), bytes,
nethercotebfed1c82004-07-17 12:57:44 +0000390 prot, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
njn13bfd852005-06-02 03:52:53 +0000391 check_mmap(res, (char*)VG_PGROUNDUP(bss), bytes);
nethercotebfed1c82004-07-17 12:57:44 +0000392 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000393
nethercote73b526f2004-10-31 18:48:21 +0000394 bytes = bss & (VKI_PAGE_SIZE - 1);
njn098da062005-03-26 16:22:43 +0000395
396 // The 'prot' condition allows for a read-only bss
397 if ((prot & PROT_WRITE) && (bytes > 0)) {
nethercote73b526f2004-10-31 18:48:21 +0000398 bytes = VKI_PAGE_SIZE - bytes;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000399 memset((char *)bss, 0, bytes);
400 }
401 }
402 }
403
404 return elfbrk;
405}
406
nethercote31779c72004-07-30 21:50:15 +0000407// Forward declaration.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000408static int do_exec_inner(const char *exe, struct exeinfo *info);
409
fitzhardinge7e343cd2003-12-16 02:14:00 +0000410static int match_ELF(const char *hdr, int len)
411{
412 ESZ(Ehdr) *e = (ESZ(Ehdr) *)hdr;
413 return (len > sizeof(*e)) && memcmp(&e->e_ident[0], ELFMAG, SELFMAG) == 0;
414}
415
nethercote31779c72004-07-30 21:50:15 +0000416static int load_ELF(char *hdr, int len, int fd, const char *name,
417 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000418{
419 struct elfinfo *e;
420 struct elfinfo *interp = NULL;
fitzhardingeca9bd9c2004-09-08 20:05:02 +0000421 ESZ(Addr) minaddr = ~0; /* lowest mapped address */
422 ESZ(Addr) maxaddr = 0; /* highest mapped address */
423 ESZ(Addr) interp_addr = 0; /* interpreter (ld.so) address */
424 ESZ(Word) interp_size = 0; /* interpreter size */
nethercote73b526f2004-10-31 18:48:21 +0000425 ESZ(Word) interp_align = VKI_PAGE_SIZE;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000426 int i;
427 void *entry;
nethercote7f390022004-10-25 17:18:24 +0000428 ESZ(Addr) ebase = 0;
429
430#ifdef HAVE_PIE
431 ebase = info->exe_base;
432#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000433
434 e = readelf(fd, name);
435
436 if (e == NULL)
437 return ENOEXEC;
438
439 info->phnum = e->e.e_phnum;
nethercote7f390022004-10-25 17:18:24 +0000440 info->entry = e->e.e_entry + ebase;
sewardjb5f6f512005-03-10 23:59:00 +0000441 info->phdr = 0;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000442
443 for(i = 0; i < e->e.e_phnum; i++) {
444 ESZ(Phdr) *ph = &e->p[i];
445
446 switch(ph->p_type) {
447 case PT_PHDR:
nethercote7f390022004-10-25 17:18:24 +0000448 info->phdr = ph->p_vaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000449 break;
450
451 case PT_LOAD:
452 if (ph->p_vaddr < minaddr)
453 minaddr = ph->p_vaddr;
454 if (ph->p_vaddr+ph->p_memsz > maxaddr)
455 maxaddr = ph->p_vaddr+ph->p_memsz;
456 break;
457
458 case PT_INTERP: {
459 char *buf = malloc(ph->p_filesz+1);
460 int j;
461 int intfd;
462 int baseaddr_set;
463
nethercote7c018f42004-07-17 16:40:50 +0000464 assert(buf);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000465 pread(fd, buf, ph->p_filesz, ph->p_offset);
466 buf[ph->p_filesz] = '\0';
467
468 intfd = open(buf, O_RDONLY);
469 if (intfd == -1) {
470 perror("open interp");
471 exit(1);
472 }
473
474 interp = readelf(intfd, buf);
475 if (interp == NULL) {
476 fprintf(stderr, "Can't read interpreter\n");
477 return 1;
478 }
479 free(buf);
480
481 baseaddr_set = 0;
482 for(j = 0; j < interp->e.e_phnum; j++) {
483 ESZ(Phdr) *iph = &interp->p[j];
484 ESZ(Addr) end;
485
486 if (iph->p_type != PT_LOAD)
487 continue;
488
489 if (!baseaddr_set) {
nethercote7f390022004-10-25 17:18:24 +0000490 interp_addr = iph->p_vaddr;
491 interp_align = iph->p_align;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000492 baseaddr_set = 1;
493 }
494
495 /* assumes that all segments in the interp are close */
496 end = (iph->p_vaddr - interp_addr) + iph->p_memsz;
497
498 if (end > interp_size)
499 interp_size = end;
500 }
501 break;
nethercoteb24cbc82004-09-03 23:25:33 +0000502
503 default:
504 // do nothing
505 break;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000506 }
507 }
508 }
509
sewardjb5f6f512005-03-10 23:59:00 +0000510 if (info->phdr == 0)
511 info->phdr = minaddr + e->e.e_phoff;
512
fitzhardinge7e343cd2003-12-16 02:14:00 +0000513 if (info->exe_base != info->exe_end) {
514 if (minaddr >= maxaddr ||
nethercote7f390022004-10-25 17:18:24 +0000515 (minaddr + ebase < info->exe_base ||
516 maxaddr + ebase > info->exe_end)) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000517 fprintf(stderr, "Executable range %p-%p is outside the\n"
518 "acceptable range %p-%p\n",
nethercote7f390022004-10-25 17:18:24 +0000519 (void *)minaddr + ebase, (void *)maxaddr + ebase,
520 (void *)info->exe_base, (void *)info->exe_end);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000521 return ENOMEM;
522 }
523 }
524
nethercote7f390022004-10-25 17:18:24 +0000525 info->brkbase = mapelf(e, ebase); /* map the executable */
fitzhardinge7e343cd2003-12-16 02:14:00 +0000526
fitzhardinge92360792003-12-24 10:11:11 +0000527 if (info->brkbase == 0)
528 return ENOMEM;
529
fitzhardinge7e343cd2003-12-16 02:14:00 +0000530 if (interp != NULL) {
531 /* reserve a chunk of address space for interpreter */
nethercotebfed1c82004-07-17 12:57:44 +0000532 void* res;
533 char* base = (char *)info->exe_base;
534 char* baseoff;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000535 int flags = MAP_PRIVATE|MAP_ANONYMOUS;
536
537 if (info->map_base != 0) {
njn13bfd852005-06-02 03:52:53 +0000538 base = (char *)VG_ROUNDUP(info->map_base, interp_align);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000539 flags |= MAP_FIXED;
540 }
541
nethercotebfed1c82004-07-17 12:57:44 +0000542 res = mmap(base, interp_size, PROT_NONE, flags, -1, 0);
543 check_mmap(res, base, interp_size);
544 base = res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000545
546 baseoff = base - interp_addr;
547
fitzhardingeb50068f2004-02-24 23:42:55 +0000548 mapelf(interp, (ESZ(Addr))baseoff);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000549
550 close(interp->fd);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000551
552 entry = baseoff + interp->e.e_entry;
553 info->interp_base = (ESZ(Addr))base;
thughes54d08592004-09-26 14:42:47 +0000554
sewardjb5f6f512005-03-10 23:59:00 +0000555 free(interp->p);
thughes54d08592004-09-26 14:42:47 +0000556 free(interp);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000557 } else
nethercote7f390022004-10-25 17:18:24 +0000558 entry = (void *)e->e.e_entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000559
nethercote7f390022004-10-25 17:18:24 +0000560 info->exe_base = minaddr + ebase;
561 info->exe_end = maxaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000562
nethercotea3c3cf22004-11-01 18:38:00 +0000563 info->init_eip = (Addr)entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000564
sewardjb5f6f512005-03-10 23:59:00 +0000565 free(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000566 free(e);
567
568 return 0;
569}
570
571
572static int match_script(const char *hdr, Int len)
573{
574 return (len > 2) && memcmp(hdr, "#!", 2) == 0;
575}
576
nethercote31779c72004-07-30 21:50:15 +0000577static int load_script(char *hdr, int len, int fd, const char *name,
578 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000579{
580 char *interp;
581 char *const end = hdr+len;
582 char *cp;
583 char *arg = NULL;
584 int eol;
585
586 interp = hdr + 2;
587 while(interp < end && (*interp == ' ' || *interp == '\t'))
588 interp++;
589
590 if (*interp != '/')
591 return ENOEXEC; /* absolute path only for interpreter */
592
593 /* skip over interpreter name */
594 for(cp = interp; cp < end && *cp != ' ' && *cp != '\t' && *cp != '\n'; cp++)
595 ;
596
597 eol = (*cp == '\n');
598
599 *cp++ = '\0';
600
601 if (!eol && cp < end) {
602 /* skip space before arg */
603 while (cp < end && (*cp == '\t' || *cp == ' '))
604 cp++;
605
606 /* arg is from here to eol */
607 arg = cp;
608 while (cp < end && *cp != '\n')
609 cp++;
610 *cp = '\0';
611 }
612
nethercoted6a56872004-07-26 15:32:47 +0000613 info->interp_name = strdup(interp);
614 assert(NULL != info->interp_name);
nethercote71980f02004-01-24 18:18:54 +0000615 if (arg != NULL && *arg != '\0') {
nethercoted6a56872004-07-26 15:32:47 +0000616 info->interp_args = strdup(arg);
617 assert(NULL != info->interp_args);
nethercote71980f02004-01-24 18:18:54 +0000618 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000619
620 if (info->argv && info->argv[0] != NULL)
621 info->argv[0] = (char *)name;
622
623 if (0)
nethercoted6a56872004-07-26 15:32:47 +0000624 printf("#! script: interp_name=\"%s\" interp_args=\"%s\"\n",
625 info->interp_name, info->interp_args);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000626
627 return do_exec_inner(interp, info);
628}
629
fitzhardingefd7da3a2004-09-08 20:05:29 +0000630/*
631 Emulate the normal Unix permissions checking algorithm.
632
633 If owner matches, then use the owner permissions, else
634 if group matches, then use the group permissions, else
635 use other permissions.
636
637 Note that we can't deal with SUID/SGID, so we refuse to run them
638 (otherwise the executable may misbehave if it doesn't have the
639 permissions it thinks it does).
640*/
641static int check_perms(int fd)
642{
643 struct stat st;
644
645 if (fstat(fd, &st) == -1)
646 return errno;
647
648 if (st.st_mode & (S_ISUID | S_ISGID)) {
649 //fprintf(stderr, "Can't execute suid/sgid executable %s\n", exe);
650 return EACCES;
651 }
652
653 if (geteuid() == st.st_uid) {
654 if (!(st.st_mode & S_IXUSR))
655 return EACCES;
656 } else {
657 int grpmatch = 0;
658
659 if (getegid() == st.st_gid)
660 grpmatch = 1;
661 else {
662 gid_t groups[32];
663 int ngrp = getgroups(32, groups);
664 int i;
665
666 for(i = 0; i < ngrp; i++)
667 if (groups[i] == st.st_gid) {
668 grpmatch = 1;
669 break;
670 }
671 }
672
673 if (grpmatch) {
674 if (!(st.st_mode & S_IXGRP))
675 return EACCES;
676 } else if (!(st.st_mode & S_IXOTH))
677 return EACCES;
678 }
679
680 return 0;
681}
682
fitzhardinge7e343cd2003-12-16 02:14:00 +0000683static int do_exec_inner(const char *exe, struct exeinfo *info)
684{
685 int fd;
fitzhardinged2e37112004-09-09 08:10:42 +0000686 int err;
nethercote73b526f2004-10-31 18:48:21 +0000687 char buf[VKI_PAGE_SIZE];
fitzhardinge7e343cd2003-12-16 02:14:00 +0000688 int bufsz;
689 int i;
690 int ret;
nethercote31779c72004-07-30 21:50:15 +0000691 static const struct {
692 int (*match)(const char *hdr, int len);
693 int (*load) ( char *hdr, int len, int fd2, const char *name,
694 struct exeinfo *);
695 } formats[] = {
696 { match_ELF, load_ELF },
697 { match_script, load_script },
698 };
fitzhardinge7e343cd2003-12-16 02:14:00 +0000699
700 fd = open(exe, O_RDONLY);
701 if (fd == -1) {
702 if (0)
703 fprintf(stderr, "Can't open executable %s: %s\n",
704 exe, strerror(errno));
705 return errno;
706 }
707
fitzhardinged2e37112004-09-09 08:10:42 +0000708 err = check_perms(fd);
fitzhardingefd7da3a2004-09-08 20:05:29 +0000709 if (err != 0) {
710 close(fd);
711 return err;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000712 }
713
714 bufsz = pread(fd, buf, sizeof(buf), 0);
715 if (bufsz < 0) {
716 fprintf(stderr, "Can't read executable header: %s\n",
717 strerror(errno));
718 close(fd);
719 return errno;
720 }
721
722 ret = ENOEXEC;
723 for(i = 0; i < sizeof(formats)/sizeof(*formats); i++) {
724 if ((formats[i].match)(buf, bufsz)) {
725 ret = (formats[i].load)(buf, bufsz, fd, exe, info);
726 break;
727 }
728 }
729
730 close(fd);
731
732 return ret;
733}
734
nethercoteea147e72004-07-26 15:43:57 +0000735// See ume.h for an indication of which entries of 'info' are inputs, which
736// are outputs, and which are both.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000737int do_exec(const char *exe, struct exeinfo *info)
738{
nethercoted6a56872004-07-26 15:32:47 +0000739 info->interp_name = NULL;
740 info->interp_args = NULL;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000741
742 return do_exec_inner(exe, info);
743}
nethercotebb1c9912004-01-04 16:43:23 +0000744
745/*--------------------------------------------------------------------*/
njn08a2e172005-06-21 22:47:54 +0000746/*--- end ---*/
nethercotebb1c9912004-01-04 16:43:23 +0000747/*--------------------------------------------------------------------*/