Home | History | Annotate | Line # | Download | only in crunchide
      1 /* $NetBSD: exec_elf32.c,v 1.15 2022/07/08 17:47:47 andvar Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1997, 1998 Christopher G. Demetriou
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *          This product includes software developed for the
     18  *          NetBSD Project.  See http://www.NetBSD.org/ for
     19  *          information about NetBSD.
     20  * 4. The name of the author may not be used to endorse or promote products
     21  *    derived from this software without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     33  *
     34  * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
     35  */
     36 
     37 #include <sys/cdefs.h>
     38 #ifndef lint
     39 __RCSID("$NetBSD: exec_elf32.c,v 1.15 2022/07/08 17:47:47 andvar Exp $");
     40 #endif
     41 
     42 #ifndef ELFSIZE
     43 #define ELFSIZE         32
     44 #endif
     45 
     46 #include <sys/types.h>
     47 #include <sys/stat.h>
     48 
     49 #include <errno.h>
     50 #include <stdio.h>
     51 #include <stdlib.h>
     52 #include <string.h>
     53 #include <unistd.h>
     54 
     55 #include "extern.h"
     56 
     57 #if (defined(NLIST_ELF32) && (ELFSIZE == 32)) || \
     58     (defined(NLIST_ELF64) && (ELFSIZE == 64))
     59 
     60 #include <sys/exec_elf.h>
     61 
     62 struct listelem {
     63 	struct listelem *next;
     64 	void *mem;
     65 	off_t file;
     66 	size_t size;
     67 };
     68 
     69 static ssize_t
     70 xreadatoff(int fd, void *buf, off_t off, size_t size, const char *fn)
     71 {
     72 	ssize_t rv;
     73 
     74 	if (lseek(fd, off, SEEK_SET) != off) {
     75 		perror(fn);
     76 		return -1;
     77 	}
     78 	if ((size_t)(rv = read(fd, buf, size)) != size) {
     79 		fprintf(stderr, "%s: read error: %s\n", fn,
     80 		    rv == -1 ? strerror(errno) : "short read");
     81 		return -1;
     82 	}
     83 	return size;
     84 }
     85 
     86 static ssize_t
     87 xwriteatoff(int fd, void *buf, off_t off, size_t size, const char *fn)
     88 {
     89 	ssize_t rv;
     90 
     91 	if (lseek(fd, off, SEEK_SET) != off) {
     92 		perror(fn);
     93 		return -1;
     94 	}
     95 	if ((size_t)(rv = write(fd, buf, size)) != size) {
     96 		fprintf(stderr, "%s: write error: %s\n", fn,
     97 		    rv == -1 ? strerror(errno) : "short write");
     98 		return -1;
     99 	}
    100 	return size;
    101 }
    102 
    103 static void *
    104 xmalloc(size_t size, const char *fn, const char *use)
    105 {
    106 	void *rv;
    107 
    108 	rv = malloc(size);
    109 	if (rv == NULL)
    110 		fprintf(stderr, "%s: out of memory (allocating for %s)\n",
    111 		    fn, use);
    112 	return (rv);
    113 }
    114 
    115 static void *
    116 xrealloc(void *ptr, size_t size, const char *fn, const char *use)
    117 {
    118 	void *rv;
    119 
    120 	rv = realloc(ptr, size);
    121 	if (rv == NULL) {
    122 		free(ptr);
    123 		fprintf(stderr, "%s: out of memory (reallocating for %s)\n",
    124 		    fn, use);
    125 	}
    126 	return (rv);
    127 }
    128 
    129 int
    130 ELFNAMEEND(check)(int fd, const char *fn)
    131 {
    132 	Elf_Ehdr eh;
    133 	struct stat sb;
    134 
    135 	/*
    136 	 * Check the header to make sure it's an ELF file (of the
    137 	 * appropriate size).
    138 	 */
    139 	if (fstat(fd, &sb) == -1)
    140 		return 0;
    141 	if (sb.st_size < (off_t)(sizeof eh))
    142 		return 0;
    143 	if (read(fd, &eh, sizeof eh) != sizeof eh)
    144 		return 0;
    145 
    146 	if (memcmp(eh.e_ident, ELFMAG, SELFMAG) != 0 ||
    147 	    eh.e_ident[EI_CLASS] != ELFCLASS)
    148                 return 0;
    149 
    150         switch (eh.e_machine) {
    151         ELFDEFNNAME(MACHDEP_ID_CASES)
    152 
    153         default:
    154                 return 0;
    155         }
    156 
    157 	return 1;
    158 }
    159 
    160 /*
    161  * This function 'hides' (some of) ELF executable file's symbols.
    162  * It hides them by renaming them to "_$$hide$$ <filename> <symbolname>".
    163  * Symbols in the global keep list, or which are marked as being undefined,
    164  * are left alone.
    165  *
    166  * An old version of this code shuffled various tables around, turning
    167  * global symbols to be hidden into local symbols.  That lost on the
    168  * mips, because CALL16 relocs must reference global symbols, and, if
    169  * those symbols were being hidden, they were no longer global.
    170  *
    171  * The new renaming behaviour doesn't take global symbols out of the
    172  * namespace.  However, it's ... unlikely that there will ever be
    173  * any collisions in practice because of the new method.
    174  */
    175 int
    176 ELFNAMEEND(hide)(int fd, const char *fn)
    177 {
    178 	Elf_Ehdr ehdr;
    179 	Elf_Shdr *shdrp = NULL;
    180 	int symtabsnum, strtabsnum;
    181 	Elf_Sym *symtabp = NULL;
    182 	char *strtabp = NULL, *nstrtabp = NULL;
    183 	Elf_Word j, nsyms;
    184 	Elf_Off stroff, maxoff;
    185 	const char *weirdreason;
    186 	ssize_t shdrsize;
    187 	size_t nstrtab_size, nstrtab_nextoff, fn_size;
    188 	int rv, i, weird;
    189 
    190 	rv = 0;
    191 	if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr)
    192 		goto bad;
    193 
    194 	shdrsize = ehdr.e_shnum * ehdr.e_shentsize;
    195 	if ((shdrp = xmalloc(shdrsize, fn, "section header table")) == NULL)
    196 		goto bad;
    197 	if (xreadatoff(fd, shdrp, ehdr.e_shoff, shdrsize, fn) != shdrsize)
    198 		goto bad;
    199 
    200 	symtabsnum = strtabsnum = -1;
    201 	maxoff = stroff = 0;
    202 	weird = 0;
    203 	weirdreason = "???";
    204 	for (i = 0; i < ehdr.e_shnum; i++) {
    205 		if (shdrp[i].sh_offset > maxoff) {
    206 			maxoff = shdrp[i].sh_offset;
    207 		}
    208 		switch (shdrp[i].sh_type) {
    209 		case SHT_SYMTAB:
    210 			if (!weird && symtabsnum != -1) {
    211 				weird = 1;
    212 				weirdreason = "multiple symbol tables";
    213 			}
    214 			symtabsnum = i;
    215 			strtabsnum = shdrp[i].sh_link;
    216 			stroff = shdrp[strtabsnum].sh_offset;
    217 			if (!weird && strtabsnum != (ehdr.e_shnum - 1)) {
    218 				weird = 1;
    219 				weirdreason = "string table not last section";
    220 			}
    221 			break;
    222 		}
    223 	}
    224 	if (symtabsnum == -1)
    225 		goto out;
    226 	if (!weird && strtabsnum == -1) {
    227 		weird = 1;
    228 		weirdreason = "no string table found";
    229 	}
    230 	if (!weird && stroff != maxoff) {
    231 		weird = 1;
    232 		weirdreason = "string table section not last in file";
    233 	}
    234 	if (weird) {
    235 		fprintf(stderr, "%s: weird executable (%s); unsupported\n", fn,
    236 		    weirdreason);
    237 		goto bad;
    238 	}
    239 
    240 	/*
    241 	 * load up everything we need
    242 	 */
    243 
    244 	/* symbol table */
    245 	if ((symtabp = xmalloc(shdrp[symtabsnum].sh_size, fn, "symbol table"))
    246 	    == NULL)
    247 		goto bad;
    248 	if ((size_t)xreadatoff(fd, symtabp, shdrp[symtabsnum].sh_offset,
    249 	    shdrp[symtabsnum].sh_size, fn) != shdrp[symtabsnum].sh_size)
    250 		goto bad;
    251 
    252 	/* string table */
    253 	if ((strtabp = xmalloc(shdrp[strtabsnum].sh_size, fn, "string table"))
    254 	    == NULL)
    255 		goto bad;
    256 	if ((size_t)xreadatoff(fd, strtabp, shdrp[strtabsnum].sh_offset,
    257 	    shdrp[strtabsnum].sh_size, fn) != shdrp[strtabsnum].sh_size)
    258 		goto bad;
    259 
    260 	nsyms = shdrp[symtabsnum].sh_size / shdrp[symtabsnum].sh_entsize;
    261 
    262 	nstrtab_size = 256;
    263 	nstrtabp = xmalloc(nstrtab_size, fn, "new string table");
    264 	if (nstrtabp == NULL)
    265 		goto bad;
    266 	nstrtab_nextoff = 0;
    267 
    268 	fn_size = strlen(fn);
    269 
    270 	for (j = 0; j < nsyms; j++) {
    271 		Elf_Sym *sp = &symtabp[j];
    272 		const char *symname = strtabp + sp->st_name;
    273 		size_t newent_len;
    274 
    275 		/*
    276 		 * make sure there's size for the next entry, even if it's
    277 		 * as large as it can be.
    278 		 *
    279 		 * "_$$hide$$ <filename> <symname><NUL>" ->
    280 		 *    9 + 3 + sizes of fn and sym name
    281 		 */
    282 		while ((nstrtab_size - nstrtab_nextoff) <
    283 		    strlen(symname) + fn_size + 12) {
    284 			nstrtab_size *= 2;
    285 			nstrtabp = xrealloc(nstrtabp, nstrtab_size, fn,
    286 			    "new string table");
    287 			if (nstrtabp == NULL)
    288 				goto bad;
    289 		}
    290 
    291 		sp->st_name = nstrtab_nextoff;
    292 
    293 		/* if it's a keeper or is undefined, don't rename it. */
    294 		if (in_keep_list(symname) ||
    295 		    sp->st_shndx == SHN_UNDEF) {
    296 			newent_len = sprintf(nstrtabp + nstrtab_nextoff,
    297 			    "%s", symname) + 1;
    298 		} else {
    299 			newent_len = sprintf(nstrtabp + nstrtab_nextoff,
    300 			    "_$$hide$$ %s %s", fn, symname) + 1;
    301 		}
    302 		nstrtab_nextoff += newent_len;
    303 	}
    304 	shdrp[strtabsnum].sh_size = nstrtab_nextoff;
    305 
    306 	/*
    307 	 * write new tables to the file
    308 	 */
    309 	if (xwriteatoff(fd, shdrp, ehdr.e_shoff, shdrsize, fn) != shdrsize)
    310 		goto bad;
    311 	if ((size_t)xwriteatoff(fd, symtabp, shdrp[symtabsnum].sh_offset,
    312 	    shdrp[symtabsnum].sh_size, fn) != shdrp[symtabsnum].sh_size)
    313 		goto bad;
    314 	if ((size_t)xwriteatoff(fd, nstrtabp, shdrp[strtabsnum].sh_offset,
    315 	    shdrp[strtabsnum].sh_size, fn) != shdrp[strtabsnum].sh_size)
    316 		goto bad;
    317 
    318 out:
    319 	if (shdrp != NULL)
    320 		free(shdrp);
    321 	if (symtabp != NULL)
    322 		free(symtabp);
    323 	if (strtabp != NULL)
    324 		free(strtabp);
    325 	if (nstrtabp != NULL)
    326 		free(nstrtabp);
    327 	return (rv);
    328 
    329 bad:
    330 	rv = 1;
    331 	goto out;
    332 }
    333 
    334 #endif /* include this size of ELF */
    335