blob: 4a1362d137ae9d3b1ddfc7094de3f250e8d64f07 [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/*
8 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
10
11 Copyright (C) 2000-2004 Julian Seward
12 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];
106 off_t offset;
107 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
145struct elfinfo *readelf(int fd, const char *filename)
146{
147 struct elfinfo *e = malloc(sizeof(*e));
148 int phsz;
149
nethercote7c018f42004-07-17 16:40:50 +0000150 assert(e);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000151 e->fd = fd;
152
153 if (pread(fd, &e->e, sizeof(e->e), 0) != sizeof(e->e)) {
nethercote08eaff32004-07-22 12:41:12 +0000154 fprintf(stderr, "valgrind: %s: can't read elf header: %s\n",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000155 filename, strerror(errno));
156 return NULL;
157 }
158
159 if (memcmp(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) {
nethercote08eaff32004-07-22 12:41:12 +0000160 fprintf(stderr, "valgrind: %s: bad ELF magic\n", filename);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000161 return NULL;
162 }
nethercotebdaa89f2004-10-09 19:08:08 +0000163 if (e->e.e_ident[EI_CLASS] != VG_ELF_CLASS) {
164 fprintf(stderr, "valgrind: wrong executable class (eg. 32-bit instead\n"
165 "valgrind: of 64-bit)\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000166 return NULL;
167 }
nethercotebdaa89f2004-10-09 19:08:08 +0000168 if (e->e.e_ident[EI_DATA] != VG_ELF_ENDIANNESS) {
169 fprintf(stderr, "valgrind: wrong endian-ness\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000170 return NULL;
171 }
172 if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) {
nethercote08eaff32004-07-22 12:41:12 +0000173 fprintf(stderr, "valgrind: need executable\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000174 return NULL;
175 }
176
nethercotebdaa89f2004-10-09 19:08:08 +0000177 if (e->e.e_machine != VG_ELF_MACHINE) {
178 fprintf(stderr, "valgrind: wrong architecture\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000179 return NULL;
180 }
181
182 if (e->e.e_phentsize != sizeof(ESZ(Phdr))) {
nethercote08eaff32004-07-22 12:41:12 +0000183 fprintf(stderr, "valgrind: sizeof Phdr wrong\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000184 return NULL;
185 }
186
187 phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum;
188 e->p = malloc(phsz);
nethercote7c018f42004-07-17 16:40:50 +0000189 assert(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000190
191 if (pread(fd, e->p, phsz, e->e.e_phoff) != phsz) {
nethercote08eaff32004-07-22 12:41:12 +0000192 fprintf(stderr, "valgrind: can't read phdr: %s\n", strerror(errno));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000193 return NULL;
194 }
195
196 return e;
197}
198
fitzhardinge7e343cd2003-12-16 02:14:00 +0000199/* Map an ELF file. Returns the brk address. */
fitzhardingeb50068f2004-02-24 23:42:55 +0000200ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000201{
202 int i;
nethercotebfed1c82004-07-17 12:57:44 +0000203 void* res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000204 ESZ(Addr) elfbrk = 0;
205
206 for(i = 0; i < e->e.e_phnum; i++) {
207 ESZ(Phdr) *ph = &e->p[i];
208 ESZ(Addr) addr, brkaddr;
209 ESZ(Word) memsz;
210
211 if (ph->p_type != PT_LOAD)
212 continue;
213
nethercote6c3cf412004-10-26 13:32:11 +0000214 addr = ph->p_vaddr+base;
215 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000216 brkaddr = addr+memsz;
217
218 if (brkaddr > elfbrk)
219 elfbrk = brkaddr;
220 }
221
fitzhardinge7e343cd2003-12-16 02:14:00 +0000222 for(i = 0; i < e->e.e_phnum; i++) {
223 ESZ(Phdr) *ph = &e->p[i];
224 ESZ(Addr) addr, bss, brkaddr;
225 ESZ(Off) off;
226 ESZ(Word) filesz;
227 ESZ(Word) memsz;
228 ESZ(Word) align;
229 unsigned prot = 0;
230
231 if (ph->p_type != PT_LOAD)
232 continue;
233
nethercote6c3cf412004-10-26 13:32:11 +0000234 if (ph->p_flags & PF_X) prot |= PROT_EXEC;
235 if (ph->p_flags & PF_W) prot |= PROT_WRITE;
236 if (ph->p_flags & PF_R) prot |= PROT_READ;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000237
nethercote6c3cf412004-10-26 13:32:11 +0000238 align = ph->p_align;
239 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
nethercotebfed1c82004-07-17 12:57:44 +0000246 res = mmap((char *)ROUNDDN(addr, align),
247 ROUNDUP(bss, align)-ROUNDDN(addr, align),
248 prot, MAP_FIXED|MAP_PRIVATE, e->fd, ROUNDDN(off, align));
249 check_mmap(res, (char*)ROUNDDN(addr,align),
250 ROUNDUP(bss, align)-ROUNDDN(addr, align));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000251
252 /* if memsz > filesz, then we need to fill the remainder with zeroed pages */
253 if (memsz > filesz) {
254 UInt bytes;
255
256 bytes = ROUNDUP(brkaddr, align)-ROUNDUP(bss, align);
nethercotebfed1c82004-07-17 12:57:44 +0000257 if (bytes > 0) {
258 res = mmap((char *)ROUNDUP(bss, align), bytes,
259 prot, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
260 check_mmap(res, (char*)ROUNDUP(bss,align), bytes);
261 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000262
nethercote73b526f2004-10-31 18:48:21 +0000263 bytes = bss & (VKI_PAGE_SIZE - 1);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000264 if (bytes > 0) {
nethercote73b526f2004-10-31 18:48:21 +0000265 bytes = VKI_PAGE_SIZE - bytes;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000266 memset((char *)bss, 0, bytes);
267 }
268 }
269 }
270
271 return elfbrk;
272}
273
nethercote31779c72004-07-30 21:50:15 +0000274// Forward declaration.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000275static int do_exec_inner(const char *exe, struct exeinfo *info);
276
fitzhardinge7e343cd2003-12-16 02:14:00 +0000277static int match_ELF(const char *hdr, int len)
278{
279 ESZ(Ehdr) *e = (ESZ(Ehdr) *)hdr;
280 return (len > sizeof(*e)) && memcmp(&e->e_ident[0], ELFMAG, SELFMAG) == 0;
281}
282
nethercote31779c72004-07-30 21:50:15 +0000283static int load_ELF(char *hdr, int len, int fd, const char *name,
284 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000285{
286 struct elfinfo *e;
287 struct elfinfo *interp = NULL;
fitzhardingeca9bd9c2004-09-08 20:05:02 +0000288 ESZ(Addr) minaddr = ~0; /* lowest mapped address */
289 ESZ(Addr) maxaddr = 0; /* highest mapped address */
290 ESZ(Addr) interp_addr = 0; /* interpreter (ld.so) address */
291 ESZ(Word) interp_size = 0; /* interpreter size */
nethercote73b526f2004-10-31 18:48:21 +0000292 ESZ(Word) interp_align = VKI_PAGE_SIZE;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000293 int i;
294 void *entry;
nethercote7f390022004-10-25 17:18:24 +0000295 ESZ(Addr) ebase = 0;
296
297#ifdef HAVE_PIE
298 ebase = info->exe_base;
299#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000300
301 e = readelf(fd, name);
302
303 if (e == NULL)
304 return ENOEXEC;
305
306 info->phnum = e->e.e_phnum;
nethercote7f390022004-10-25 17:18:24 +0000307 info->entry = e->e.e_entry + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000308
309 for(i = 0; i < e->e.e_phnum; i++) {
310 ESZ(Phdr) *ph = &e->p[i];
311
312 switch(ph->p_type) {
313 case PT_PHDR:
nethercote7f390022004-10-25 17:18:24 +0000314 info->phdr = ph->p_vaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000315 break;
316
317 case PT_LOAD:
318 if (ph->p_vaddr < minaddr)
319 minaddr = ph->p_vaddr;
320 if (ph->p_vaddr+ph->p_memsz > maxaddr)
321 maxaddr = ph->p_vaddr+ph->p_memsz;
322 break;
323
324 case PT_INTERP: {
325 char *buf = malloc(ph->p_filesz+1);
326 int j;
327 int intfd;
328 int baseaddr_set;
329
nethercote7c018f42004-07-17 16:40:50 +0000330 assert(buf);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000331 pread(fd, buf, ph->p_filesz, ph->p_offset);
332 buf[ph->p_filesz] = '\0';
333
334 intfd = open(buf, O_RDONLY);
335 if (intfd == -1) {
336 perror("open interp");
337 exit(1);
338 }
339
340 interp = readelf(intfd, buf);
341 if (interp == NULL) {
342 fprintf(stderr, "Can't read interpreter\n");
343 return 1;
344 }
345 free(buf);
346
347 baseaddr_set = 0;
348 for(j = 0; j < interp->e.e_phnum; j++) {
349 ESZ(Phdr) *iph = &interp->p[j];
350 ESZ(Addr) end;
351
352 if (iph->p_type != PT_LOAD)
353 continue;
354
355 if (!baseaddr_set) {
nethercote7f390022004-10-25 17:18:24 +0000356 interp_addr = iph->p_vaddr;
357 interp_align = iph->p_align;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000358 baseaddr_set = 1;
359 }
360
361 /* assumes that all segments in the interp are close */
362 end = (iph->p_vaddr - interp_addr) + iph->p_memsz;
363
364 if (end > interp_size)
365 interp_size = end;
366 }
367 break;
nethercoteb24cbc82004-09-03 23:25:33 +0000368
369 default:
370 // do nothing
371 break;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000372 }
373 }
374 }
375
376 if (info->exe_base != info->exe_end) {
377 if (minaddr >= maxaddr ||
nethercote7f390022004-10-25 17:18:24 +0000378 (minaddr + ebase < info->exe_base ||
379 maxaddr + ebase > info->exe_end)) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000380 fprintf(stderr, "Executable range %p-%p is outside the\n"
381 "acceptable range %p-%p\n",
nethercote7f390022004-10-25 17:18:24 +0000382 (void *)minaddr + ebase, (void *)maxaddr + ebase,
383 (void *)info->exe_base, (void *)info->exe_end);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000384 return ENOMEM;
385 }
386 }
387
nethercote7f390022004-10-25 17:18:24 +0000388 info->brkbase = mapelf(e, ebase); /* map the executable */
fitzhardinge7e343cd2003-12-16 02:14:00 +0000389
fitzhardinge92360792003-12-24 10:11:11 +0000390 if (info->brkbase == 0)
391 return ENOMEM;
392
fitzhardinge7e343cd2003-12-16 02:14:00 +0000393 if (interp != NULL) {
394 /* reserve a chunk of address space for interpreter */
nethercotebfed1c82004-07-17 12:57:44 +0000395 void* res;
396 char* base = (char *)info->exe_base;
397 char* baseoff;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000398 int flags = MAP_PRIVATE|MAP_ANONYMOUS;
399
400 if (info->map_base != 0) {
nethercote7f390022004-10-25 17:18:24 +0000401 base = (char *)ROUNDUP(info->map_base, interp_align);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000402 flags |= MAP_FIXED;
403 }
404
nethercotebfed1c82004-07-17 12:57:44 +0000405 res = mmap(base, interp_size, PROT_NONE, flags, -1, 0);
406 check_mmap(res, base, interp_size);
407 base = res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000408
409 baseoff = base - interp_addr;
410
fitzhardingeb50068f2004-02-24 23:42:55 +0000411 mapelf(interp, (ESZ(Addr))baseoff);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000412
413 close(interp->fd);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000414
415 entry = baseoff + interp->e.e_entry;
416 info->interp_base = (ESZ(Addr))base;
thughes54d08592004-09-26 14:42:47 +0000417
418 free(interp);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000419 } else
nethercote7f390022004-10-25 17:18:24 +0000420 entry = (void *)e->e.e_entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000421
nethercote7f390022004-10-25 17:18:24 +0000422 info->exe_base = minaddr + ebase;
423 info->exe_end = maxaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000424
nethercotea3c3cf22004-11-01 18:38:00 +0000425 info->init_eip = (Addr)entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000426
427 free(e);
428
429 return 0;
430}
431
432
433static int match_script(const char *hdr, Int len)
434{
435 return (len > 2) && memcmp(hdr, "#!", 2) == 0;
436}
437
nethercote31779c72004-07-30 21:50:15 +0000438static int load_script(char *hdr, int len, int fd, const char *name,
439 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000440{
441 char *interp;
442 char *const end = hdr+len;
443 char *cp;
444 char *arg = NULL;
445 int eol;
446
447 interp = hdr + 2;
448 while(interp < end && (*interp == ' ' || *interp == '\t'))
449 interp++;
450
451 if (*interp != '/')
452 return ENOEXEC; /* absolute path only for interpreter */
453
454 /* skip over interpreter name */
455 for(cp = interp; cp < end && *cp != ' ' && *cp != '\t' && *cp != '\n'; cp++)
456 ;
457
458 eol = (*cp == '\n');
459
460 *cp++ = '\0';
461
462 if (!eol && cp < end) {
463 /* skip space before arg */
464 while (cp < end && (*cp == '\t' || *cp == ' '))
465 cp++;
466
467 /* arg is from here to eol */
468 arg = cp;
469 while (cp < end && *cp != '\n')
470 cp++;
471 *cp = '\0';
472 }
473
nethercoted6a56872004-07-26 15:32:47 +0000474 info->interp_name = strdup(interp);
475 assert(NULL != info->interp_name);
nethercote71980f02004-01-24 18:18:54 +0000476 if (arg != NULL && *arg != '\0') {
nethercoted6a56872004-07-26 15:32:47 +0000477 info->interp_args = strdup(arg);
478 assert(NULL != info->interp_args);
nethercote71980f02004-01-24 18:18:54 +0000479 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000480
481 if (info->argv && info->argv[0] != NULL)
482 info->argv[0] = (char *)name;
483
484 if (0)
nethercoted6a56872004-07-26 15:32:47 +0000485 printf("#! script: interp_name=\"%s\" interp_args=\"%s\"\n",
486 info->interp_name, info->interp_args);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000487
488 return do_exec_inner(interp, info);
489}
490
fitzhardingefd7da3a2004-09-08 20:05:29 +0000491/*
492 Emulate the normal Unix permissions checking algorithm.
493
494 If owner matches, then use the owner permissions, else
495 if group matches, then use the group permissions, else
496 use other permissions.
497
498 Note that we can't deal with SUID/SGID, so we refuse to run them
499 (otherwise the executable may misbehave if it doesn't have the
500 permissions it thinks it does).
501*/
502static int check_perms(int fd)
503{
504 struct stat st;
505
506 if (fstat(fd, &st) == -1)
507 return errno;
508
509 if (st.st_mode & (S_ISUID | S_ISGID)) {
510 //fprintf(stderr, "Can't execute suid/sgid executable %s\n", exe);
511 return EACCES;
512 }
513
514 if (geteuid() == st.st_uid) {
515 if (!(st.st_mode & S_IXUSR))
516 return EACCES;
517 } else {
518 int grpmatch = 0;
519
520 if (getegid() == st.st_gid)
521 grpmatch = 1;
522 else {
523 gid_t groups[32];
524 int ngrp = getgroups(32, groups);
525 int i;
526
527 for(i = 0; i < ngrp; i++)
528 if (groups[i] == st.st_gid) {
529 grpmatch = 1;
530 break;
531 }
532 }
533
534 if (grpmatch) {
535 if (!(st.st_mode & S_IXGRP))
536 return EACCES;
537 } else if (!(st.st_mode & S_IXOTH))
538 return EACCES;
539 }
540
541 return 0;
542}
543
fitzhardinge7e343cd2003-12-16 02:14:00 +0000544static int do_exec_inner(const char *exe, struct exeinfo *info)
545{
546 int fd;
fitzhardinged2e37112004-09-09 08:10:42 +0000547 int err;
nethercote73b526f2004-10-31 18:48:21 +0000548 char buf[VKI_PAGE_SIZE];
fitzhardinge7e343cd2003-12-16 02:14:00 +0000549 int bufsz;
550 int i;
551 int ret;
nethercote31779c72004-07-30 21:50:15 +0000552 static const struct {
553 int (*match)(const char *hdr, int len);
554 int (*load) ( char *hdr, int len, int fd2, const char *name,
555 struct exeinfo *);
556 } formats[] = {
557 { match_ELF, load_ELF },
558 { match_script, load_script },
559 };
fitzhardinge7e343cd2003-12-16 02:14:00 +0000560
561 fd = open(exe, O_RDONLY);
562 if (fd == -1) {
563 if (0)
564 fprintf(stderr, "Can't open executable %s: %s\n",
565 exe, strerror(errno));
566 return errno;
567 }
568
fitzhardinged2e37112004-09-09 08:10:42 +0000569 err = check_perms(fd);
fitzhardingefd7da3a2004-09-08 20:05:29 +0000570 if (err != 0) {
571 close(fd);
572 return err;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000573 }
574
575 bufsz = pread(fd, buf, sizeof(buf), 0);
576 if (bufsz < 0) {
577 fprintf(stderr, "Can't read executable header: %s\n",
578 strerror(errno));
579 close(fd);
580 return errno;
581 }
582
583 ret = ENOEXEC;
584 for(i = 0; i < sizeof(formats)/sizeof(*formats); i++) {
585 if ((formats[i].match)(buf, bufsz)) {
586 ret = (formats[i].load)(buf, bufsz, fd, exe, info);
587 break;
588 }
589 }
590
591 close(fd);
592
593 return ret;
594}
595
nethercoteea147e72004-07-26 15:43:57 +0000596// See ume.h for an indication of which entries of 'info' are inputs, which
597// are outputs, and which are both.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000598int do_exec(const char *exe, struct exeinfo *info)
599{
nethercoted6a56872004-07-26 15:32:47 +0000600 info->interp_name = NULL;
601 info->interp_args = NULL;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000602
603 return do_exec_inner(exe, info);
604}
nethercotebb1c9912004-01-04 16:43:23 +0000605
606/*--------------------------------------------------------------------*/
607/*--- end ume.c ---*/
608/*--------------------------------------------------------------------*/