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