blob: cf526c3c4534a01687f70cc7206d00da9741445a [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)) {
nethercote08eaff32004-07-22 12:41:12 +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) {
nethercote08eaff32004-07-22 12:41:12 +0000161 fprintf(stderr, "valgrind: %s: bad ELF magic\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) {
nethercotebdaa89f2004-10-09 19:08:08 +0000165 fprintf(stderr, "valgrind: wrong executable class (eg. 32-bit instead\n"
166 "valgrind: of 64-bit)\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000167 return NULL;
168 }
njn35172bc2005-03-26 00:04:03 +0000169 if (e->e.e_ident[EI_DATA] != VGA_ELF_ENDIANNESS) {
nethercotebdaa89f2004-10-09 19:08:08 +0000170 fprintf(stderr, "valgrind: wrong endian-ness\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000171 return NULL;
172 }
173 if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) {
nethercote08eaff32004-07-22 12:41:12 +0000174 fprintf(stderr, "valgrind: need executable\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000175 return NULL;
176 }
177
njn35172bc2005-03-26 00:04:03 +0000178 if (e->e.e_machine != VGA_ELF_MACHINE) {
nethercotebdaa89f2004-10-09 19:08:08 +0000179 fprintf(stderr, "valgrind: wrong architecture\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000180 return NULL;
181 }
182
183 if (e->e.e_phentsize != sizeof(ESZ(Phdr))) {
nethercote08eaff32004-07-22 12:41:12 +0000184 fprintf(stderr, "valgrind: sizeof Phdr wrong\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000185 return NULL;
186 }
187
188 phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum;
189 e->p = malloc(phsz);
nethercote7c018f42004-07-17 16:40:50 +0000190 assert(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000191
192 if (pread(fd, e->p, phsz, e->e.e_phoff) != phsz) {
nethercote08eaff32004-07-22 12:41:12 +0000193 fprintf(stderr, "valgrind: can't read phdr: %s\n", strerror(errno));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000194 return NULL;
195 }
196
197 return e;
198}
199
fitzhardinge7e343cd2003-12-16 02:14:00 +0000200/* Map an ELF file. Returns the brk address. */
sewardj2c5ffbe2005-03-12 13:32:06 +0000201static
fitzhardingeb50068f2004-02-24 23:42:55 +0000202ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000203{
204 int i;
nethercotebfed1c82004-07-17 12:57:44 +0000205 void* res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000206 ESZ(Addr) elfbrk = 0;
207
208 for(i = 0; i < e->e.e_phnum; i++) {
209 ESZ(Phdr) *ph = &e->p[i];
210 ESZ(Addr) addr, brkaddr;
211 ESZ(Word) memsz;
212
213 if (ph->p_type != PT_LOAD)
214 continue;
215
nethercote6c3cf412004-10-26 13:32:11 +0000216 addr = ph->p_vaddr+base;
217 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000218 brkaddr = addr+memsz;
219
220 if (brkaddr > elfbrk)
221 elfbrk = brkaddr;
222 }
223
fitzhardinge7e343cd2003-12-16 02:14:00 +0000224 for(i = 0; i < e->e.e_phnum; i++) {
225 ESZ(Phdr) *ph = &e->p[i];
226 ESZ(Addr) addr, bss, brkaddr;
227 ESZ(Off) off;
228 ESZ(Word) filesz;
229 ESZ(Word) memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000230 unsigned prot = 0;
231
232 if (ph->p_type != PT_LOAD)
233 continue;
234
nethercote6c3cf412004-10-26 13:32:11 +0000235 if (ph->p_flags & PF_X) prot |= PROT_EXEC;
236 if (ph->p_flags & PF_W) prot |= PROT_WRITE;
237 if (ph->p_flags & PF_R) prot |= PROT_READ;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000238
nethercote6c3cf412004-10-26 13:32:11 +0000239 addr = ph->p_vaddr+base;
240 off = ph->p_offset;
241 filesz = ph->p_filesz;
242 bss = addr+filesz;
243 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000244 brkaddr = addr+memsz;
245
njnf7fbe6c2004-11-30 11:40:24 +0000246 // Tom says: In the following, do what the Linux kernel does and only
247 // map the pages that are required instead of rounding everything to
248 // the specified alignment (ph->p_align). (AMD64 doesn't work if you
249 // use ph->p_align -- part of stage2's memory gets trashed somehow.)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000250
njnf7fbe6c2004-11-30 11:40:24 +0000251 res = mmap((char *)PGROUNDDN(addr), PGROUNDUP(bss)-PGROUNDDN(addr),
252 prot, MAP_FIXED|MAP_PRIVATE, e->fd, PGROUNDDN(off));
253 check_mmap(res, (char*)PGROUNDDN(addr),
254 PGROUNDUP(bss)-PGROUNDDN(addr));
255
256 // if memsz > filesz, fill the remainder with zeroed pages
fitzhardinge7e343cd2003-12-16 02:14:00 +0000257 if (memsz > filesz) {
258 UInt bytes;
259
njnf7fbe6c2004-11-30 11:40:24 +0000260 bytes = PGROUNDUP(brkaddr)-PGROUNDUP(bss);
nethercotebfed1c82004-07-17 12:57:44 +0000261 if (bytes > 0) {
njnf7fbe6c2004-11-30 11:40:24 +0000262 res = mmap((char *)PGROUNDUP(bss), bytes,
nethercotebfed1c82004-07-17 12:57:44 +0000263 prot, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
njnf7fbe6c2004-11-30 11:40:24 +0000264 check_mmap(res, (char*)PGROUNDUP(bss), bytes);
nethercotebfed1c82004-07-17 12:57:44 +0000265 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000266
nethercote73b526f2004-10-31 18:48:21 +0000267 bytes = bss & (VKI_PAGE_SIZE - 1);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000268 if (bytes > 0) {
nethercote73b526f2004-10-31 18:48:21 +0000269 bytes = VKI_PAGE_SIZE - bytes;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000270 memset((char *)bss, 0, bytes);
271 }
272 }
273 }
274
275 return elfbrk;
276}
277
nethercote31779c72004-07-30 21:50:15 +0000278// Forward declaration.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000279static int do_exec_inner(const char *exe, struct exeinfo *info);
280
fitzhardinge7e343cd2003-12-16 02:14:00 +0000281static int match_ELF(const char *hdr, int len)
282{
283 ESZ(Ehdr) *e = (ESZ(Ehdr) *)hdr;
284 return (len > sizeof(*e)) && memcmp(&e->e_ident[0], ELFMAG, SELFMAG) == 0;
285}
286
nethercote31779c72004-07-30 21:50:15 +0000287static int load_ELF(char *hdr, int len, int fd, const char *name,
288 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000289{
290 struct elfinfo *e;
291 struct elfinfo *interp = NULL;
fitzhardingeca9bd9c2004-09-08 20:05:02 +0000292 ESZ(Addr) minaddr = ~0; /* lowest mapped address */
293 ESZ(Addr) maxaddr = 0; /* highest mapped address */
294 ESZ(Addr) interp_addr = 0; /* interpreter (ld.so) address */
295 ESZ(Word) interp_size = 0; /* interpreter size */
nethercote73b526f2004-10-31 18:48:21 +0000296 ESZ(Word) interp_align = VKI_PAGE_SIZE;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000297 int i;
298 void *entry;
nethercote7f390022004-10-25 17:18:24 +0000299 ESZ(Addr) ebase = 0;
300
301#ifdef HAVE_PIE
302 ebase = info->exe_base;
303#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000304
305 e = readelf(fd, name);
306
307 if (e == NULL)
308 return ENOEXEC;
309
310 info->phnum = e->e.e_phnum;
nethercote7f390022004-10-25 17:18:24 +0000311 info->entry = e->e.e_entry + ebase;
sewardjb5f6f512005-03-10 23:59:00 +0000312 info->phdr = 0;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000313
314 for(i = 0; i < e->e.e_phnum; i++) {
315 ESZ(Phdr) *ph = &e->p[i];
316
317 switch(ph->p_type) {
318 case PT_PHDR:
nethercote7f390022004-10-25 17:18:24 +0000319 info->phdr = ph->p_vaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000320 break;
321
322 case PT_LOAD:
323 if (ph->p_vaddr < minaddr)
324 minaddr = ph->p_vaddr;
325 if (ph->p_vaddr+ph->p_memsz > maxaddr)
326 maxaddr = ph->p_vaddr+ph->p_memsz;
327 break;
328
329 case PT_INTERP: {
330 char *buf = malloc(ph->p_filesz+1);
331 int j;
332 int intfd;
333 int baseaddr_set;
334
nethercote7c018f42004-07-17 16:40:50 +0000335 assert(buf);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000336 pread(fd, buf, ph->p_filesz, ph->p_offset);
337 buf[ph->p_filesz] = '\0';
338
339 intfd = open(buf, O_RDONLY);
340 if (intfd == -1) {
341 perror("open interp");
342 exit(1);
343 }
344
345 interp = readelf(intfd, buf);
346 if (interp == NULL) {
347 fprintf(stderr, "Can't read interpreter\n");
348 return 1;
349 }
350 free(buf);
351
352 baseaddr_set = 0;
353 for(j = 0; j < interp->e.e_phnum; j++) {
354 ESZ(Phdr) *iph = &interp->p[j];
355 ESZ(Addr) end;
356
357 if (iph->p_type != PT_LOAD)
358 continue;
359
360 if (!baseaddr_set) {
nethercote7f390022004-10-25 17:18:24 +0000361 interp_addr = iph->p_vaddr;
362 interp_align = iph->p_align;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000363 baseaddr_set = 1;
364 }
365
366 /* assumes that all segments in the interp are close */
367 end = (iph->p_vaddr - interp_addr) + iph->p_memsz;
368
369 if (end > interp_size)
370 interp_size = end;
371 }
372 break;
nethercoteb24cbc82004-09-03 23:25:33 +0000373
374 default:
375 // do nothing
376 break;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000377 }
378 }
379 }
380
sewardjb5f6f512005-03-10 23:59:00 +0000381 if (info->phdr == 0)
382 info->phdr = minaddr + e->e.e_phoff;
383
fitzhardinge7e343cd2003-12-16 02:14:00 +0000384 if (info->exe_base != info->exe_end) {
385 if (minaddr >= maxaddr ||
nethercote7f390022004-10-25 17:18:24 +0000386 (minaddr + ebase < info->exe_base ||
387 maxaddr + ebase > info->exe_end)) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000388 fprintf(stderr, "Executable range %p-%p is outside the\n"
389 "acceptable range %p-%p\n",
nethercote7f390022004-10-25 17:18:24 +0000390 (void *)minaddr + ebase, (void *)maxaddr + ebase,
391 (void *)info->exe_base, (void *)info->exe_end);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000392 return ENOMEM;
393 }
394 }
395
nethercote7f390022004-10-25 17:18:24 +0000396 info->brkbase = mapelf(e, ebase); /* map the executable */
fitzhardinge7e343cd2003-12-16 02:14:00 +0000397
fitzhardinge92360792003-12-24 10:11:11 +0000398 if (info->brkbase == 0)
399 return ENOMEM;
400
fitzhardinge7e343cd2003-12-16 02:14:00 +0000401 if (interp != NULL) {
402 /* reserve a chunk of address space for interpreter */
nethercotebfed1c82004-07-17 12:57:44 +0000403 void* res;
404 char* base = (char *)info->exe_base;
405 char* baseoff;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000406 int flags = MAP_PRIVATE|MAP_ANONYMOUS;
407
408 if (info->map_base != 0) {
nethercote7f390022004-10-25 17:18:24 +0000409 base = (char *)ROUNDUP(info->map_base, interp_align);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000410 flags |= MAP_FIXED;
411 }
412
nethercotebfed1c82004-07-17 12:57:44 +0000413 res = mmap(base, interp_size, PROT_NONE, flags, -1, 0);
414 check_mmap(res, base, interp_size);
415 base = res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000416
417 baseoff = base - interp_addr;
418
fitzhardingeb50068f2004-02-24 23:42:55 +0000419 mapelf(interp, (ESZ(Addr))baseoff);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000420
421 close(interp->fd);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000422
423 entry = baseoff + interp->e.e_entry;
424 info->interp_base = (ESZ(Addr))base;
thughes54d08592004-09-26 14:42:47 +0000425
sewardjb5f6f512005-03-10 23:59:00 +0000426 free(interp->p);
thughes54d08592004-09-26 14:42:47 +0000427 free(interp);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000428 } else
nethercote7f390022004-10-25 17:18:24 +0000429 entry = (void *)e->e.e_entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000430
nethercote7f390022004-10-25 17:18:24 +0000431 info->exe_base = minaddr + ebase;
432 info->exe_end = maxaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000433
nethercotea3c3cf22004-11-01 18:38:00 +0000434 info->init_eip = (Addr)entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000435
sewardjb5f6f512005-03-10 23:59:00 +0000436 free(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000437 free(e);
438
439 return 0;
440}
441
442
443static int match_script(const char *hdr, Int len)
444{
445 return (len > 2) && memcmp(hdr, "#!", 2) == 0;
446}
447
nethercote31779c72004-07-30 21:50:15 +0000448static int load_script(char *hdr, int len, int fd, const char *name,
449 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000450{
451 char *interp;
452 char *const end = hdr+len;
453 char *cp;
454 char *arg = NULL;
455 int eol;
456
457 interp = hdr + 2;
458 while(interp < end && (*interp == ' ' || *interp == '\t'))
459 interp++;
460
461 if (*interp != '/')
462 return ENOEXEC; /* absolute path only for interpreter */
463
464 /* skip over interpreter name */
465 for(cp = interp; cp < end && *cp != ' ' && *cp != '\t' && *cp != '\n'; cp++)
466 ;
467
468 eol = (*cp == '\n');
469
470 *cp++ = '\0';
471
472 if (!eol && cp < end) {
473 /* skip space before arg */
474 while (cp < end && (*cp == '\t' || *cp == ' '))
475 cp++;
476
477 /* arg is from here to eol */
478 arg = cp;
479 while (cp < end && *cp != '\n')
480 cp++;
481 *cp = '\0';
482 }
483
nethercoted6a56872004-07-26 15:32:47 +0000484 info->interp_name = strdup(interp);
485 assert(NULL != info->interp_name);
nethercote71980f02004-01-24 18:18:54 +0000486 if (arg != NULL && *arg != '\0') {
nethercoted6a56872004-07-26 15:32:47 +0000487 info->interp_args = strdup(arg);
488 assert(NULL != info->interp_args);
nethercote71980f02004-01-24 18:18:54 +0000489 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000490
491 if (info->argv && info->argv[0] != NULL)
492 info->argv[0] = (char *)name;
493
494 if (0)
nethercoted6a56872004-07-26 15:32:47 +0000495 printf("#! script: interp_name=\"%s\" interp_args=\"%s\"\n",
496 info->interp_name, info->interp_args);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000497
498 return do_exec_inner(interp, info);
499}
500
fitzhardingefd7da3a2004-09-08 20:05:29 +0000501/*
502 Emulate the normal Unix permissions checking algorithm.
503
504 If owner matches, then use the owner permissions, else
505 if group matches, then use the group permissions, else
506 use other permissions.
507
508 Note that we can't deal with SUID/SGID, so we refuse to run them
509 (otherwise the executable may misbehave if it doesn't have the
510 permissions it thinks it does).
511*/
512static int check_perms(int fd)
513{
514 struct stat st;
515
516 if (fstat(fd, &st) == -1)
517 return errno;
518
519 if (st.st_mode & (S_ISUID | S_ISGID)) {
520 //fprintf(stderr, "Can't execute suid/sgid executable %s\n", exe);
521 return EACCES;
522 }
523
524 if (geteuid() == st.st_uid) {
525 if (!(st.st_mode & S_IXUSR))
526 return EACCES;
527 } else {
528 int grpmatch = 0;
529
530 if (getegid() == st.st_gid)
531 grpmatch = 1;
532 else {
533 gid_t groups[32];
534 int ngrp = getgroups(32, groups);
535 int i;
536
537 for(i = 0; i < ngrp; i++)
538 if (groups[i] == st.st_gid) {
539 grpmatch = 1;
540 break;
541 }
542 }
543
544 if (grpmatch) {
545 if (!(st.st_mode & S_IXGRP))
546 return EACCES;
547 } else if (!(st.st_mode & S_IXOTH))
548 return EACCES;
549 }
550
551 return 0;
552}
553
fitzhardinge7e343cd2003-12-16 02:14:00 +0000554static int do_exec_inner(const char *exe, struct exeinfo *info)
555{
556 int fd;
fitzhardinged2e37112004-09-09 08:10:42 +0000557 int err;
nethercote73b526f2004-10-31 18:48:21 +0000558 char buf[VKI_PAGE_SIZE];
fitzhardinge7e343cd2003-12-16 02:14:00 +0000559 int bufsz;
560 int i;
561 int ret;
nethercote31779c72004-07-30 21:50:15 +0000562 static const struct {
563 int (*match)(const char *hdr, int len);
564 int (*load) ( char *hdr, int len, int fd2, const char *name,
565 struct exeinfo *);
566 } formats[] = {
567 { match_ELF, load_ELF },
568 { match_script, load_script },
569 };
fitzhardinge7e343cd2003-12-16 02:14:00 +0000570
571 fd = open(exe, O_RDONLY);
572 if (fd == -1) {
573 if (0)
574 fprintf(stderr, "Can't open executable %s: %s\n",
575 exe, strerror(errno));
576 return errno;
577 }
578
fitzhardinged2e37112004-09-09 08:10:42 +0000579 err = check_perms(fd);
fitzhardingefd7da3a2004-09-08 20:05:29 +0000580 if (err != 0) {
581 close(fd);
582 return err;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000583 }
584
585 bufsz = pread(fd, buf, sizeof(buf), 0);
586 if (bufsz < 0) {
587 fprintf(stderr, "Can't read executable header: %s\n",
588 strerror(errno));
589 close(fd);
590 return errno;
591 }
592
593 ret = ENOEXEC;
594 for(i = 0; i < sizeof(formats)/sizeof(*formats); i++) {
595 if ((formats[i].match)(buf, bufsz)) {
596 ret = (formats[i].load)(buf, bufsz, fd, exe, info);
597 break;
598 }
599 }
600
601 close(fd);
602
603 return ret;
604}
605
nethercoteea147e72004-07-26 15:43:57 +0000606// See ume.h for an indication of which entries of 'info' are inputs, which
607// are outputs, and which are both.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000608int do_exec(const char *exe, struct exeinfo *info)
609{
nethercoted6a56872004-07-26 15:32:47 +0000610 info->interp_name = NULL;
611 info->interp_args = NULL;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000612
613 return do_exec_inner(exe, info);
614}
nethercotebb1c9912004-01-04 16:43:23 +0000615
616/*--------------------------------------------------------------------*/
617/*--- end ume.c ---*/
618/*--------------------------------------------------------------------*/