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