blob: 939392162656d15a27e3fbe6f41c844bf5f2f69f [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"
48
nethercote3f458152004-11-01 18:42:23 +000049#if ELFSZ == 64
50#define ESZ(x) Elf64_##x
51#elif ELFSZ == 32
52#define ESZ(x) Elf32_##x
53#else
54#error ELFSZ needs to ==32 or ==64
55#endif
56
nethercote1fe54502004-07-26 15:28:33 +000057struct elfinfo
58{
59 ESZ(Ehdr) e;
60 ESZ(Phdr) *p;
61 int fd;
62};
63
nethercote30d37842004-07-26 10:05:55 +000064static void check_mmap(void* res, void* base, int len)
nethercotebfed1c82004-07-17 12:57:44 +000065{
66 if ((void*)-1 == res) {
nethercote969ecf12004-10-13 17:29:01 +000067 fprintf(stderr, "valgrind: mmap(%p, %d) failed in UME.\n", base, len);
nethercotebfed1c82004-07-17 12:57:44 +000068 exit(1);
69 }
70}
71
nethercote31779c72004-07-30 21:50:15 +000072// 'extra' allows the caller to pass in extra args to 'fn', like free
73// variables to a closure.
74void foreach_map(int (*fn)(char *start, char *end,
fitzhardinge7e343cd2003-12-16 02:14:00 +000075 const char *perm, off_t offset,
nethercote31779c72004-07-30 21:50:15 +000076 int maj, int min, int ino, void* extra),
77 void* extra)
fitzhardinge7e343cd2003-12-16 02:14:00 +000078{
79 static char buf[10240];
80 char *bufptr = buf;
81 int ret, fd;
82
83 fd = open("/proc/self/maps", O_RDONLY);
84
85 if (fd == -1) {
86 perror("open /proc/self/maps");
87 return;
88 }
89
90 ret = read(fd, buf, sizeof(buf));
91
92 if (ret == -1) {
93 perror("read /proc/self/maps");
94 close(fd);
95 return;
96 }
97 close(fd);
98
99 if (ret == sizeof(buf)) {
100 fprintf(stderr, "buf too small\n");
101 return;
102 }
103
104 while(bufptr && bufptr < buf+ret) {
105 char perm[5];
njnc6168192004-11-29 13:54:10 +0000106 ULong offset;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000107 int maj, min;
108 int ino;
109 void *segstart, *segend;
110
nethercote545fe672004-11-01 16:52:43 +0000111 sscanf(bufptr, "%p-%p %s %llx %x:%x %d",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000112 &segstart, &segend, perm, &offset, &maj, &min, &ino);
113 bufptr = strchr(bufptr, '\n');
114 if (bufptr != NULL)
115 bufptr++; /* skip \n */
116
nethercote31779c72004-07-30 21:50:15 +0000117 if (!(*fn)(segstart, segend, perm, offset, maj, min, ino, extra))
fitzhardinge7e343cd2003-12-16 02:14:00 +0000118 break;
119 }
120}
121
nethercote31779c72004-07-30 21:50:15 +0000122/*------------------------------------------------------------*/
123/*--- Finding auxv on the stack ---*/
124/*------------------------------------------------------------*/
fitzhardinge7e343cd2003-12-16 02:14:00 +0000125
nethercoteebf1d862004-11-01 18:22:05 +0000126struct ume_auxv *find_auxv(UWord* sp)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000127{
nethercoteebf1d862004-11-01 18:22:05 +0000128 sp++; // skip argc (Nb: is word-sized, not int-sized!)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000129
nethercoteebf1d862004-11-01 18:22:05 +0000130 while (*sp != 0) // skip argv
131 sp++;
132 sp++;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000133
nethercoteebf1d862004-11-01 18:22:05 +0000134 while (*sp != 0) // skip env
135 sp++;
136 sp++;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000137
nethercoteebf1d862004-11-01 18:22:05 +0000138 return (struct ume_auxv *)sp;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000139}
140
nethercote31779c72004-07-30 21:50:15 +0000141/*------------------------------------------------------------*/
142/*--- Loading ELF files ---*/
143/*------------------------------------------------------------*/
fitzhardinge7e343cd2003-12-16 02:14:00 +0000144
sewardj2c5ffbe2005-03-12 13:32:06 +0000145static
fitzhardinge7e343cd2003-12-16 02:14:00 +0000146struct elfinfo *readelf(int fd, const char *filename)
147{
148 struct elfinfo *e = malloc(sizeof(*e));
149 int phsz;
150
nethercote7c018f42004-07-17 16:40:50 +0000151 assert(e);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000152 e->fd = fd;
153
154 if (pread(fd, &e->e, sizeof(e->e), 0) != sizeof(e->e)) {
sewardj703eec52005-04-07 02:24:23 +0000155 fprintf(stderr, "valgrind: %s: can't read ELF header: %s\n",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000156 filename, strerror(errno));
157 return NULL;
158 }
159
160 if (memcmp(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) {
sewardj703eec52005-04-07 02:24:23 +0000161 fprintf(stderr, "valgrind: %s: bad ELF magic number\n", filename);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000162 return NULL;
163 }
njn35172bc2005-03-26 00:04:03 +0000164 if (e->e.e_ident[EI_CLASS] != VGA_ELF_CLASS) {
sewardj703eec52005-04-07 02:24:23 +0000165 fprintf(stderr,
166 "valgrind: wrong ELF executable class "
167 "(eg. 32-bit instead of 64-bit)\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000168 return NULL;
169 }
njn35172bc2005-03-26 00:04:03 +0000170 if (e->e.e_ident[EI_DATA] != VGA_ELF_ENDIANNESS) {
sewardj703eec52005-04-07 02:24:23 +0000171 fprintf(stderr, "valgrind: executable has wrong endian-ness\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000172 return NULL;
173 }
174 if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) {
sewardj703eec52005-04-07 02:24:23 +0000175 fprintf(stderr, "valgrind: this is not an executable\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000176 return NULL;
177 }
178
njn35172bc2005-03-26 00:04:03 +0000179 if (e->e.e_machine != VGA_ELF_MACHINE) {
sewardj703eec52005-04-07 02:24:23 +0000180 fprintf(stderr, "valgrind: executable is not for "
181 "this architecture\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000182 return NULL;
183 }
184
185 if (e->e.e_phentsize != sizeof(ESZ(Phdr))) {
sewardj703eec52005-04-07 02:24:23 +0000186 fprintf(stderr, "valgrind: sizeof ELF Phdr wrong\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000187 return NULL;
188 }
189
190 phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum;
191 e->p = malloc(phsz);
nethercote7c018f42004-07-17 16:40:50 +0000192 assert(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000193
194 if (pread(fd, e->p, phsz, e->e.e_phoff) != phsz) {
nethercote08eaff32004-07-22 12:41:12 +0000195 fprintf(stderr, "valgrind: can't read phdr: %s\n", strerror(errno));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000196 return NULL;
197 }
198
199 return e;
200}
201
fitzhardinge7e343cd2003-12-16 02:14:00 +0000202/* Map an ELF file. Returns the brk address. */
sewardj2c5ffbe2005-03-12 13:32:06 +0000203static
fitzhardingeb50068f2004-02-24 23:42:55 +0000204ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000205{
206 int i;
nethercotebfed1c82004-07-17 12:57:44 +0000207 void* res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000208 ESZ(Addr) elfbrk = 0;
209
210 for(i = 0; i < e->e.e_phnum; i++) {
211 ESZ(Phdr) *ph = &e->p[i];
212 ESZ(Addr) addr, brkaddr;
213 ESZ(Word) memsz;
214
215 if (ph->p_type != PT_LOAD)
216 continue;
217
nethercote6c3cf412004-10-26 13:32:11 +0000218 addr = ph->p_vaddr+base;
219 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000220 brkaddr = addr+memsz;
221
222 if (brkaddr > elfbrk)
223 elfbrk = brkaddr;
224 }
225
fitzhardinge7e343cd2003-12-16 02:14:00 +0000226 for(i = 0; i < e->e.e_phnum; i++) {
227 ESZ(Phdr) *ph = &e->p[i];
228 ESZ(Addr) addr, bss, brkaddr;
229 ESZ(Off) off;
230 ESZ(Word) filesz;
231 ESZ(Word) memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000232 unsigned prot = 0;
233
234 if (ph->p_type != PT_LOAD)
235 continue;
236
nethercote6c3cf412004-10-26 13:32:11 +0000237 if (ph->p_flags & PF_X) prot |= PROT_EXEC;
238 if (ph->p_flags & PF_W) prot |= PROT_WRITE;
239 if (ph->p_flags & PF_R) prot |= PROT_READ;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000240
nethercote6c3cf412004-10-26 13:32:11 +0000241 addr = ph->p_vaddr+base;
242 off = ph->p_offset;
243 filesz = ph->p_filesz;
244 bss = addr+filesz;
245 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000246 brkaddr = addr+memsz;
247
njnf7fbe6c2004-11-30 11:40:24 +0000248 // Tom says: In the following, do what the Linux kernel does and only
249 // map the pages that are required instead of rounding everything to
250 // the specified alignment (ph->p_align). (AMD64 doesn't work if you
251 // use ph->p_align -- part of stage2's memory gets trashed somehow.)
njn098da062005-03-26 16:22:43 +0000252 //
253 // The condition handles the case of a zero-length segment.
njn13bfd852005-06-02 03:52:53 +0000254 if (VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr) > 0) {
255 res = mmap((char *)VG_PGROUNDDN(addr),
256 VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr),
257 prot, MAP_FIXED|MAP_PRIVATE, e->fd, VG_PGROUNDDN(off));
258 check_mmap(res, (char*)VG_PGROUNDDN(addr),
259 VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr));
njn098da062005-03-26 16:22:43 +0000260 }
njnf7fbe6c2004-11-30 11:40:24 +0000261
262 // if memsz > filesz, fill the remainder with zeroed pages
fitzhardinge7e343cd2003-12-16 02:14:00 +0000263 if (memsz > filesz) {
264 UInt bytes;
265
njn13bfd852005-06-02 03:52:53 +0000266 bytes = VG_PGROUNDUP(brkaddr)-VG_PGROUNDUP(bss);
nethercotebfed1c82004-07-17 12:57:44 +0000267 if (bytes > 0) {
njn13bfd852005-06-02 03:52:53 +0000268 res = mmap((char *)VG_PGROUNDUP(bss), bytes,
nethercotebfed1c82004-07-17 12:57:44 +0000269 prot, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
njn13bfd852005-06-02 03:52:53 +0000270 check_mmap(res, (char*)VG_PGROUNDUP(bss), bytes);
nethercotebfed1c82004-07-17 12:57:44 +0000271 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000272
nethercote73b526f2004-10-31 18:48:21 +0000273 bytes = bss & (VKI_PAGE_SIZE - 1);
njn098da062005-03-26 16:22:43 +0000274
275 // The 'prot' condition allows for a read-only bss
276 if ((prot & PROT_WRITE) && (bytes > 0)) {
nethercote73b526f2004-10-31 18:48:21 +0000277 bytes = VKI_PAGE_SIZE - bytes;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000278 memset((char *)bss, 0, bytes);
279 }
280 }
281 }
282
283 return elfbrk;
284}
285
nethercote31779c72004-07-30 21:50:15 +0000286// Forward declaration.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000287static int do_exec_inner(const char *exe, struct exeinfo *info);
288
fitzhardinge7e343cd2003-12-16 02:14:00 +0000289static int match_ELF(const char *hdr, int len)
290{
291 ESZ(Ehdr) *e = (ESZ(Ehdr) *)hdr;
292 return (len > sizeof(*e)) && memcmp(&e->e_ident[0], ELFMAG, SELFMAG) == 0;
293}
294
nethercote31779c72004-07-30 21:50:15 +0000295static int load_ELF(char *hdr, int len, int fd, const char *name,
296 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000297{
298 struct elfinfo *e;
299 struct elfinfo *interp = NULL;
fitzhardingeca9bd9c2004-09-08 20:05:02 +0000300 ESZ(Addr) minaddr = ~0; /* lowest mapped address */
301 ESZ(Addr) maxaddr = 0; /* highest mapped address */
302 ESZ(Addr) interp_addr = 0; /* interpreter (ld.so) address */
303 ESZ(Word) interp_size = 0; /* interpreter size */
nethercote73b526f2004-10-31 18:48:21 +0000304 ESZ(Word) interp_align = VKI_PAGE_SIZE;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000305 int i;
306 void *entry;
nethercote7f390022004-10-25 17:18:24 +0000307 ESZ(Addr) ebase = 0;
308
309#ifdef HAVE_PIE
310 ebase = info->exe_base;
311#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000312
313 e = readelf(fd, name);
314
315 if (e == NULL)
316 return ENOEXEC;
317
318 info->phnum = e->e.e_phnum;
nethercote7f390022004-10-25 17:18:24 +0000319 info->entry = e->e.e_entry + ebase;
sewardjb5f6f512005-03-10 23:59:00 +0000320 info->phdr = 0;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000321
322 for(i = 0; i < e->e.e_phnum; i++) {
323 ESZ(Phdr) *ph = &e->p[i];
324
325 switch(ph->p_type) {
326 case PT_PHDR:
nethercote7f390022004-10-25 17:18:24 +0000327 info->phdr = ph->p_vaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000328 break;
329
330 case PT_LOAD:
331 if (ph->p_vaddr < minaddr)
332 minaddr = ph->p_vaddr;
333 if (ph->p_vaddr+ph->p_memsz > maxaddr)
334 maxaddr = ph->p_vaddr+ph->p_memsz;
335 break;
336
337 case PT_INTERP: {
338 char *buf = malloc(ph->p_filesz+1);
339 int j;
340 int intfd;
341 int baseaddr_set;
342
nethercote7c018f42004-07-17 16:40:50 +0000343 assert(buf);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000344 pread(fd, buf, ph->p_filesz, ph->p_offset);
345 buf[ph->p_filesz] = '\0';
346
347 intfd = open(buf, O_RDONLY);
348 if (intfd == -1) {
349 perror("open interp");
350 exit(1);
351 }
352
353 interp = readelf(intfd, buf);
354 if (interp == NULL) {
355 fprintf(stderr, "Can't read interpreter\n");
356 return 1;
357 }
358 free(buf);
359
360 baseaddr_set = 0;
361 for(j = 0; j < interp->e.e_phnum; j++) {
362 ESZ(Phdr) *iph = &interp->p[j];
363 ESZ(Addr) end;
364
365 if (iph->p_type != PT_LOAD)
366 continue;
367
368 if (!baseaddr_set) {
nethercote7f390022004-10-25 17:18:24 +0000369 interp_addr = iph->p_vaddr;
370 interp_align = iph->p_align;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000371 baseaddr_set = 1;
372 }
373
374 /* assumes that all segments in the interp are close */
375 end = (iph->p_vaddr - interp_addr) + iph->p_memsz;
376
377 if (end > interp_size)
378 interp_size = end;
379 }
380 break;
nethercoteb24cbc82004-09-03 23:25:33 +0000381
382 default:
383 // do nothing
384 break;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000385 }
386 }
387 }
388
sewardjb5f6f512005-03-10 23:59:00 +0000389 if (info->phdr == 0)
390 info->phdr = minaddr + e->e.e_phoff;
391
fitzhardinge7e343cd2003-12-16 02:14:00 +0000392 if (info->exe_base != info->exe_end) {
393 if (minaddr >= maxaddr ||
nethercote7f390022004-10-25 17:18:24 +0000394 (minaddr + ebase < info->exe_base ||
395 maxaddr + ebase > info->exe_end)) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000396 fprintf(stderr, "Executable range %p-%p is outside the\n"
397 "acceptable range %p-%p\n",
nethercote7f390022004-10-25 17:18:24 +0000398 (void *)minaddr + ebase, (void *)maxaddr + ebase,
399 (void *)info->exe_base, (void *)info->exe_end);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000400 return ENOMEM;
401 }
402 }
403
nethercote7f390022004-10-25 17:18:24 +0000404 info->brkbase = mapelf(e, ebase); /* map the executable */
fitzhardinge7e343cd2003-12-16 02:14:00 +0000405
fitzhardinge92360792003-12-24 10:11:11 +0000406 if (info->brkbase == 0)
407 return ENOMEM;
408
fitzhardinge7e343cd2003-12-16 02:14:00 +0000409 if (interp != NULL) {
410 /* reserve a chunk of address space for interpreter */
nethercotebfed1c82004-07-17 12:57:44 +0000411 void* res;
412 char* base = (char *)info->exe_base;
413 char* baseoff;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000414 int flags = MAP_PRIVATE|MAP_ANONYMOUS;
415
416 if (info->map_base != 0) {
njn13bfd852005-06-02 03:52:53 +0000417 base = (char *)VG_ROUNDUP(info->map_base, interp_align);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000418 flags |= MAP_FIXED;
419 }
420
nethercotebfed1c82004-07-17 12:57:44 +0000421 res = mmap(base, interp_size, PROT_NONE, flags, -1, 0);
422 check_mmap(res, base, interp_size);
423 base = res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000424
425 baseoff = base - interp_addr;
426
fitzhardingeb50068f2004-02-24 23:42:55 +0000427 mapelf(interp, (ESZ(Addr))baseoff);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000428
429 close(interp->fd);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000430
431 entry = baseoff + interp->e.e_entry;
432 info->interp_base = (ESZ(Addr))base;
thughes54d08592004-09-26 14:42:47 +0000433
sewardjb5f6f512005-03-10 23:59:00 +0000434 free(interp->p);
thughes54d08592004-09-26 14:42:47 +0000435 free(interp);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000436 } else
nethercote7f390022004-10-25 17:18:24 +0000437 entry = (void *)e->e.e_entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000438
nethercote7f390022004-10-25 17:18:24 +0000439 info->exe_base = minaddr + ebase;
440 info->exe_end = maxaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000441
nethercotea3c3cf22004-11-01 18:38:00 +0000442 info->init_eip = (Addr)entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000443
sewardjb5f6f512005-03-10 23:59:00 +0000444 free(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000445 free(e);
446
447 return 0;
448}
449
450
451static int match_script(const char *hdr, Int len)
452{
453 return (len > 2) && memcmp(hdr, "#!", 2) == 0;
454}
455
nethercote31779c72004-07-30 21:50:15 +0000456static int load_script(char *hdr, int len, int fd, const char *name,
457 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000458{
459 char *interp;
460 char *const end = hdr+len;
461 char *cp;
462 char *arg = NULL;
463 int eol;
464
465 interp = hdr + 2;
466 while(interp < end && (*interp == ' ' || *interp == '\t'))
467 interp++;
468
469 if (*interp != '/')
470 return ENOEXEC; /* absolute path only for interpreter */
471
472 /* skip over interpreter name */
473 for(cp = interp; cp < end && *cp != ' ' && *cp != '\t' && *cp != '\n'; cp++)
474 ;
475
476 eol = (*cp == '\n');
477
478 *cp++ = '\0';
479
480 if (!eol && cp < end) {
481 /* skip space before arg */
482 while (cp < end && (*cp == '\t' || *cp == ' '))
483 cp++;
484
485 /* arg is from here to eol */
486 arg = cp;
487 while (cp < end && *cp != '\n')
488 cp++;
489 *cp = '\0';
490 }
491
nethercoted6a56872004-07-26 15:32:47 +0000492 info->interp_name = strdup(interp);
493 assert(NULL != info->interp_name);
nethercote71980f02004-01-24 18:18:54 +0000494 if (arg != NULL && *arg != '\0') {
nethercoted6a56872004-07-26 15:32:47 +0000495 info->interp_args = strdup(arg);
496 assert(NULL != info->interp_args);
nethercote71980f02004-01-24 18:18:54 +0000497 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000498
499 if (info->argv && info->argv[0] != NULL)
500 info->argv[0] = (char *)name;
501
502 if (0)
nethercoted6a56872004-07-26 15:32:47 +0000503 printf("#! script: interp_name=\"%s\" interp_args=\"%s\"\n",
504 info->interp_name, info->interp_args);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000505
506 return do_exec_inner(interp, info);
507}
508
fitzhardingefd7da3a2004-09-08 20:05:29 +0000509/*
510 Emulate the normal Unix permissions checking algorithm.
511
512 If owner matches, then use the owner permissions, else
513 if group matches, then use the group permissions, else
514 use other permissions.
515
516 Note that we can't deal with SUID/SGID, so we refuse to run them
517 (otherwise the executable may misbehave if it doesn't have the
518 permissions it thinks it does).
519*/
520static int check_perms(int fd)
521{
522 struct stat st;
523
524 if (fstat(fd, &st) == -1)
525 return errno;
526
527 if (st.st_mode & (S_ISUID | S_ISGID)) {
528 //fprintf(stderr, "Can't execute suid/sgid executable %s\n", exe);
529 return EACCES;
530 }
531
532 if (geteuid() == st.st_uid) {
533 if (!(st.st_mode & S_IXUSR))
534 return EACCES;
535 } else {
536 int grpmatch = 0;
537
538 if (getegid() == st.st_gid)
539 grpmatch = 1;
540 else {
541 gid_t groups[32];
542 int ngrp = getgroups(32, groups);
543 int i;
544
545 for(i = 0; i < ngrp; i++)
546 if (groups[i] == st.st_gid) {
547 grpmatch = 1;
548 break;
549 }
550 }
551
552 if (grpmatch) {
553 if (!(st.st_mode & S_IXGRP))
554 return EACCES;
555 } else if (!(st.st_mode & S_IXOTH))
556 return EACCES;
557 }
558
559 return 0;
560}
561
fitzhardinge7e343cd2003-12-16 02:14:00 +0000562static int do_exec_inner(const char *exe, struct exeinfo *info)
563{
564 int fd;
fitzhardinged2e37112004-09-09 08:10:42 +0000565 int err;
nethercote73b526f2004-10-31 18:48:21 +0000566 char buf[VKI_PAGE_SIZE];
fitzhardinge7e343cd2003-12-16 02:14:00 +0000567 int bufsz;
568 int i;
569 int ret;
nethercote31779c72004-07-30 21:50:15 +0000570 static const struct {
571 int (*match)(const char *hdr, int len);
572 int (*load) ( char *hdr, int len, int fd2, const char *name,
573 struct exeinfo *);
574 } formats[] = {
575 { match_ELF, load_ELF },
576 { match_script, load_script },
577 };
fitzhardinge7e343cd2003-12-16 02:14:00 +0000578
579 fd = open(exe, O_RDONLY);
580 if (fd == -1) {
581 if (0)
582 fprintf(stderr, "Can't open executable %s: %s\n",
583 exe, strerror(errno));
584 return errno;
585 }
586
fitzhardinged2e37112004-09-09 08:10:42 +0000587 err = check_perms(fd);
fitzhardingefd7da3a2004-09-08 20:05:29 +0000588 if (err != 0) {
589 close(fd);
590 return err;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000591 }
592
593 bufsz = pread(fd, buf, sizeof(buf), 0);
594 if (bufsz < 0) {
595 fprintf(stderr, "Can't read executable header: %s\n",
596 strerror(errno));
597 close(fd);
598 return errno;
599 }
600
601 ret = ENOEXEC;
602 for(i = 0; i < sizeof(formats)/sizeof(*formats); i++) {
603 if ((formats[i].match)(buf, bufsz)) {
604 ret = (formats[i].load)(buf, bufsz, fd, exe, info);
605 break;
606 }
607 }
608
609 close(fd);
610
611 return ret;
612}
613
nethercoteea147e72004-07-26 15:43:57 +0000614// See ume.h for an indication of which entries of 'info' are inputs, which
615// are outputs, and which are both.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000616int do_exec(const char *exe, struct exeinfo *info)
617{
nethercoted6a56872004-07-26 15:32:47 +0000618 info->interp_name = NULL;
619 info->interp_args = NULL;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000620
621 return do_exec_inner(exe, info);
622}
nethercotebb1c9912004-01-04 16:43:23 +0000623
624/*--------------------------------------------------------------------*/
625/*--- end ume.c ---*/
626/*--------------------------------------------------------------------*/