Home | History | Annotate | Line # | Download | only in crunchide
exec_elf32.c revision 1.9
      1 /*	$NetBSD: exec_elf32.c,v 1.9 1999/10/25 13:57:11 kleink Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997, 1998 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.9 1999/10/25 13:57:11 kleink 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 static void *
    118 xrealloc(void *ptr, size_t size, const char *fn, const char *use)
    119 {
    120 	void *rv;
    121 
    122 	rv = realloc(ptr, size);
    123 	if (rv == NULL) {
    124 		free(ptr);
    125 		fprintf(stderr, "%s: out of memory (reallocating for %s)\n",
    126 		    fn, use);
    127 	}
    128 	return (rv);
    129 }
    130 
    131 int
    132 ELFNAMEEND(check)(int fd, const char *fn)
    133 {
    134 	Elf_Ehdr eh;
    135 	struct stat sb;
    136 
    137 	/*
    138 	 * Check the header to maek sure it's an ELF file (of the
    139 	 * appropriate size).
    140 	 */
    141 	if (fstat(fd, &sb) == -1)
    142 		return 0;
    143 	if (sb.st_size < sizeof eh)
    144 		return 0;
    145 	if (read(fd, &eh, sizeof eh) != sizeof eh)
    146 		return 0;
    147 
    148 	if (memcmp(eh.e_ident, ELFMAG, SELFMAG) != 0 ||
    149 	    eh.e_ident[EI_CLASS] != ELFCLASS)
    150                 return 0;
    151 
    152         switch (eh.e_machine) {
    153         ELFDEFNNAME(MACHDEP_ID_CASES)
    154 
    155         default:
    156                 return 0;
    157         }
    158 
    159 	return 1;
    160 }
    161 
    162 /*
    163  * This function 'hides' (some of) ELF executable file's symbols.
    164  * It hides them by renaming them to "_$$hide$$ <filename> <symbolname>".
    165  * Symbols in the global keep list, or which are marked as being undefined,
    166  * are left alone.
    167  *
    168  * An old version of this code shuffled various tables around, turning
    169  * global symbols to be hidden into local symbols.  That lost on the
    170  * mips, because CALL16 relocs must reference global symbols, and, if
    171  * those symbols were being hidden, they were no longer global.
    172  *
    173  * The new renaming behaviour doesn't take global symbols out of the
    174  * namespace.  However, it's ... unlikely that there will ever be
    175  * any collisions in practice because of the new method.
    176  */
    177 int
    178 ELFNAMEEND(hide)(int fd, const char *fn)
    179 {
    180 	Elf_Ehdr ehdr;
    181 	Elf_Shdr *shdrp = NULL;
    182 	int symtabsnum, strtabsnum;
    183 	Elf_Sym *symtabp = NULL;
    184 	char *strtabp = NULL, *nstrtabp = NULL;
    185 	Elf_Word nsyms;
    186 	Elf_Off stroff, maxoff;
    187 	const char *weirdreason;
    188 	ssize_t shdrsize;
    189 	size_t nstrtab_size, nstrtab_nextoff, fn_size;
    190 	int rv, i, weird;
    191 
    192 	rv = 0;
    193 	if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr)
    194 		goto bad;
    195 
    196 	shdrsize = ehdr.e_shnum * ehdr.e_shentsize;
    197 	if ((shdrp = xmalloc(shdrsize, fn, "section header table")) == NULL)
    198 		goto bad;
    199 	if (xreadatoff(fd, shdrp, ehdr.e_shoff, shdrsize, fn) != shdrsize)
    200 		goto bad;
    201 
    202 	symtabsnum = strtabsnum = -1;
    203 	maxoff = stroff = 0;
    204 	weird = 0;
    205 	weirdreason = "???";
    206 	for (i = 0; i < ehdr.e_shnum; i++) {
    207 		if (shdrp[i].sh_offset > maxoff) {
    208 			maxoff = shdrp[i].sh_offset;
    209 		}
    210 		switch (shdrp[i].sh_type) {
    211 		case SHT_SYMTAB:
    212 			if (!weird && symtabsnum != -1) {
    213 				weird = 1;
    214 				weirdreason = "multiple symbol tables";
    215 			}
    216 			symtabsnum = i;
    217 			strtabsnum = shdrp[i].sh_link;
    218 			stroff = shdrp[strtabsnum].sh_offset;
    219 			if (!weird && strtabsnum != (ehdr.e_shnum - 1)) {
    220 				weird = 1;
    221 				weirdreason = "string table not last section";
    222 			}
    223 			break;
    224 		}
    225 	}
    226 	if (symtabsnum == -1)
    227 		goto out;
    228 	if (!weird && strtabsnum == -1) {
    229 		weird = 1;
    230 		weirdreason = "no string table found";
    231 	}
    232 	if (!weird && stroff != maxoff) {
    233 		weird = 1;
    234 		weirdreason = "string table section not last in file";
    235 	}
    236 	if (weird) {
    237 		fprintf(stderr, "%s: weird executable (%s); unsupported\n", fn,
    238 		    weirdreason);
    239 		goto bad;
    240 	}
    241 
    242 	/*
    243 	 * load up everything we need
    244 	 */
    245 
    246 	/* symbol table */
    247 	if ((symtabp = xmalloc(shdrp[symtabsnum].sh_size, fn, "symbol table"))
    248 	    == NULL)
    249 		goto bad;
    250 	if (xreadatoff(fd, symtabp, shdrp[symtabsnum].sh_offset,
    251 	    shdrp[symtabsnum].sh_size, fn) != shdrp[symtabsnum].sh_size)
    252 		goto bad;
    253 
    254 	/* string table */
    255 	if ((strtabp = xmalloc(shdrp[strtabsnum].sh_size, fn, "string table"))
    256 	    == NULL)
    257 		goto bad;
    258 	if (xreadatoff(fd, strtabp, shdrp[strtabsnum].sh_offset,
    259 	    shdrp[strtabsnum].sh_size, fn) != shdrp[strtabsnum].sh_size)
    260 		goto bad;
    261 
    262 	nsyms = shdrp[symtabsnum].sh_size / shdrp[symtabsnum].sh_entsize;
    263 
    264 	nstrtab_size = 256;
    265 	nstrtabp = xmalloc(nstrtab_size, fn, "new string table");
    266 	if (nstrtabp == NULL)
    267 		goto bad;
    268 	nstrtab_nextoff = 0;
    269 
    270 	fn_size = strlen(fn);
    271 
    272 	for (i = 0; i < nsyms; i++) {
    273 		Elf_Sym *sp = &symtabp[i];
    274 		const char *symname = strtabp + sp->st_name;
    275 		size_t newent_len;
    276 
    277 		/*
    278 		 * make sure there's size for the next entry, even if it's
    279 		 * as large as it can be.
    280 		 *
    281 		 * "_$$hide$$ <filename> <symname><NUL>" ->
    282 		 *    9 + 3 + sizes of fn and sym name
    283 		 */
    284 		while ((nstrtab_size - nstrtab_nextoff) <
    285 		    strlen(symname) + fn_size + 12) {
    286 			nstrtab_size *= 2;
    287 			nstrtabp = xrealloc(nstrtabp, nstrtab_size, fn,
    288 			    "new string table");
    289 			if (nstrtabp == NULL)
    290 				goto bad;
    291 		}
    292 
    293 		sp->st_name = nstrtab_nextoff;
    294 
    295 		/* if it's a keeper or is undefined, don't rename it. */
    296 		if (in_keep_list(symname) ||
    297 		    sp->st_shndx == SHN_UNDEF) {
    298 			newent_len = sprintf(nstrtabp + nstrtab_nextoff,
    299 			    "%s", symname) + 1;
    300 		} else {
    301 			newent_len = sprintf(nstrtabp + nstrtab_nextoff,
    302 			    "_$$hide$$ %s %s", fn, symname) + 1;
    303 		}
    304 		nstrtab_nextoff += newent_len;
    305 	}
    306 	shdrp[strtabsnum].sh_size = nstrtab_nextoff;
    307 
    308 	/*
    309 	 * write new tables to the file
    310 	 */
    311 	if (xwriteatoff(fd, shdrp, ehdr.e_shoff, shdrsize, fn) != shdrsize)
    312 		goto bad;
    313 	if (xwriteatoff(fd, symtabp, shdrp[symtabsnum].sh_offset,
    314 	    shdrp[symtabsnum].sh_size, fn) != shdrp[symtabsnum].sh_size)
    315 		goto bad;
    316 	if (xwriteatoff(fd, nstrtabp, shdrp[strtabsnum].sh_offset,
    317 	    shdrp[strtabsnum].sh_size, fn) != shdrp[strtabsnum].sh_size)
    318 		goto bad;
    319 
    320 out:
    321 	if (shdrp != NULL)
    322 		free(shdrp);
    323 	if (symtabp != NULL)
    324 		free(symtabp);
    325 	if (strtabp != NULL)
    326 		free(strtabp);
    327 	if (nstrtabp != NULL)
    328 		free(nstrtabp);
    329 	return (rv);
    330 
    331 bad:
    332 	rv = 1;
    333 	goto out;
    334 }
    335 
    336 #endif /* include this size of ELF */
    337