1/* $NetBSD: exec_elf32.c,v 1.13 2003/07/26 20:34:12 salo 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.13 2003/07/26 20:34:12 salo 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 62struct listelem { 63 struct listelem *next; 64 void *mem; 65 off_t file; 66 size_t size; 67}; 68 69static ssize_t 70xreadatoff(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 86static ssize_t 87xwriteatoff(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 103static void * 104xmalloc(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 115static void * 116xrealloc(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 129int 130ELFNAMEEND(check)(int fd, const char *fn) 131{ 132 Elf_Ehdr eh; 133 struct stat sb; 134 135 /* 136 * Check the header to maek 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 */ 175int 176ELFNAMEEND(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 318out: 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 329bad: 330 rv = 1; 331 goto out; 332} 333 334#endif /* include this size of ELF */ 335