Home | History | Annotate | Line # | Download | only in crunchide
exec_elf32.c revision 1.3
      1 /*	$NetBSD: exec_elf32.c,v 1.3 1997/08/02 21:30:19 perry 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.3 1997/08/02 21:30:19 perry 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 #include <stdio.h>
     45 #include <stdlib.h>
     46 #include <string.h>
     47 #include <errno.h>
     48 #include "extern.h"
     49 
     50 #if (defined(NLIST_ELF32) && (ELFSIZE == 32)) || \
     51     (defined(NLIST_ELF64) && (ELFSIZE == 64))
     52 
     53 #include <sys/exec_elf.h>
     54 
     55 #define CONCAT(x,y)     __CONCAT(x,y)
     56 #define ELFNAME(x)      CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x)))
     57 #define ELFNAME2(x,y)   CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y))))
     58 #define ELFNAMEEND(x)   CONCAT(x,CONCAT(_elf,ELFSIZE))
     59 #define ELFDEFNNAME(x)  CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x)))
     60 
     61 struct listelem {
     62 	struct listelem *next;
     63 	void *mem;
     64 	off_t file;
     65 	size_t size;
     66 };
     67 
     68 static ssize_t
     69 xreadatoff(int fd, void *buf, off_t off, size_t size, const char *fn)
     70 {
     71 	ssize_t rv;
     72 
     73 	if (lseek(fd, off, SEEK_SET) != off) {
     74 		perror(fn);
     75 		return -1;
     76 	}
     77 	if ((rv = read(fd, buf, size)) != size) {
     78 		fprintf(stderr, "%s: read error: %s\n", fn,
     79 		    rv == -1 ? strerror(errno) : "short read");
     80 		return -1;
     81 	}
     82 	return size;
     83 }
     84 
     85 static ssize_t
     86 xwriteatoff(int fd, void *buf, off_t off, size_t size, const char *fn)
     87 {
     88 	ssize_t rv;
     89 
     90 	if (lseek(fd, off, SEEK_SET) != off) {
     91 		perror(fn);
     92 		return -1;
     93 	}
     94 	if ((rv = write(fd, buf, size)) != size) {
     95 		fprintf(stderr, "%s: write error: %s\n", fn,
     96 		    rv == -1 ? strerror(errno) : "short write");
     97 		return -1;
     98 	}
     99 	return size;
    100 }
    101 
    102 static void *
    103 xmalloc(size_t size, const char *fn, const char *use)
    104 {
    105 	void *rv;
    106 
    107 	rv = malloc(size);
    108 	if (rv == NULL)
    109 		fprintf(stderr, "%s: out of memory (allocating for %s)\n",
    110 		    fn, use);
    111 	return (rv);
    112 }
    113 
    114 int
    115 ELFNAMEEND(check)(int fd, const char *fn)
    116 {
    117 	Elf_Ehdr eh;
    118 	struct stat sb;
    119 
    120 	/*
    121 	 * Check the header to maek sure it's an ELF file (of the
    122 	 * appropriate size).
    123 	 */
    124 	if (fstat(fd, &sb) == -1)
    125 		return 0;
    126 	if (sb.st_size < sizeof eh)
    127 		return 0;
    128 	if (read(fd, &eh, sizeof eh) != sizeof eh)
    129 		return 0;
    130 
    131 	if (memcmp(eh.e_ident, Elf_e_ident, Elf_e_siz))
    132                 return 0;
    133 
    134         switch (eh.e_machine) {
    135         ELFDEFNNAME(MACHDEP_ID_CASES)
    136 
    137         default:
    138                 return 0;
    139         }
    140 
    141 	return 1;
    142 }
    143 
    144 int
    145 ELFNAMEEND(hide)(int fd, const char *fn)
    146 {
    147 	Elf_Ehdr ehdr;
    148 	Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr;
    149 	Elf_Sym *symtabp = NULL;
    150 	char *strtabp = NULL;
    151 	Elf_RelA *relap = NULL;
    152 	Elf_Rel *relp = NULL;
    153 	Elf_Word *symfwmap = NULL, *symrvmap = NULL, nsyms, nlocalsyms, ewi;
    154 	struct listelem *relalist = NULL, *rellist = NULL, *tmpl;
    155 	ssize_t shdrsize;
    156 	int rv, i, weird;
    157 
    158 	rv = 0;
    159 	if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr)
    160 		goto bad;
    161 
    162 	shdrsize = ehdr.e_shnum * ehdr.e_shentsize;
    163 	if ((shdrp = xmalloc(shdrsize, fn, "section header table")) == NULL)
    164 		goto bad;
    165 	if (xreadatoff(fd, shdrp, ehdr.e_shoff, shdrsize, fn) != shdrsize)
    166 		goto bad;
    167 
    168 	symtabshdr = strtabshdr = NULL;
    169 	weird = 0;
    170 	for (i = 0; i < ehdr.e_shnum; i++) {
    171 		switch (shdrp[i].sh_type) {
    172 		case Elf_sht_symtab:
    173 			if (symtabshdr != NULL)
    174 				weird = 1;
    175 			symtabshdr = &shdrp[i];
    176 			strtabshdr = &shdrp[shdrp[i].sh_link];
    177 			break;
    178 		case Elf_sht_rela:
    179 			tmpl = xmalloc(sizeof *tmpl, fn, "rela list element");
    180 			if (tmpl == NULL)
    181 				goto bad;
    182 			tmpl->mem = NULL;
    183 			tmpl->file = shdrp[i].sh_offset;
    184 			tmpl->size = shdrp[i].sh_size;
    185 			tmpl->next = relalist;
    186 			relalist = tmpl;
    187 			break;
    188 		case Elf_sht_rel:
    189 			tmpl = xmalloc(sizeof *tmpl, fn, "rel list element");
    190 			if (tmpl == NULL)
    191 				goto bad;
    192 			tmpl->mem = NULL;
    193 			tmpl->file = shdrp[i].sh_offset;
    194 			tmpl->size = shdrp[i].sh_size;
    195 			tmpl->next = rellist;
    196 			rellist = tmpl;
    197 			break;
    198 		}
    199 	}
    200 	if (symtabshdr == NULL)
    201 		goto out;
    202 	if (strtabshdr == NULL)
    203 		weird = 1;
    204 	if (weird) {
    205 		fprintf(stderr, "%s: weird executable (unsupported)\n", fn);
    206 		goto bad;
    207 	}
    208 
    209 	/*
    210 	 * load up everything we need
    211 	 */
    212 
    213 	/* symbol table */
    214 	if ((symtabp = xmalloc(symtabshdr->sh_size, fn, "symbol table"))
    215 	    == NULL)
    216 		goto bad;
    217 	if (xreadatoff(fd, symtabp, symtabshdr->sh_offset, symtabshdr->sh_size,
    218 	    fn) != symtabshdr->sh_size)
    219 		goto bad;
    220 
    221 	/* string table */
    222 	if ((strtabp = xmalloc(strtabshdr->sh_size, fn, "string table"))
    223 	    == NULL)
    224 		goto bad;
    225 	if (xreadatoff(fd, strtabp, strtabshdr->sh_offset, strtabshdr->sh_size,
    226 	    fn) != strtabshdr->sh_size)
    227 		goto bad;
    228 
    229 	/* any rela tables */
    230 	for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) {
    231 		if ((tmpl->mem = xmalloc(tmpl->size, fn, "rela table"))
    232 		    == NULL)
    233 			goto bad;
    234 		if (xreadatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) !=
    235 		    tmpl->size)
    236 			goto bad;
    237 	}
    238 
    239 	/* any rel tables */
    240 	for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) {
    241 		if ((tmpl->mem = xmalloc(tmpl->size, fn, "rel table"))
    242 		    == NULL)
    243 			goto bad;
    244 		if (xreadatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) !=
    245 		    tmpl->size)
    246 			goto bad;
    247 	}
    248 
    249 	/* Prepare data structures for symbol movement. */
    250 	nsyms = symtabshdr->sh_size / symtabshdr->sh_entsize;
    251 	nlocalsyms = symtabshdr->sh_info;
    252 	if ((symfwmap = xmalloc(nsyms * sizeof (Elf_Word), fn,
    253 	    "symbol forward mapping table")) == NULL)
    254 		goto bad;
    255 	if ((symrvmap = xmalloc(nsyms * sizeof (Elf_Word), fn,
    256 	    "symbol reverse mapping table")) == NULL)
    257 		goto bad;
    258 
    259 	/* init location -> symbol # table */
    260 	for (ewi = 0; ewi < nsyms; ewi++)
    261 		symrvmap[ewi] = ewi;
    262 
    263 	/* move symbols, making them local */
    264 	for (ewi = nlocalsyms; ewi < nsyms; ewi++) {
    265 		Elf_Sym *sp, symswap;
    266 		Elf_Word mapswap;
    267 
    268 		sp = &symtabp[ewi];
    269 
    270 		/* if it's on our keep list, don't move it */
    271 		if (in_keep_list(strtabp + sp->st_name))
    272 			continue;
    273 
    274 		/* if it's an undefined symbol, keep it */
    275 		if (sp->st_shndx == Elf_eshn_undefined)
    276 			continue;
    277 
    278 		/* adjust the symbol so that it's local */
    279 		sp->st_info =
    280 		    (Elf_estb_local << 4) | ELF_SYM_TYPE(sp->st_info); /* XXX */
    281 
    282 		/*
    283 		 * move the symbol to its new location
    284 		 */
    285 
    286 		/* note that symbols in those locations have been swapped */
    287 		mapswap = symrvmap[ewi];
    288 		symrvmap[ewi] = symrvmap[nlocalsyms];
    289 		symrvmap[nlocalsyms] = mapswap;
    290 
    291 		/* and swap the symbols */
    292 		symswap = *sp;
    293 		*sp = symtabp[nlocalsyms];
    294 		symtabp[nlocalsyms] = symswap;
    295 
    296 		nlocalsyms++;			/* note new local sym */
    297 	}
    298 	symtabshdr->sh_info = nlocalsyms;
    299 
    300 	/* set up symbol # -> location mapping table */
    301 	for (ewi = 0; ewi < nsyms; ewi++)
    302 		symfwmap[symrvmap[ewi]] = ewi;
    303 
    304 	/* any rela tables */
    305 	for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) {
    306 		Elf_RelA *relap = tmpl->mem;
    307 
    308 		for (ewi = 0; ewi < tmpl->size / sizeof *relap; ewi++) {
    309 			relap[ewi].r_info =
    310 #if (ELFSIZE == 32)					/* XXX */
    311 			    symfwmap[ELF_R_SYM(relap[ewi].r_info)] << 8 |
    312 			    ELF_R_TYPE(relap[ewi].r_info);
    313 #elif (ELFSIZE == 64)					/* XXX */
    314 			    symfwmap[ELF_R_SYM(relap[ewi].r_info)] << 32 |
    315 			    ELF_R_TYPE(relap[ewi].r_info);
    316 #endif							/* XXX */
    317 		}
    318 	}
    319 
    320 	/* any rel tables */
    321 	for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) {
    322 		Elf_Rel *relp = tmpl->mem;
    323 
    324 		for (ewi = 0; ewi < tmpl->size / sizeof *relp; ewi++) {
    325 			relp[ewi].r_info =
    326 #if (ELFSIZE == 32)					/* XXX */
    327 			    symfwmap[ELF_R_SYM(relp[ewi].r_info)] << 8 |
    328 			    ELF_R_TYPE(relp[ewi].r_info);
    329 #elif (ELFSIZE == 64)					/* XXX */
    330 			    symfwmap[ELF_R_SYM(relp[ewi].r_info)] << 32 |
    331 			    ELF_R_TYPE(relp[ewi].r_info);
    332 #endif							/* XXX */
    333 		}
    334 	}
    335 
    336 	/*
    337 	 * write new tables to the file
    338 	 */
    339 	if (xwriteatoff(fd, shdrp, ehdr.e_shoff, shdrsize, fn) != shdrsize)
    340 		goto bad;
    341 	if (xwriteatoff(fd, symtabp, symtabshdr->sh_offset,
    342 	    symtabshdr->sh_size, fn) != symtabshdr->sh_size)
    343 		goto bad;
    344 	for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) {
    345 		if (xwriteatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) !=
    346 		    tmpl->size)
    347 			goto bad;
    348 	}
    349 	for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) {
    350 		if (xwriteatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) !=
    351 		    tmpl->size)
    352 			goto bad;
    353 	}
    354 
    355 out:
    356 	if (shdrp != NULL)
    357 		free(shdrp);
    358 	if (symtabp != NULL)
    359 		free(symtabp);
    360 	if (strtabp != NULL)
    361 		free(strtabp);
    362 	if (symfwmap != NULL)
    363 		free(symfwmap);
    364 	if (symrvmap != NULL)
    365 		free(symrvmap);
    366 	while ((tmpl = relalist) != NULL) {
    367 		relalist = tmpl->next;
    368 		if (tmpl->mem != NULL)
    369 			free(tmpl->mem);
    370 		free(tmpl);
    371 	}
    372 	while ((tmpl = rellist) != NULL) {
    373 		rellist = tmpl->next;
    374 		if (tmpl->mem != NULL)
    375 			free(tmpl->mem);
    376 		free(tmpl);
    377 	}
    378 	return (rv);
    379 
    380 bad:
    381 	rv = 1;
    382 	goto out;
    383 }
    384 
    385 #endif /* include this size of ELF */
    386