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