blob: e3b38a238df087c02e9ecbfad4383a757e51fc37 [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/*------------------------------------------------------------*/
125/*--- Finding auxv on the stack ---*/
126/*------------------------------------------------------------*/
fitzhardinge7e343cd2003-12-16 02:14:00 +0000127
nethercoteebf1d862004-11-01 18:22:05 +0000128struct ume_auxv *find_auxv(UWord* sp)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000129{
nethercoteebf1d862004-11-01 18:22:05 +0000130 sp++; // skip argc (Nb: is word-sized, not int-sized!)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000131
nethercoteebf1d862004-11-01 18:22:05 +0000132 while (*sp != 0) // skip argv
133 sp++;
134 sp++;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000135
nethercoteebf1d862004-11-01 18:22:05 +0000136 while (*sp != 0) // skip env
137 sp++;
138 sp++;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000139
nethercoteebf1d862004-11-01 18:22:05 +0000140 return (struct ume_auxv *)sp;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000141}
142
nethercote31779c72004-07-30 21:50:15 +0000143/*------------------------------------------------------------*/
144/*--- Loading ELF files ---*/
145/*------------------------------------------------------------*/
fitzhardinge7e343cd2003-12-16 02:14:00 +0000146
sewardj2c5ffbe2005-03-12 13:32:06 +0000147static
fitzhardinge7e343cd2003-12-16 02:14:00 +0000148struct elfinfo *readelf(int fd, const char *filename)
149{
150 struct elfinfo *e = malloc(sizeof(*e));
151 int phsz;
152
nethercote7c018f42004-07-17 16:40:50 +0000153 assert(e);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000154 e->fd = fd;
155
156 if (pread(fd, &e->e, sizeof(e->e), 0) != sizeof(e->e)) {
sewardj703eec52005-04-07 02:24:23 +0000157 fprintf(stderr, "valgrind: %s: can't read ELF header: %s\n",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000158 filename, strerror(errno));
159 return NULL;
160 }
161
162 if (memcmp(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) {
sewardj703eec52005-04-07 02:24:23 +0000163 fprintf(stderr, "valgrind: %s: bad ELF magic number\n", filename);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000164 return NULL;
165 }
njn35172bc2005-03-26 00:04:03 +0000166 if (e->e.e_ident[EI_CLASS] != VGA_ELF_CLASS) {
sewardj703eec52005-04-07 02:24:23 +0000167 fprintf(stderr,
168 "valgrind: wrong ELF executable class "
169 "(eg. 32-bit instead of 64-bit)\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000170 return NULL;
171 }
njn35172bc2005-03-26 00:04:03 +0000172 if (e->e.e_ident[EI_DATA] != VGA_ELF_ENDIANNESS) {
sewardj703eec52005-04-07 02:24:23 +0000173 fprintf(stderr, "valgrind: executable has wrong endian-ness\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000174 return NULL;
175 }
176 if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) {
sewardj703eec52005-04-07 02:24:23 +0000177 fprintf(stderr, "valgrind: this is not an executable\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000178 return NULL;
179 }
180
njn35172bc2005-03-26 00:04:03 +0000181 if (e->e.e_machine != VGA_ELF_MACHINE) {
sewardj703eec52005-04-07 02:24:23 +0000182 fprintf(stderr, "valgrind: executable is not for "
183 "this architecture\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000184 return NULL;
185 }
186
187 if (e->e.e_phentsize != sizeof(ESZ(Phdr))) {
sewardj703eec52005-04-07 02:24:23 +0000188 fprintf(stderr, "valgrind: sizeof ELF Phdr wrong\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000189 return NULL;
190 }
191
192 phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum;
193 e->p = malloc(phsz);
nethercote7c018f42004-07-17 16:40:50 +0000194 assert(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000195
196 if (pread(fd, e->p, phsz, e->e.e_phoff) != phsz) {
nethercote08eaff32004-07-22 12:41:12 +0000197 fprintf(stderr, "valgrind: can't read phdr: %s\n", strerror(errno));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000198 return NULL;
199 }
200
201 return e;
202}
203
fitzhardinge7e343cd2003-12-16 02:14:00 +0000204/* Map an ELF file. Returns the brk address. */
sewardj2c5ffbe2005-03-12 13:32:06 +0000205static
fitzhardingeb50068f2004-02-24 23:42:55 +0000206ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000207{
208 int i;
nethercotebfed1c82004-07-17 12:57:44 +0000209 void* res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000210 ESZ(Addr) elfbrk = 0;
211
212 for(i = 0; i < e->e.e_phnum; i++) {
213 ESZ(Phdr) *ph = &e->p[i];
214 ESZ(Addr) addr, brkaddr;
215 ESZ(Word) memsz;
216
217 if (ph->p_type != PT_LOAD)
218 continue;
219
nethercote6c3cf412004-10-26 13:32:11 +0000220 addr = ph->p_vaddr+base;
221 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000222 brkaddr = addr+memsz;
223
224 if (brkaddr > elfbrk)
225 elfbrk = brkaddr;
226 }
227
fitzhardinge7e343cd2003-12-16 02:14:00 +0000228 for(i = 0; i < e->e.e_phnum; i++) {
229 ESZ(Phdr) *ph = &e->p[i];
230 ESZ(Addr) addr, bss, brkaddr;
231 ESZ(Off) off;
232 ESZ(Word) filesz;
233 ESZ(Word) memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000234 unsigned prot = 0;
235
236 if (ph->p_type != PT_LOAD)
237 continue;
238
nethercote6c3cf412004-10-26 13:32:11 +0000239 if (ph->p_flags & PF_X) prot |= PROT_EXEC;
240 if (ph->p_flags & PF_W) prot |= PROT_WRITE;
241 if (ph->p_flags & PF_R) prot |= PROT_READ;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000242
nethercote6c3cf412004-10-26 13:32:11 +0000243 addr = ph->p_vaddr+base;
244 off = ph->p_offset;
245 filesz = ph->p_filesz;
246 bss = addr+filesz;
247 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000248 brkaddr = addr+memsz;
249
njnf7fbe6c2004-11-30 11:40:24 +0000250 // Tom says: In the following, do what the Linux kernel does and only
251 // map the pages that are required instead of rounding everything to
252 // the specified alignment (ph->p_align). (AMD64 doesn't work if you
253 // use ph->p_align -- part of stage2's memory gets trashed somehow.)
njn098da062005-03-26 16:22:43 +0000254 //
255 // The condition handles the case of a zero-length segment.
njn13bfd852005-06-02 03:52:53 +0000256 if (VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr) > 0) {
257 res = mmap((char *)VG_PGROUNDDN(addr),
258 VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr),
259 prot, MAP_FIXED|MAP_PRIVATE, e->fd, VG_PGROUNDDN(off));
260 check_mmap(res, (char*)VG_PGROUNDDN(addr),
261 VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr));
njn098da062005-03-26 16:22:43 +0000262 }
njnf7fbe6c2004-11-30 11:40:24 +0000263
264 // if memsz > filesz, fill the remainder with zeroed pages
fitzhardinge7e343cd2003-12-16 02:14:00 +0000265 if (memsz > filesz) {
266 UInt bytes;
267
njn13bfd852005-06-02 03:52:53 +0000268 bytes = VG_PGROUNDUP(brkaddr)-VG_PGROUNDUP(bss);
nethercotebfed1c82004-07-17 12:57:44 +0000269 if (bytes > 0) {
njn13bfd852005-06-02 03:52:53 +0000270 res = mmap((char *)VG_PGROUNDUP(bss), bytes,
nethercotebfed1c82004-07-17 12:57:44 +0000271 prot, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
njn13bfd852005-06-02 03:52:53 +0000272 check_mmap(res, (char*)VG_PGROUNDUP(bss), bytes);
nethercotebfed1c82004-07-17 12:57:44 +0000273 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000274
nethercote73b526f2004-10-31 18:48:21 +0000275 bytes = bss & (VKI_PAGE_SIZE - 1);
njn098da062005-03-26 16:22:43 +0000276
277 // The 'prot' condition allows for a read-only bss
278 if ((prot & PROT_WRITE) && (bytes > 0)) {
nethercote73b526f2004-10-31 18:48:21 +0000279 bytes = VKI_PAGE_SIZE - bytes;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000280 memset((char *)bss, 0, bytes);
281 }
282 }
283 }
284
285 return elfbrk;
286}
287
nethercote31779c72004-07-30 21:50:15 +0000288// Forward declaration.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000289static int do_exec_inner(const char *exe, struct exeinfo *info);
290
fitzhardinge7e343cd2003-12-16 02:14:00 +0000291static int match_ELF(const char *hdr, int len)
292{
293 ESZ(Ehdr) *e = (ESZ(Ehdr) *)hdr;
294 return (len > sizeof(*e)) && memcmp(&e->e_ident[0], ELFMAG, SELFMAG) == 0;
295}
296
nethercote31779c72004-07-30 21:50:15 +0000297static int load_ELF(char *hdr, int len, int fd, const char *name,
298 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000299{
300 struct elfinfo *e;
301 struct elfinfo *interp = NULL;
fitzhardingeca9bd9c2004-09-08 20:05:02 +0000302 ESZ(Addr) minaddr = ~0; /* lowest mapped address */
303 ESZ(Addr) maxaddr = 0; /* highest mapped address */
304 ESZ(Addr) interp_addr = 0; /* interpreter (ld.so) address */
305 ESZ(Word) interp_size = 0; /* interpreter size */
nethercote73b526f2004-10-31 18:48:21 +0000306 ESZ(Word) interp_align = VKI_PAGE_SIZE;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000307 int i;
308 void *entry;
nethercote7f390022004-10-25 17:18:24 +0000309 ESZ(Addr) ebase = 0;
310
311#ifdef HAVE_PIE
312 ebase = info->exe_base;
313#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000314
315 e = readelf(fd, name);
316
317 if (e == NULL)
318 return ENOEXEC;
319
320 info->phnum = e->e.e_phnum;
nethercote7f390022004-10-25 17:18:24 +0000321 info->entry = e->e.e_entry + ebase;
sewardjb5f6f512005-03-10 23:59:00 +0000322 info->phdr = 0;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000323
324 for(i = 0; i < e->e.e_phnum; i++) {
325 ESZ(Phdr) *ph = &e->p[i];
326
327 switch(ph->p_type) {
328 case PT_PHDR:
nethercote7f390022004-10-25 17:18:24 +0000329 info->phdr = ph->p_vaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000330 break;
331
332 case PT_LOAD:
333 if (ph->p_vaddr < minaddr)
334 minaddr = ph->p_vaddr;
335 if (ph->p_vaddr+ph->p_memsz > maxaddr)
336 maxaddr = ph->p_vaddr+ph->p_memsz;
337 break;
338
339 case PT_INTERP: {
340 char *buf = malloc(ph->p_filesz+1);
341 int j;
342 int intfd;
343 int baseaddr_set;
344
nethercote7c018f42004-07-17 16:40:50 +0000345 assert(buf);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000346 pread(fd, buf, ph->p_filesz, ph->p_offset);
347 buf[ph->p_filesz] = '\0';
348
349 intfd = open(buf, O_RDONLY);
350 if (intfd == -1) {
351 perror("open interp");
352 exit(1);
353 }
354
355 interp = readelf(intfd, buf);
356 if (interp == NULL) {
357 fprintf(stderr, "Can't read interpreter\n");
358 return 1;
359 }
360 free(buf);
361
362 baseaddr_set = 0;
363 for(j = 0; j < interp->e.e_phnum; j++) {
364 ESZ(Phdr) *iph = &interp->p[j];
365 ESZ(Addr) end;
366
367 if (iph->p_type != PT_LOAD)
368 continue;
369
370 if (!baseaddr_set) {
nethercote7f390022004-10-25 17:18:24 +0000371 interp_addr = iph->p_vaddr;
372 interp_align = iph->p_align;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000373 baseaddr_set = 1;
374 }
375
376 /* assumes that all segments in the interp are close */
377 end = (iph->p_vaddr - interp_addr) + iph->p_memsz;
378
379 if (end > interp_size)
380 interp_size = end;
381 }
382 break;
nethercoteb24cbc82004-09-03 23:25:33 +0000383
384 default:
385 // do nothing
386 break;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000387 }
388 }
389 }
390
sewardjb5f6f512005-03-10 23:59:00 +0000391 if (info->phdr == 0)
392 info->phdr = minaddr + e->e.e_phoff;
393
fitzhardinge7e343cd2003-12-16 02:14:00 +0000394 if (info->exe_base != info->exe_end) {
395 if (minaddr >= maxaddr ||
nethercote7f390022004-10-25 17:18:24 +0000396 (minaddr + ebase < info->exe_base ||
397 maxaddr + ebase > info->exe_end)) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000398 fprintf(stderr, "Executable range %p-%p is outside the\n"
399 "acceptable range %p-%p\n",
nethercote7f390022004-10-25 17:18:24 +0000400 (void *)minaddr + ebase, (void *)maxaddr + ebase,
401 (void *)info->exe_base, (void *)info->exe_end);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000402 return ENOMEM;
403 }
404 }
405
nethercote7f390022004-10-25 17:18:24 +0000406 info->brkbase = mapelf(e, ebase); /* map the executable */
fitzhardinge7e343cd2003-12-16 02:14:00 +0000407
fitzhardinge92360792003-12-24 10:11:11 +0000408 if (info->brkbase == 0)
409 return ENOMEM;
410
fitzhardinge7e343cd2003-12-16 02:14:00 +0000411 if (interp != NULL) {
412 /* reserve a chunk of address space for interpreter */
nethercotebfed1c82004-07-17 12:57:44 +0000413 void* res;
414 char* base = (char *)info->exe_base;
415 char* baseoff;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000416 int flags = MAP_PRIVATE|MAP_ANONYMOUS;
417
418 if (info->map_base != 0) {
njn13bfd852005-06-02 03:52:53 +0000419 base = (char *)VG_ROUNDUP(info->map_base, interp_align);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000420 flags |= MAP_FIXED;
421 }
422
nethercotebfed1c82004-07-17 12:57:44 +0000423 res = mmap(base, interp_size, PROT_NONE, flags, -1, 0);
424 check_mmap(res, base, interp_size);
425 base = res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000426
427 baseoff = base - interp_addr;
428
fitzhardingeb50068f2004-02-24 23:42:55 +0000429 mapelf(interp, (ESZ(Addr))baseoff);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000430
431 close(interp->fd);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000432
433 entry = baseoff + interp->e.e_entry;
434 info->interp_base = (ESZ(Addr))base;
thughes54d08592004-09-26 14:42:47 +0000435
sewardjb5f6f512005-03-10 23:59:00 +0000436 free(interp->p);
thughes54d08592004-09-26 14:42:47 +0000437 free(interp);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000438 } else
nethercote7f390022004-10-25 17:18:24 +0000439 entry = (void *)e->e.e_entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000440
nethercote7f390022004-10-25 17:18:24 +0000441 info->exe_base = minaddr + ebase;
442 info->exe_end = maxaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000443
nethercotea3c3cf22004-11-01 18:38:00 +0000444 info->init_eip = (Addr)entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000445
sewardjb5f6f512005-03-10 23:59:00 +0000446 free(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000447 free(e);
448
449 return 0;
450}
451
452
453static int match_script(const char *hdr, Int len)
454{
455 return (len > 2) && memcmp(hdr, "#!", 2) == 0;
456}
457
nethercote31779c72004-07-30 21:50:15 +0000458static int load_script(char *hdr, int len, int fd, const char *name,
459 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000460{
461 char *interp;
462 char *const end = hdr+len;
463 char *cp;
464 char *arg = NULL;
465 int eol;
466
467 interp = hdr + 2;
468 while(interp < end && (*interp == ' ' || *interp == '\t'))
469 interp++;
470
471 if (*interp != '/')
472 return ENOEXEC; /* absolute path only for interpreter */
473
474 /* skip over interpreter name */
475 for(cp = interp; cp < end && *cp != ' ' && *cp != '\t' && *cp != '\n'; cp++)
476 ;
477
478 eol = (*cp == '\n');
479
480 *cp++ = '\0';
481
482 if (!eol && cp < end) {
483 /* skip space before arg */
484 while (cp < end && (*cp == '\t' || *cp == ' '))
485 cp++;
486
487 /* arg is from here to eol */
488 arg = cp;
489 while (cp < end && *cp != '\n')
490 cp++;
491 *cp = '\0';
492 }
493
nethercoted6a56872004-07-26 15:32:47 +0000494 info->interp_name = strdup(interp);
495 assert(NULL != info->interp_name);
nethercote71980f02004-01-24 18:18:54 +0000496 if (arg != NULL && *arg != '\0') {
nethercoted6a56872004-07-26 15:32:47 +0000497 info->interp_args = strdup(arg);
498 assert(NULL != info->interp_args);
nethercote71980f02004-01-24 18:18:54 +0000499 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000500
501 if (info->argv && info->argv[0] != NULL)
502 info->argv[0] = (char *)name;
503
504 if (0)
nethercoted6a56872004-07-26 15:32:47 +0000505 printf("#! script: interp_name=\"%s\" interp_args=\"%s\"\n",
506 info->interp_name, info->interp_args);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000507
508 return do_exec_inner(interp, info);
509}
510
fitzhardingefd7da3a2004-09-08 20:05:29 +0000511/*
512 Emulate the normal Unix permissions checking algorithm.
513
514 If owner matches, then use the owner permissions, else
515 if group matches, then use the group permissions, else
516 use other permissions.
517
518 Note that we can't deal with SUID/SGID, so we refuse to run them
519 (otherwise the executable may misbehave if it doesn't have the
520 permissions it thinks it does).
521*/
522static int check_perms(int fd)
523{
524 struct stat st;
525
526 if (fstat(fd, &st) == -1)
527 return errno;
528
529 if (st.st_mode & (S_ISUID | S_ISGID)) {
530 //fprintf(stderr, "Can't execute suid/sgid executable %s\n", exe);
531 return EACCES;
532 }
533
534 if (geteuid() == st.st_uid) {
535 if (!(st.st_mode & S_IXUSR))
536 return EACCES;
537 } else {
538 int grpmatch = 0;
539
540 if (getegid() == st.st_gid)
541 grpmatch = 1;
542 else {
543 gid_t groups[32];
544 int ngrp = getgroups(32, groups);
545 int i;
546
547 for(i = 0; i < ngrp; i++)
548 if (groups[i] == st.st_gid) {
549 grpmatch = 1;
550 break;
551 }
552 }
553
554 if (grpmatch) {
555 if (!(st.st_mode & S_IXGRP))
556 return EACCES;
557 } else if (!(st.st_mode & S_IXOTH))
558 return EACCES;
559 }
560
561 return 0;
562}
563
fitzhardinge7e343cd2003-12-16 02:14:00 +0000564static int do_exec_inner(const char *exe, struct exeinfo *info)
565{
566 int fd;
fitzhardinged2e37112004-09-09 08:10:42 +0000567 int err;
nethercote73b526f2004-10-31 18:48:21 +0000568 char buf[VKI_PAGE_SIZE];
fitzhardinge7e343cd2003-12-16 02:14:00 +0000569 int bufsz;
570 int i;
571 int ret;
nethercote31779c72004-07-30 21:50:15 +0000572 static const struct {
573 int (*match)(const char *hdr, int len);
574 int (*load) ( char *hdr, int len, int fd2, const char *name,
575 struct exeinfo *);
576 } formats[] = {
577 { match_ELF, load_ELF },
578 { match_script, load_script },
579 };
fitzhardinge7e343cd2003-12-16 02:14:00 +0000580
581 fd = open(exe, O_RDONLY);
582 if (fd == -1) {
583 if (0)
584 fprintf(stderr, "Can't open executable %s: %s\n",
585 exe, strerror(errno));
586 return errno;
587 }
588
fitzhardinged2e37112004-09-09 08:10:42 +0000589 err = check_perms(fd);
fitzhardingefd7da3a2004-09-08 20:05:29 +0000590 if (err != 0) {
591 close(fd);
592 return err;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000593 }
594
595 bufsz = pread(fd, buf, sizeof(buf), 0);
596 if (bufsz < 0) {
597 fprintf(stderr, "Can't read executable header: %s\n",
598 strerror(errno));
599 close(fd);
600 return errno;
601 }
602
603 ret = ENOEXEC;
604 for(i = 0; i < sizeof(formats)/sizeof(*formats); i++) {
605 if ((formats[i].match)(buf, bufsz)) {
606 ret = (formats[i].load)(buf, bufsz, fd, exe, info);
607 break;
608 }
609 }
610
611 close(fd);
612
613 return ret;
614}
615
nethercoteea147e72004-07-26 15:43:57 +0000616// See ume.h for an indication of which entries of 'info' are inputs, which
617// are outputs, and which are both.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000618int do_exec(const char *exe, struct exeinfo *info)
619{
nethercoted6a56872004-07-26 15:32:47 +0000620 info->interp_name = NULL;
621 info->interp_args = NULL;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000622
623 return do_exec_inner(exe, info);
624}
nethercotebb1c9912004-01-04 16:43:23 +0000625
626/*--------------------------------------------------------------------*/
627/*--- end ume.c ---*/
628/*--------------------------------------------------------------------*/