blob: 983dfe8a1a994497f8f8acb085eec590c97c697b [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
nethercotef1e5e152004-09-01 23:58:16 +000036#include "core.h"
fitzhardinge7e343cd2003-12-16 02:14:00 +000037
fitzhardinge7e343cd2003-12-16 02:14:00 +000038#include <sys/mman.h>
39#include <fcntl.h>
40#include <errno.h>
fitzhardinge7e343cd2003-12-16 02:14:00 +000041#include <stdio.h>
42#include <string.h>
43#include <stdlib.h>
44#include <unistd.h>
fitzhardinge7e343cd2003-12-16 02:14:00 +000045#include <assert.h>
46
47#include "ume.h"
njn5363a562005-06-12 04:34:51 +000048#include "pub_core_libcbase.h"
njnf536bbb2005-06-13 04:21:38 +000049#include "pub_core_machine.h"
fitzhardinge7e343cd2003-12-16 02:14:00 +000050
nethercote3f458152004-11-01 18:42:23 +000051#if ELFSZ == 64
52#define ESZ(x) Elf64_##x
53#elif ELFSZ == 32
54#define ESZ(x) Elf32_##x
55#else
56#error ELFSZ needs to ==32 or ==64
57#endif
58
nethercote1fe54502004-07-26 15:28:33 +000059struct elfinfo
60{
61 ESZ(Ehdr) e;
62 ESZ(Phdr) *p;
63 int fd;
64};
65
nethercote30d37842004-07-26 10:05:55 +000066static void check_mmap(void* res, void* base, int len)
nethercotebfed1c82004-07-17 12:57:44 +000067{
68 if ((void*)-1 == res) {
nethercote969ecf12004-10-13 17:29:01 +000069 fprintf(stderr, "valgrind: mmap(%p, %d) failed in UME.\n", base, len);
nethercotebfed1c82004-07-17 12:57:44 +000070 exit(1);
71 }
72}
73
nethercote31779c72004-07-30 21:50:15 +000074// 'extra' allows the caller to pass in extra args to 'fn', like free
75// variables to a closure.
76void foreach_map(int (*fn)(char *start, char *end,
fitzhardinge7e343cd2003-12-16 02:14:00 +000077 const char *perm, off_t offset,
nethercote31779c72004-07-30 21:50:15 +000078 int maj, int min, int ino, void* extra),
79 void* extra)
fitzhardinge7e343cd2003-12-16 02:14:00 +000080{
81 static char buf[10240];
82 char *bufptr = buf;
83 int ret, fd;
84
85 fd = open("/proc/self/maps", O_RDONLY);
86
87 if (fd == -1) {
88 perror("open /proc/self/maps");
89 return;
90 }
91
92 ret = read(fd, buf, sizeof(buf));
93
94 if (ret == -1) {
95 perror("read /proc/self/maps");
96 close(fd);
97 return;
98 }
99 close(fd);
100
101 if (ret == sizeof(buf)) {
102 fprintf(stderr, "buf too small\n");
103 return;
104 }
105
106 while(bufptr && bufptr < buf+ret) {
107 char perm[5];
njnc6168192004-11-29 13:54:10 +0000108 ULong offset;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000109 int maj, min;
110 int ino;
111 void *segstart, *segend;
112
nethercote545fe672004-11-01 16:52:43 +0000113 sscanf(bufptr, "%p-%p %s %llx %x:%x %d",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000114 &segstart, &segend, perm, &offset, &maj, &min, &ino);
115 bufptr = strchr(bufptr, '\n');
116 if (bufptr != NULL)
117 bufptr++; /* skip \n */
118
nethercote31779c72004-07-30 21:50:15 +0000119 if (!(*fn)(segstart, segend, perm, offset, maj, min, ino, extra))
fitzhardinge7e343cd2003-12-16 02:14:00 +0000120 break;
121 }
122}
123
nethercote31779c72004-07-30 21:50:15 +0000124/*------------------------------------------------------------*/
njnfcb7c3e2005-06-18 15:54:25 +0000125/*--- Stack switching ---*/
126/*------------------------------------------------------------*/
127
128// __attribute__((noreturn))
129// void jump_and_switch_stacks ( Addr stack, Addr dst );
130#if defined(VGA_x86)
131// 4(%esp) == stack
132// 8(%esp) == dst
133asm(
134".global jump_and_switch_stacks\n"
135"jump_and_switch_stacks:\n"
136" movl %esp, %esi\n" // remember old stack pointer
137" movl 4(%esi), %esp\n" // set stack
138" pushl 8(%esi)\n" // dst to stack
139" movl $0, %eax\n" // zero all GP regs
140" movl $0, %ebx\n"
141" movl $0, %ecx\n"
142" movl $0, %edx\n"
143" movl $0, %esi\n"
144" movl $0, %edi\n"
145" movl $0, %ebp\n"
146" ret\n" // jump to dst
147" ud2\n" // should never get here
148);
149#elif defined(VGA_amd64)
150// %rdi == stack
151// %rsi == dst
152asm(
153".global jump_and_switch_stacks\n"
154"jump_and_switch_stacks:\n"
155" movq %rdi, %rsp\n" // set stack
156" pushq %rsi\n" // dst to stack
157" movq $0, %rax\n" // zero all GP regs
158" movq $0, %rbx\n"
159" movq $0, %rcx\n"
160" movq $0, %rdx\n"
161" movq $0, %rsi\n"
162" movq $0, %rdi\n"
163" movq $0, %rbp\n"
164" movq $0, %r8\n"\
165" movq $0, %r9\n"\
166" movq $0, %r10\n"
167" movq $0, %r11\n"
168" movq $0, %r12\n"
169" movq $0, %r13\n"
170" movq $0, %r14\n"
171" movq $0, %r15\n"
172" ret\n" // jump to dst
173" ud2\n" // should never get here
174);
175#else
176# error Unknown architecture
177#endif
178
179/*------------------------------------------------------------*/
nethercote31779c72004-07-30 21:50:15 +0000180/*--- Finding auxv on the stack ---*/
181/*------------------------------------------------------------*/
fitzhardinge7e343cd2003-12-16 02:14:00 +0000182
nethercoteebf1d862004-11-01 18:22:05 +0000183struct ume_auxv *find_auxv(UWord* sp)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000184{
nethercoteebf1d862004-11-01 18:22:05 +0000185 sp++; // skip argc (Nb: is word-sized, not int-sized!)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000186
nethercoteebf1d862004-11-01 18:22:05 +0000187 while (*sp != 0) // skip argv
188 sp++;
189 sp++;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000190
nethercoteebf1d862004-11-01 18:22:05 +0000191 while (*sp != 0) // skip env
192 sp++;
193 sp++;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000194
nethercoteebf1d862004-11-01 18:22:05 +0000195 return (struct ume_auxv *)sp;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000196}
197
nethercote31779c72004-07-30 21:50:15 +0000198/*------------------------------------------------------------*/
199/*--- Loading ELF files ---*/
200/*------------------------------------------------------------*/
fitzhardinge7e343cd2003-12-16 02:14:00 +0000201
sewardj2c5ffbe2005-03-12 13:32:06 +0000202static
fitzhardinge7e343cd2003-12-16 02:14:00 +0000203struct elfinfo *readelf(int fd, const char *filename)
204{
205 struct elfinfo *e = malloc(sizeof(*e));
206 int phsz;
207
nethercote7c018f42004-07-17 16:40:50 +0000208 assert(e);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000209 e->fd = fd;
210
211 if (pread(fd, &e->e, sizeof(e->e), 0) != sizeof(e->e)) {
sewardj703eec52005-04-07 02:24:23 +0000212 fprintf(stderr, "valgrind: %s: can't read ELF header: %s\n",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000213 filename, strerror(errno));
214 return NULL;
215 }
216
217 if (memcmp(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) {
sewardj703eec52005-04-07 02:24:23 +0000218 fprintf(stderr, "valgrind: %s: bad ELF magic number\n", filename);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000219 return NULL;
220 }
njn35172bc2005-03-26 00:04:03 +0000221 if (e->e.e_ident[EI_CLASS] != VGA_ELF_CLASS) {
sewardj703eec52005-04-07 02:24:23 +0000222 fprintf(stderr,
223 "valgrind: wrong ELF executable class "
224 "(eg. 32-bit instead of 64-bit)\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000225 return NULL;
226 }
njn35172bc2005-03-26 00:04:03 +0000227 if (e->e.e_ident[EI_DATA] != VGA_ELF_ENDIANNESS) {
sewardj703eec52005-04-07 02:24:23 +0000228 fprintf(stderr, "valgrind: executable has wrong endian-ness\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000229 return NULL;
230 }
231 if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) {
sewardj703eec52005-04-07 02:24:23 +0000232 fprintf(stderr, "valgrind: this is not an executable\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000233 return NULL;
234 }
235
njn35172bc2005-03-26 00:04:03 +0000236 if (e->e.e_machine != VGA_ELF_MACHINE) {
sewardj703eec52005-04-07 02:24:23 +0000237 fprintf(stderr, "valgrind: executable is not for "
238 "this architecture\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000239 return NULL;
240 }
241
242 if (e->e.e_phentsize != sizeof(ESZ(Phdr))) {
sewardj703eec52005-04-07 02:24:23 +0000243 fprintf(stderr, "valgrind: sizeof ELF Phdr wrong\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000244 return NULL;
245 }
246
247 phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum;
248 e->p = malloc(phsz);
nethercote7c018f42004-07-17 16:40:50 +0000249 assert(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000250
251 if (pread(fd, e->p, phsz, e->e.e_phoff) != phsz) {
nethercote08eaff32004-07-22 12:41:12 +0000252 fprintf(stderr, "valgrind: can't read phdr: %s\n", strerror(errno));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000253 return NULL;
254 }
255
256 return e;
257}
258
fitzhardinge7e343cd2003-12-16 02:14:00 +0000259/* Map an ELF file. Returns the brk address. */
sewardj2c5ffbe2005-03-12 13:32:06 +0000260static
fitzhardingeb50068f2004-02-24 23:42:55 +0000261ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000262{
263 int i;
nethercotebfed1c82004-07-17 12:57:44 +0000264 void* res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000265 ESZ(Addr) elfbrk = 0;
266
267 for(i = 0; i < e->e.e_phnum; i++) {
268 ESZ(Phdr) *ph = &e->p[i];
269 ESZ(Addr) addr, brkaddr;
270 ESZ(Word) memsz;
271
272 if (ph->p_type != PT_LOAD)
273 continue;
274
nethercote6c3cf412004-10-26 13:32:11 +0000275 addr = ph->p_vaddr+base;
276 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000277 brkaddr = addr+memsz;
278
279 if (brkaddr > elfbrk)
280 elfbrk = brkaddr;
281 }
282
fitzhardinge7e343cd2003-12-16 02:14:00 +0000283 for(i = 0; i < e->e.e_phnum; i++) {
284 ESZ(Phdr) *ph = &e->p[i];
285 ESZ(Addr) addr, bss, brkaddr;
286 ESZ(Off) off;
287 ESZ(Word) filesz;
288 ESZ(Word) memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000289 unsigned prot = 0;
290
291 if (ph->p_type != PT_LOAD)
292 continue;
293
nethercote6c3cf412004-10-26 13:32:11 +0000294 if (ph->p_flags & PF_X) prot |= PROT_EXEC;
295 if (ph->p_flags & PF_W) prot |= PROT_WRITE;
296 if (ph->p_flags & PF_R) prot |= PROT_READ;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000297
nethercote6c3cf412004-10-26 13:32:11 +0000298 addr = ph->p_vaddr+base;
299 off = ph->p_offset;
300 filesz = ph->p_filesz;
301 bss = addr+filesz;
302 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000303 brkaddr = addr+memsz;
304
njnf7fbe6c2004-11-30 11:40:24 +0000305 // Tom says: In the following, do what the Linux kernel does and only
306 // map the pages that are required instead of rounding everything to
307 // the specified alignment (ph->p_align). (AMD64 doesn't work if you
308 // use ph->p_align -- part of stage2's memory gets trashed somehow.)
njn098da062005-03-26 16:22:43 +0000309 //
310 // The condition handles the case of a zero-length segment.
njn13bfd852005-06-02 03:52:53 +0000311 if (VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr) > 0) {
312 res = mmap((char *)VG_PGROUNDDN(addr),
313 VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr),
314 prot, MAP_FIXED|MAP_PRIVATE, e->fd, VG_PGROUNDDN(off));
315 check_mmap(res, (char*)VG_PGROUNDDN(addr),
316 VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr));
njn098da062005-03-26 16:22:43 +0000317 }
njnf7fbe6c2004-11-30 11:40:24 +0000318
319 // if memsz > filesz, fill the remainder with zeroed pages
fitzhardinge7e343cd2003-12-16 02:14:00 +0000320 if (memsz > filesz) {
321 UInt bytes;
322
njn13bfd852005-06-02 03:52:53 +0000323 bytes = VG_PGROUNDUP(brkaddr)-VG_PGROUNDUP(bss);
nethercotebfed1c82004-07-17 12:57:44 +0000324 if (bytes > 0) {
njn13bfd852005-06-02 03:52:53 +0000325 res = mmap((char *)VG_PGROUNDUP(bss), bytes,
nethercotebfed1c82004-07-17 12:57:44 +0000326 prot, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
njn13bfd852005-06-02 03:52:53 +0000327 check_mmap(res, (char*)VG_PGROUNDUP(bss), bytes);
nethercotebfed1c82004-07-17 12:57:44 +0000328 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000329
nethercote73b526f2004-10-31 18:48:21 +0000330 bytes = bss & (VKI_PAGE_SIZE - 1);
njn098da062005-03-26 16:22:43 +0000331
332 // The 'prot' condition allows for a read-only bss
333 if ((prot & PROT_WRITE) && (bytes > 0)) {
nethercote73b526f2004-10-31 18:48:21 +0000334 bytes = VKI_PAGE_SIZE - bytes;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000335 memset((char *)bss, 0, bytes);
336 }
337 }
338 }
339
340 return elfbrk;
341}
342
nethercote31779c72004-07-30 21:50:15 +0000343// Forward declaration.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000344static int do_exec_inner(const char *exe, struct exeinfo *info);
345
fitzhardinge7e343cd2003-12-16 02:14:00 +0000346static int match_ELF(const char *hdr, int len)
347{
348 ESZ(Ehdr) *e = (ESZ(Ehdr) *)hdr;
349 return (len > sizeof(*e)) && memcmp(&e->e_ident[0], ELFMAG, SELFMAG) == 0;
350}
351
nethercote31779c72004-07-30 21:50:15 +0000352static int load_ELF(char *hdr, int len, int fd, const char *name,
353 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000354{
355 struct elfinfo *e;
356 struct elfinfo *interp = NULL;
fitzhardingeca9bd9c2004-09-08 20:05:02 +0000357 ESZ(Addr) minaddr = ~0; /* lowest mapped address */
358 ESZ(Addr) maxaddr = 0; /* highest mapped address */
359 ESZ(Addr) interp_addr = 0; /* interpreter (ld.so) address */
360 ESZ(Word) interp_size = 0; /* interpreter size */
nethercote73b526f2004-10-31 18:48:21 +0000361 ESZ(Word) interp_align = VKI_PAGE_SIZE;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000362 int i;
363 void *entry;
nethercote7f390022004-10-25 17:18:24 +0000364 ESZ(Addr) ebase = 0;
365
366#ifdef HAVE_PIE
367 ebase = info->exe_base;
368#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000369
370 e = readelf(fd, name);
371
372 if (e == NULL)
373 return ENOEXEC;
374
375 info->phnum = e->e.e_phnum;
nethercote7f390022004-10-25 17:18:24 +0000376 info->entry = e->e.e_entry + ebase;
sewardjb5f6f512005-03-10 23:59:00 +0000377 info->phdr = 0;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000378
379 for(i = 0; i < e->e.e_phnum; i++) {
380 ESZ(Phdr) *ph = &e->p[i];
381
382 switch(ph->p_type) {
383 case PT_PHDR:
nethercote7f390022004-10-25 17:18:24 +0000384 info->phdr = ph->p_vaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000385 break;
386
387 case PT_LOAD:
388 if (ph->p_vaddr < minaddr)
389 minaddr = ph->p_vaddr;
390 if (ph->p_vaddr+ph->p_memsz > maxaddr)
391 maxaddr = ph->p_vaddr+ph->p_memsz;
392 break;
393
394 case PT_INTERP: {
395 char *buf = malloc(ph->p_filesz+1);
396 int j;
397 int intfd;
398 int baseaddr_set;
399
nethercote7c018f42004-07-17 16:40:50 +0000400 assert(buf);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000401 pread(fd, buf, ph->p_filesz, ph->p_offset);
402 buf[ph->p_filesz] = '\0';
403
404 intfd = open(buf, O_RDONLY);
405 if (intfd == -1) {
406 perror("open interp");
407 exit(1);
408 }
409
410 interp = readelf(intfd, buf);
411 if (interp == NULL) {
412 fprintf(stderr, "Can't read interpreter\n");
413 return 1;
414 }
415 free(buf);
416
417 baseaddr_set = 0;
418 for(j = 0; j < interp->e.e_phnum; j++) {
419 ESZ(Phdr) *iph = &interp->p[j];
420 ESZ(Addr) end;
421
422 if (iph->p_type != PT_LOAD)
423 continue;
424
425 if (!baseaddr_set) {
nethercote7f390022004-10-25 17:18:24 +0000426 interp_addr = iph->p_vaddr;
427 interp_align = iph->p_align;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000428 baseaddr_set = 1;
429 }
430
431 /* assumes that all segments in the interp are close */
432 end = (iph->p_vaddr - interp_addr) + iph->p_memsz;
433
434 if (end > interp_size)
435 interp_size = end;
436 }
437 break;
nethercoteb24cbc82004-09-03 23:25:33 +0000438
439 default:
440 // do nothing
441 break;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000442 }
443 }
444 }
445
sewardjb5f6f512005-03-10 23:59:00 +0000446 if (info->phdr == 0)
447 info->phdr = minaddr + e->e.e_phoff;
448
fitzhardinge7e343cd2003-12-16 02:14:00 +0000449 if (info->exe_base != info->exe_end) {
450 if (minaddr >= maxaddr ||
nethercote7f390022004-10-25 17:18:24 +0000451 (minaddr + ebase < info->exe_base ||
452 maxaddr + ebase > info->exe_end)) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000453 fprintf(stderr, "Executable range %p-%p is outside the\n"
454 "acceptable range %p-%p\n",
nethercote7f390022004-10-25 17:18:24 +0000455 (void *)minaddr + ebase, (void *)maxaddr + ebase,
456 (void *)info->exe_base, (void *)info->exe_end);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000457 return ENOMEM;
458 }
459 }
460
nethercote7f390022004-10-25 17:18:24 +0000461 info->brkbase = mapelf(e, ebase); /* map the executable */
fitzhardinge7e343cd2003-12-16 02:14:00 +0000462
fitzhardinge92360792003-12-24 10:11:11 +0000463 if (info->brkbase == 0)
464 return ENOMEM;
465
fitzhardinge7e343cd2003-12-16 02:14:00 +0000466 if (interp != NULL) {
467 /* reserve a chunk of address space for interpreter */
nethercotebfed1c82004-07-17 12:57:44 +0000468 void* res;
469 char* base = (char *)info->exe_base;
470 char* baseoff;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000471 int flags = MAP_PRIVATE|MAP_ANONYMOUS;
472
473 if (info->map_base != 0) {
njn13bfd852005-06-02 03:52:53 +0000474 base = (char *)VG_ROUNDUP(info->map_base, interp_align);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000475 flags |= MAP_FIXED;
476 }
477
nethercotebfed1c82004-07-17 12:57:44 +0000478 res = mmap(base, interp_size, PROT_NONE, flags, -1, 0);
479 check_mmap(res, base, interp_size);
480 base = res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000481
482 baseoff = base - interp_addr;
483
fitzhardingeb50068f2004-02-24 23:42:55 +0000484 mapelf(interp, (ESZ(Addr))baseoff);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000485
486 close(interp->fd);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000487
488 entry = baseoff + interp->e.e_entry;
489 info->interp_base = (ESZ(Addr))base;
thughes54d08592004-09-26 14:42:47 +0000490
sewardjb5f6f512005-03-10 23:59:00 +0000491 free(interp->p);
thughes54d08592004-09-26 14:42:47 +0000492 free(interp);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000493 } else
nethercote7f390022004-10-25 17:18:24 +0000494 entry = (void *)e->e.e_entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000495
nethercote7f390022004-10-25 17:18:24 +0000496 info->exe_base = minaddr + ebase;
497 info->exe_end = maxaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000498
nethercotea3c3cf22004-11-01 18:38:00 +0000499 info->init_eip = (Addr)entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000500
sewardjb5f6f512005-03-10 23:59:00 +0000501 free(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000502 free(e);
503
504 return 0;
505}
506
507
508static int match_script(const char *hdr, Int len)
509{
510 return (len > 2) && memcmp(hdr, "#!", 2) == 0;
511}
512
nethercote31779c72004-07-30 21:50:15 +0000513static int load_script(char *hdr, int len, int fd, const char *name,
514 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000515{
516 char *interp;
517 char *const end = hdr+len;
518 char *cp;
519 char *arg = NULL;
520 int eol;
521
522 interp = hdr + 2;
523 while(interp < end && (*interp == ' ' || *interp == '\t'))
524 interp++;
525
526 if (*interp != '/')
527 return ENOEXEC; /* absolute path only for interpreter */
528
529 /* skip over interpreter name */
530 for(cp = interp; cp < end && *cp != ' ' && *cp != '\t' && *cp != '\n'; cp++)
531 ;
532
533 eol = (*cp == '\n');
534
535 *cp++ = '\0';
536
537 if (!eol && cp < end) {
538 /* skip space before arg */
539 while (cp < end && (*cp == '\t' || *cp == ' '))
540 cp++;
541
542 /* arg is from here to eol */
543 arg = cp;
544 while (cp < end && *cp != '\n')
545 cp++;
546 *cp = '\0';
547 }
548
nethercoted6a56872004-07-26 15:32:47 +0000549 info->interp_name = strdup(interp);
550 assert(NULL != info->interp_name);
nethercote71980f02004-01-24 18:18:54 +0000551 if (arg != NULL && *arg != '\0') {
nethercoted6a56872004-07-26 15:32:47 +0000552 info->interp_args = strdup(arg);
553 assert(NULL != info->interp_args);
nethercote71980f02004-01-24 18:18:54 +0000554 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000555
556 if (info->argv && info->argv[0] != NULL)
557 info->argv[0] = (char *)name;
558
559 if (0)
nethercoted6a56872004-07-26 15:32:47 +0000560 printf("#! script: interp_name=\"%s\" interp_args=\"%s\"\n",
561 info->interp_name, info->interp_args);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000562
563 return do_exec_inner(interp, info);
564}
565
fitzhardingefd7da3a2004-09-08 20:05:29 +0000566/*
567 Emulate the normal Unix permissions checking algorithm.
568
569 If owner matches, then use the owner permissions, else
570 if group matches, then use the group permissions, else
571 use other permissions.
572
573 Note that we can't deal with SUID/SGID, so we refuse to run them
574 (otherwise the executable may misbehave if it doesn't have the
575 permissions it thinks it does).
576*/
577static int check_perms(int fd)
578{
579 struct stat st;
580
581 if (fstat(fd, &st) == -1)
582 return errno;
583
584 if (st.st_mode & (S_ISUID | S_ISGID)) {
585 //fprintf(stderr, "Can't execute suid/sgid executable %s\n", exe);
586 return EACCES;
587 }
588
589 if (geteuid() == st.st_uid) {
590 if (!(st.st_mode & S_IXUSR))
591 return EACCES;
592 } else {
593 int grpmatch = 0;
594
595 if (getegid() == st.st_gid)
596 grpmatch = 1;
597 else {
598 gid_t groups[32];
599 int ngrp = getgroups(32, groups);
600 int i;
601
602 for(i = 0; i < ngrp; i++)
603 if (groups[i] == st.st_gid) {
604 grpmatch = 1;
605 break;
606 }
607 }
608
609 if (grpmatch) {
610 if (!(st.st_mode & S_IXGRP))
611 return EACCES;
612 } else if (!(st.st_mode & S_IXOTH))
613 return EACCES;
614 }
615
616 return 0;
617}
618
fitzhardinge7e343cd2003-12-16 02:14:00 +0000619static int do_exec_inner(const char *exe, struct exeinfo *info)
620{
621 int fd;
fitzhardinged2e37112004-09-09 08:10:42 +0000622 int err;
nethercote73b526f2004-10-31 18:48:21 +0000623 char buf[VKI_PAGE_SIZE];
fitzhardinge7e343cd2003-12-16 02:14:00 +0000624 int bufsz;
625 int i;
626 int ret;
nethercote31779c72004-07-30 21:50:15 +0000627 static const struct {
628 int (*match)(const char *hdr, int len);
629 int (*load) ( char *hdr, int len, int fd2, const char *name,
630 struct exeinfo *);
631 } formats[] = {
632 { match_ELF, load_ELF },
633 { match_script, load_script },
634 };
fitzhardinge7e343cd2003-12-16 02:14:00 +0000635
636 fd = open(exe, O_RDONLY);
637 if (fd == -1) {
638 if (0)
639 fprintf(stderr, "Can't open executable %s: %s\n",
640 exe, strerror(errno));
641 return errno;
642 }
643
fitzhardinged2e37112004-09-09 08:10:42 +0000644 err = check_perms(fd);
fitzhardingefd7da3a2004-09-08 20:05:29 +0000645 if (err != 0) {
646 close(fd);
647 return err;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000648 }
649
650 bufsz = pread(fd, buf, sizeof(buf), 0);
651 if (bufsz < 0) {
652 fprintf(stderr, "Can't read executable header: %s\n",
653 strerror(errno));
654 close(fd);
655 return errno;
656 }
657
658 ret = ENOEXEC;
659 for(i = 0; i < sizeof(formats)/sizeof(*formats); i++) {
660 if ((formats[i].match)(buf, bufsz)) {
661 ret = (formats[i].load)(buf, bufsz, fd, exe, info);
662 break;
663 }
664 }
665
666 close(fd);
667
668 return ret;
669}
670
nethercoteea147e72004-07-26 15:43:57 +0000671// See ume.h for an indication of which entries of 'info' are inputs, which
672// are outputs, and which are both.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000673int do_exec(const char *exe, struct exeinfo *info)
674{
nethercoted6a56872004-07-26 15:32:47 +0000675 info->interp_name = NULL;
676 info->interp_args = NULL;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000677
678 return do_exec_inner(exe, info);
679}
nethercotebb1c9912004-01-04 16:43:23 +0000680
681/*--------------------------------------------------------------------*/
682/*--- end ume.c ---*/
683/*--------------------------------------------------------------------*/