Home | History | Annotate | Line # | Download | only in crunchide
exec_elf32.c revision 1.4
      1 /*	$NetBSD: exec_elf32.c,v 1.4 1997/08/12 06:07:24 mikel Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997 Christopher G. Demetriou.  All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. All advertising materials mentioning features or use of this software
     15  *    must display the following acknowledgement:
     16  *      This product includes software developed by Christopher G. Demetriou
     17  *	for the NetBSD Project.
     18  * 4. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 #ifndef lint
     35 __RCSID("$NetBSD: exec_elf32.c,v 1.4 1997/08/12 06:07:24 mikel Exp $");
     36 #endif
     37 
     38 #ifndef ELFSIZE
     39 #define ELFSIZE         32
     40 #endif
     41 
     42 #include <sys/types.h>
     43 #include <sys/stat.h>
     44 
     45 #include <errno.h>
     46 #include <stdio.h>
     47 #include <stdlib.h>
     48 #include <string.h>
     49 #include <unistd.h>
     50 
     51 #include "extern.h"
     52 
     53 #if (defined(NLIST_ELF32) && (ELFSIZE == 32)) || \
     54     (defined(NLIST_ELF64) && (ELFSIZE == 64))
     55 
     56 #include <sys/exec_elf.h>
     57 
     58 #define CONCAT(x,y)     __CONCAT(x,y)
     59 #define ELFNAME(x)      CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x)))
     60 #define ELFNAME2(x,y)   CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y))))
     61 #define ELFNAMEEND(x)   CONCAT(x,CONCAT(_elf,ELFSIZE))
     62 #define ELFDEFNNAME(x)  CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x)))
     63 
     64 struct listelem {
     65 	struct listelem *next;
     66 	void *mem;
     67 	off_t file;
     68 	size_t size;
     69 };
     70 
     71 static ssize_t
     72 xreadatoff(int fd, void *buf, off_t off, size_t size, const char *fn)
     73 {
     74 	ssize_t rv;
     75 
     76 	if (lseek(fd, off, SEEK_SET) != off) {
     77 		perror(fn);
     78 		return -1;
     79 	}
     80 	if ((rv = read(fd, buf, size)) != size) {
     81 		fprintf(stderr, "%s: read error: %s\n", fn,
     82 		    rv == -1 ? strerror(errno) : "short read");
     83 		return -1;
     84 	}
     85 	return size;
     86 }
     87 
     88 static ssize_t
     89 xwriteatoff(int fd, void *buf, off_t off, size_t size, const char *fn)
     90 {
     91 	ssize_t rv;
     92 
     93 	if (lseek(fd, off, SEEK_SET) != off) {
     94 		perror(fn);
     95 		return -1;
     96 	}
     97 	if ((rv = write(fd, buf, size)) != size) {
     98 		fprintf(stderr, "%s: write error: %s\n", fn,
     99 		    rv == -1 ? strerror(errno) : "short write");
    100 		return -1;
    101 	}
    102 	return size;
    103 }
    104 
    105 static void *
    106 xmalloc(size_t size, const char *fn, const char *use)
    107 {
    108 	void *rv;
    109 
    110 	rv = malloc(size);
    111 	if (rv == NULL)
    112 		fprintf(stderr, "%s: out of memory (allocating for %s)\n",
    113 		    fn, use);
    114 	return (rv);
    115 }
    116 
    117 int
    118 ELFNAMEEND(check)(int fd, const char *fn)
    119 {
    120 	Elf_Ehdr eh;
    121 	struct stat sb;
    122 
    123 	/*
    124 	 * Check the header to maek sure it's an ELF file (of the
    125 	 * appropriate size).
    126 	 */
    127 	if (fstat(fd, &sb) == -1)
    128 		return 0;
    129 	if (sb.st_size < sizeof eh)
    130 		return 0;
    131 	if (read(fd, &eh, sizeof eh) != sizeof eh)
    132 		return 0;
    133 
    134 	if (memcmp(eh.e_ident, Elf_e_ident, Elf_e_siz))
    135                 return 0;
    136 
    137         switch (eh.e_machine) {
    138         ELFDEFNNAME(MACHDEP_ID_CASES)
    139 
    140         default:
    141                 return 0;
    142         }
    143 
    144 	return 1;
    145 }
    146 
    147 int
    148 ELFNAMEEND(hide)(int fd, const char *fn)
    149 {
    150 	Elf_Ehdr ehdr;
    151 	Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr;
    152 	Elf_Sym *symtabp = NULL;
    153 	char *strtabp = NULL;
    154 	Elf_Word *symfwmap = NULL, *symrvmap = NULL, nsyms, nlocalsyms, ewi;
    155 	struct listelem *relalist = NULL, *rellist = NULL, *tmpl;
    156 	ssize_t shdrsize;
    157 	int rv, i, weird;
    158 
    159 	rv = 0;
    160 	if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr)
    161 		goto bad;
    162 
    163 	shdrsize = ehdr.e_shnum * ehdr.e_shentsize;
    164 	if ((shdrp = xmalloc(shdrsize, fn, "section header table")) == NULL)
    165 		goto bad;
    166 	if (xreadatoff(fd, shdrp, ehdr.e_shoff, shdrsize, fn) != shdrsize)
    167 		goto bad;
    168 
    169 	symtabshdr = strtabshdr = NULL;
    170 	weird = 0;
    171 	for (i = 0; i < ehdr.e_shnum; i++) {
    172 		switch (shdrp[i].sh_type) {
    173 		case Elf_sht_symtab:
    174 			if (symtabshdr != NULL)
    175 				weird = 1;
    176 			symtabshdr = &shdrp[i];
    177 			strtabshdr = &shdrp[shdrp[i].sh_link];
    178 			break;
    179 		case Elf_sht_rela:
    180 			tmpl = xmalloc(sizeof *tmpl, fn, "rela list element");
    181 			if (tmpl == NULL)
    182 				goto bad;
    183 			tmpl->mem = NULL;
    184 			tmpl->file = shdrp[i].sh_offset;
    185 			tmpl->size = shdrp[i].sh_size;
    186 			tmpl->next = relalist;
    187 			relalist = tmpl;
    188 			break;
    189 		case Elf_sht_rel:
    190 			tmpl = xmalloc(sizeof *tmpl, fn, "rel list element");
    191 			if (tmpl == NULL)
    192 				goto bad;
    193 			tmpl->mem = NULL;
    194 			tmpl->file = shdrp[i].sh_offset;
    195 			tmpl->size = shdrp[i].sh_size;
    196 			tmpl->next = rellist;
    197 			rellist = tmpl;
    198 			break;
    199 		}
    200 	}
    201 	if (symtabshdr == NULL)
    202 		goto out;
    203 	if (strtabshdr == NULL)
    204 		weird = 1;
    205 	if (weird) {
    206 		fprintf(stderr, "%s: weird executable (unsupported)\n", fn);
    207 		goto bad;
    208 	}
    209 
    210 	/*
    211 	 * load up everything we need
    212 	 */
    213 
    214 	/* symbol table */
    215 	if ((symtabp = xmalloc(symtabshdr->sh_size, fn, "symbol table"))
    216 	    == NULL)
    217 		goto bad;
    218 	if (xreadatoff(fd, symtabp, symtabshdr->sh_offset, symtabshdr->sh_size,
    219 	    fn) != symtabshdr->sh_size)
    220 		goto bad;
    221 
    222 	/* string table */
    223 	if ((strtabp = xmalloc(strtabshdr->sh_size, fn, "string table"))
    224 	    == NULL)
    225 		goto bad;
    226 	if (xreadatoff(fd, strtabp, strtabshdr->sh_offset, strtabshdr->sh_size,
    227 	    fn) != strtabshdr->sh_size)
    228 		goto bad;
    229 
    230 	/* any rela tables */
    231 	for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) {
    232 		if ((tmpl->mem = xmalloc(tmpl->size, fn, "rela table"))
    233 		    == NULL)
    234 			goto bad;
    235 		if (xreadatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) !=
    236 		    tmpl->size)
    237 			goto bad;
    238 	}
    239 
    240 	/* any rel tables */
    241 	for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) {
    242 		if ((tmpl->mem = xmalloc(tmpl->size, fn, "rel table"))
    243 		    == NULL)
    244 			goto bad;
    245 		if (xreadatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) !=
    246 		    tmpl->size)
    247 			goto bad;
    248 	}
    249 
    250 	/* Prepare data structures for symbol movement. */
    251 	nsyms = symtabshdr->sh_size / symtabshdr->sh_entsize;
    252 	nlocalsyms = symtabshdr->sh_info;
    253 	if ((symfwmap = xmalloc(nsyms * sizeof (Elf_Word), fn,
    254 	    "symbol forward mapping table")) == NULL)
    255 		goto bad;
    256 	if ((symrvmap = xmalloc(nsyms * sizeof (Elf_Word), fn,
    257 	    "symbol reverse mapping table")) == NULL)
    258 		goto bad;
    259 
    260 	/* init location -> symbol # table */
    261 	for (ewi = 0; ewi < nsyms; ewi++)
    262 		symrvmap[ewi] = ewi;
    263 
    264 	/* move symbols, making them local */
    265 	for (ewi = nlocalsyms; ewi < nsyms; ewi++) {
    266 		Elf_Sym *sp, symswap;
    267 		Elf_Word mapswap;
    268 
    269 		sp = &symtabp[ewi];
    270 
    271 		/* if it's on our keep list, don't move it */
    272 		if (in_keep_list(strtabp + sp->st_name))
    273 			continue;
    274 
    275 		/* if it's an undefined symbol, keep it */
    276 		if (sp->st_shndx == Elf_eshn_undefined)
    277 			continue;
    278 
    279 		/* adjust the symbol so that it's local */
    280 		sp->st_info =
    281 		    (Elf_estb_local << 4) | ELF_SYM_TYPE(sp->st_info); /* XXX */
    282 
    283 		/*
    284 		 * move the symbol to its new location
    285 		 */
    286 
    287 		/* note that symbols in those locations have been swapped */
    288 		mapswap = symrvmap[ewi];
    289 		symrvmap[ewi] = symrvmap[nlocalsyms];
    290 		symrvmap[nlocalsyms] = mapswap;
    291 
    292 		/* and swap the symbols */
    293 		symswap = *sp;
    294 		*sp = symtabp[nlocalsyms];
    295 		symtabp[nlocalsyms] = symswap;
    296 
    297 		nlocalsyms++;			/* note new local sym */
    298 	}
    299 	symtabshdr->sh_info = nlocalsyms;
    300 
    301 	/* set up symbol # -> location mapping table */
    302 	for (ewi = 0; ewi < nsyms; ewi++)
    303 		symfwmap[symrvmap[ewi]] = ewi;
    304 
    305 	/* any rela tables */
    306 	for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) {
    307 		Elf_RelA *relap = tmpl->mem;
    308 
    309 		for (ewi = 0; ewi < tmpl->size / sizeof *relap; ewi++) {
    310 			relap[ewi].r_info =
    311 #if (ELFSIZE == 32)					/* XXX */
    312 			    symfwmap[ELF_R_SYM(relap[ewi].r_info)] << 8 |
    313 			    ELF_R_TYPE(relap[ewi].r_info);
    314 #elif (ELFSIZE == 64)					/* XXX */
    315 			    symfwmap[ELF_R_SYM(relap[ewi].r_info)] << 32 |
    316 			    ELF_R_TYPE(relap[ewi].r_info);
    317 #endif							/* XXX */
    318 		}
    319 	}
    320 
    321 	/* any rel tables */
    322 	for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) {
    323 		Elf_Rel *relp = tmpl->mem;
    324 
    325 		for (ewi = 0; ewi < tmpl->size / sizeof *relp; ewi++) {
    326 			relp[ewi].r_info =
    327 #if (ELFSIZE == 32)					/* XXX */
    328 			    symfwmap[ELF_R_SYM(relp[ewi].r_info)] << 8 |
    329 			    ELF_R_TYPE(relp[ewi].r_info);
    330 #elif (ELFSIZE == 64)					/* XXX */
    331 			    symfwmap[ELF_R_SYM(relp[ewi].r_info)] << 32 |
    332 			    ELF_R_TYPE(relp[ewi].r_info);
    333 #endif							/* XXX */
    334 		}
    335 	}
    336 
    337 	/*
    338 	 * write new tables to the file
    339 	 */
    340 	if (xwriteatoff(fd, shdrp, ehdr.e_shoff, shdrsize, fn) != shdrsize)
    341 		goto bad;
    342 	if (xwriteatoff(fd, symtabp, symtabshdr->sh_offset,
    343 	    symtabshdr->sh_size, fn) != symtabshdr->sh_size)
    344 		goto bad;
    345 	for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) {
    346 		if (xwriteatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) !=
    347 		    tmpl->size)
    348 			goto bad;
    349 	}
    350 	for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) {
    351 		if (xwriteatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) !=
    352 		    tmpl->size)
    353 			goto bad;
    354 	}
    355 
    356 out:
    357 	if (shdrp != NULL)
    358 		free(shdrp);
    359 	if (symtabp != NULL)
    360 		free(symtabp);
    361 	if (strtabp != NULL)
    362 		free(strtabp);
    363 	if (symfwmap != NULL)
    364 		free(symfwmap);
    365 	if (symrvmap != NULL)
    366 		free(symrvmap);
    367 	while ((tmpl = relalist) != NULL) {
    368 		relalist = tmpl->next;
    369 		if (tmpl->mem != NULL)
    370 			free(tmpl->mem);
    371 		free(tmpl);
    372 	}
    373 	while ((tmpl = rellist) != NULL) {
    374 		rellist = tmpl->next;
    375 		if (tmpl->mem != NULL)
    376 			free(tmpl->mem);
    377 		free(tmpl);
    378 	}
    379 	return (rv);
    380 
    381 bad:
    382 	rv = 1;
    383 	goto out;
    384 }
    385 
    386 #endif /* include this size of ELF */
    387