exec_elf32.c revision 76224
139172Sjkh/* 239172Sjkh * Copyright (c) 1997 Christopher G. Demetriou. All rights reserved. 339172Sjkh * 439172Sjkh * Redistribution and use in source and binary forms, with or without 539172Sjkh * modification, are permitted provided that the following conditions 639172Sjkh * are met: 739172Sjkh * 1. Redistributions of source code must retain the above copyright 839172Sjkh * notice, this list of conditions and the following disclaimer. 939172Sjkh * 2. Redistributions in binary form must reproduce the above copyright 1039172Sjkh * notice, this list of conditions and the following disclaimer in the 1139172Sjkh * documentation and/or other materials provided with the distribution. 1239172Sjkh * 3. All advertising materials mentioning features or use of this software 1339172Sjkh * must display the following acknowledgement: 1439172Sjkh * This product includes software developed by Christopher G. Demetriou 1539172Sjkh * for the NetBSD Project. 1639172Sjkh * 4. The name of the author may not be used to endorse or promote products 1739172Sjkh * derived from this software without specific prior written permission 1839172Sjkh * 1939172Sjkh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2039172Sjkh * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2139172Sjkh * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2239172Sjkh * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2339172Sjkh * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2439172Sjkh * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2539172Sjkh * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2639172Sjkh * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2739172Sjkh * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2839172Sjkh * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2939172Sjkh */ 3039172Sjkh 3139172Sjkh#include <sys/cdefs.h> 3239172Sjkh#ifndef lint 3376224Sobrien#if 0 3439172Sjkh__RCSID("$NetBSD: exec_elf32.c,v 1.4 1997/08/12 06:07:24 mikel Exp $"); 3539172Sjkh#endif 3676224Sobrienstatic const char rcsid[] = 3776224Sobrien "$FreeBSD: head/usr.sbin/crunch/crunchide/exec_elf32.c 76224 2001-05-02 23:56:21Z obrien $"; 3876224Sobrien#endif 3939172Sjkh 4039172Sjkh#ifndef ELFSIZE 4139172Sjkh#define ELFSIZE 32 4239172Sjkh#endif 4339172Sjkh 4439172Sjkh#include <sys/types.h> 4539172Sjkh#include <sys/stat.h> 4639172Sjkh 4739172Sjkh#include <errno.h> 4839172Sjkh#include <stdio.h> 4939172Sjkh#include <stdlib.h> 5039172Sjkh#include <string.h> 5139172Sjkh#include <unistd.h> 5239172Sjkh 5339172Sjkh#include "extern.h" 5439172Sjkh 5539172Sjkh#if (defined(NLIST_ELF32) && (ELFSIZE == 32)) || \ 5639172Sjkh (defined(NLIST_ELF64) && (ELFSIZE == 64)) 5739172Sjkh 5876224Sobrien#include <machine/elf.h> 5939172Sjkh 6039172Sjkh#define CONCAT(x,y) __CONCAT(x,y) 6139172Sjkh#define ELFNAME(x) CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x))) 6239172Sjkh#define ELFNAME2(x,y) CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y)))) 6339172Sjkh#define ELFNAMEEND(x) CONCAT(x,CONCAT(_elf,ELFSIZE)) 6439172Sjkh#define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x))) 6539172Sjkh 6639172Sjkhstruct listelem { 6739172Sjkh struct listelem *next; 6839172Sjkh void *mem; 6939172Sjkh off_t file; 7039172Sjkh size_t size; 7139172Sjkh}; 7239172Sjkh 7339172Sjkhstatic ssize_t 7439172Sjkhxreadatoff(int fd, void *buf, off_t off, size_t size, const char *fn) 7539172Sjkh{ 7639172Sjkh ssize_t rv; 7739172Sjkh 7839172Sjkh if (lseek(fd, off, SEEK_SET) != off) { 7939172Sjkh perror(fn); 8039172Sjkh return -1; 8139172Sjkh } 8239172Sjkh if ((rv = read(fd, buf, size)) != size) { 8339172Sjkh fprintf(stderr, "%s: read error: %s\n", fn, 8439172Sjkh rv == -1 ? strerror(errno) : "short read"); 8539172Sjkh return -1; 8639172Sjkh } 8739172Sjkh return size; 8839172Sjkh} 8939172Sjkh 9039172Sjkhstatic ssize_t 9139172Sjkhxwriteatoff(int fd, void *buf, off_t off, size_t size, const char *fn) 9239172Sjkh{ 9339172Sjkh ssize_t rv; 9439172Sjkh 9539172Sjkh if (lseek(fd, off, SEEK_SET) != off) { 9639172Sjkh perror(fn); 9739172Sjkh return -1; 9839172Sjkh } 9939172Sjkh if ((rv = write(fd, buf, size)) != size) { 10039172Sjkh fprintf(stderr, "%s: write error: %s\n", fn, 10139172Sjkh rv == -1 ? strerror(errno) : "short write"); 10239172Sjkh return -1; 10339172Sjkh } 10439172Sjkh return size; 10539172Sjkh} 10639172Sjkh 10739172Sjkhstatic void * 10839172Sjkhxmalloc(size_t size, const char *fn, const char *use) 10939172Sjkh{ 11039172Sjkh void *rv; 11139172Sjkh 11239172Sjkh rv = malloc(size); 11339172Sjkh if (rv == NULL) 11439172Sjkh fprintf(stderr, "%s: out of memory (allocating for %s)\n", 11539172Sjkh fn, use); 11639172Sjkh return (rv); 11739172Sjkh} 11839172Sjkh 11939172Sjkhint 12039172SjkhELFNAMEEND(check)(int fd, const char *fn) 12139172Sjkh{ 12239172Sjkh Elf_Ehdr eh; 12339172Sjkh struct stat sb; 12439172Sjkh 12539172Sjkh /* 12639172Sjkh * Check the header to maek sure it's an ELF file (of the 12739172Sjkh * appropriate size). 12839172Sjkh */ 12939172Sjkh if (fstat(fd, &sb) == -1) 13039172Sjkh return 0; 13139172Sjkh if (sb.st_size < sizeof eh) 13239172Sjkh return 0; 13339172Sjkh if (read(fd, &eh, sizeof eh) != sizeof eh) 13439172Sjkh return 0; 13539172Sjkh 13639172Sjkh if (IS_ELF(eh) == 0) 13739172Sjkh return 0; 13839172Sjkh 13939172Sjkh switch (eh.e_machine) { 14039172Sjkh case EM_386: break; 14139172Sjkh case EM_ALPHA: break; 14239172Sjkh/* ELFDEFNNAME(MACHDEP_ID_CASES) */ 14339172Sjkh 14439172Sjkh default: 14539172Sjkh return 0; 14639172Sjkh } 14739172Sjkh 14839172Sjkh return 1; 14939172Sjkh} 15039172Sjkh 15139172Sjkhint 15239172SjkhELFNAMEEND(hide)(int fd, const char *fn) 15339172Sjkh{ 15439172Sjkh Elf_Ehdr ehdr; 15539172Sjkh Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr; 15639172Sjkh Elf_Sym *symtabp = NULL; 15739172Sjkh char *strtabp = NULL; 15839172Sjkh Elf_Word *symfwmap = NULL, *symrvmap = NULL, nsyms, nlocalsyms, ewi; 15939172Sjkh struct listelem *relalist = NULL, *rellist = NULL, *tmpl; 16039172Sjkh ssize_t shdrsize; 16139172Sjkh int rv, i, weird; 16239172Sjkh 16339172Sjkh rv = 0; 16439172Sjkh if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr) 16539172Sjkh goto bad; 16639172Sjkh 16739172Sjkh shdrsize = ehdr.e_shnum * ehdr.e_shentsize; 16839172Sjkh if ((shdrp = xmalloc(shdrsize, fn, "section header table")) == NULL) 16939172Sjkh goto bad; 17039172Sjkh if (xreadatoff(fd, shdrp, ehdr.e_shoff, shdrsize, fn) != shdrsize) 17139172Sjkh goto bad; 17239172Sjkh 17339172Sjkh symtabshdr = strtabshdr = NULL; 17439172Sjkh weird = 0; 17539172Sjkh for (i = 0; i < ehdr.e_shnum; i++) { 17639172Sjkh switch (shdrp[i].sh_type) { 17739172Sjkh case SHT_SYMTAB: 17839172Sjkh if (symtabshdr != NULL) 17939172Sjkh weird = 1; 18039172Sjkh symtabshdr = &shdrp[i]; 18139172Sjkh strtabshdr = &shdrp[shdrp[i].sh_link]; 18239172Sjkh break; 18339172Sjkh case SHT_RELA: 18439172Sjkh tmpl = xmalloc(sizeof *tmpl, fn, "rela list element"); 18539172Sjkh if (tmpl == NULL) 18639172Sjkh goto bad; 18739172Sjkh tmpl->mem = NULL; 18839172Sjkh tmpl->file = shdrp[i].sh_offset; 18939172Sjkh tmpl->size = shdrp[i].sh_size; 19039172Sjkh tmpl->next = relalist; 19139172Sjkh relalist = tmpl; 19239172Sjkh break; 19339172Sjkh case SHT_REL: 19439172Sjkh tmpl = xmalloc(sizeof *tmpl, fn, "rel list element"); 19539172Sjkh if (tmpl == NULL) 19639172Sjkh goto bad; 19739172Sjkh tmpl->mem = NULL; 19839172Sjkh tmpl->file = shdrp[i].sh_offset; 19939172Sjkh tmpl->size = shdrp[i].sh_size; 20039172Sjkh tmpl->next = rellist; 20139172Sjkh rellist = tmpl; 20239172Sjkh break; 20339172Sjkh } 20439172Sjkh } 20539172Sjkh if (symtabshdr == NULL) 20639172Sjkh goto out; 20739172Sjkh if (strtabshdr == NULL) 20839172Sjkh weird = 1; 20939172Sjkh if (weird) { 21039172Sjkh fprintf(stderr, "%s: weird executable (unsupported)\n", fn); 21139172Sjkh goto bad; 21239172Sjkh } 21339172Sjkh 21439172Sjkh /* 21539172Sjkh * load up everything we need 21639172Sjkh */ 21739172Sjkh 21839172Sjkh /* symbol table */ 21939172Sjkh if ((symtabp = xmalloc(symtabshdr->sh_size, fn, "symbol table")) 22039172Sjkh == NULL) 22139172Sjkh goto bad; 22239172Sjkh if (xreadatoff(fd, symtabp, symtabshdr->sh_offset, symtabshdr->sh_size, 22339172Sjkh fn) != symtabshdr->sh_size) 22439172Sjkh goto bad; 22539172Sjkh 22639172Sjkh /* string table */ 22739172Sjkh if ((strtabp = xmalloc(strtabshdr->sh_size, fn, "string table")) 22839172Sjkh == NULL) 22939172Sjkh goto bad; 23039172Sjkh if (xreadatoff(fd, strtabp, strtabshdr->sh_offset, strtabshdr->sh_size, 23139172Sjkh fn) != strtabshdr->sh_size) 23239172Sjkh goto bad; 23339172Sjkh 23439172Sjkh /* any rela tables */ 23539172Sjkh for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) { 23639172Sjkh if ((tmpl->mem = xmalloc(tmpl->size, fn, "rela table")) 23739172Sjkh == NULL) 23839172Sjkh goto bad; 23939172Sjkh if (xreadatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) != 24039172Sjkh tmpl->size) 24139172Sjkh goto bad; 24239172Sjkh } 24339172Sjkh 24439172Sjkh /* any rel tables */ 24539172Sjkh for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) { 24639172Sjkh if ((tmpl->mem = xmalloc(tmpl->size, fn, "rel table")) 24739172Sjkh == NULL) 24839172Sjkh goto bad; 24939172Sjkh if (xreadatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) != 25039172Sjkh tmpl->size) 25139172Sjkh goto bad; 25239172Sjkh } 25339172Sjkh 25439172Sjkh /* Prepare data structures for symbol movement. */ 25539172Sjkh nsyms = symtabshdr->sh_size / symtabshdr->sh_entsize; 25639172Sjkh nlocalsyms = symtabshdr->sh_info; 25739172Sjkh if ((symfwmap = xmalloc(nsyms * sizeof (Elf_Word), fn, 25839172Sjkh "symbol forward mapping table")) == NULL) 25939172Sjkh goto bad; 26039172Sjkh if ((symrvmap = xmalloc(nsyms * sizeof (Elf_Word), fn, 26139172Sjkh "symbol reverse mapping table")) == NULL) 26239172Sjkh goto bad; 26339172Sjkh 26439172Sjkh /* init location -> symbol # table */ 26539172Sjkh for (ewi = 0; ewi < nsyms; ewi++) 26639172Sjkh symrvmap[ewi] = ewi; 26739172Sjkh 26839172Sjkh /* move symbols, making them local */ 26939172Sjkh for (ewi = nlocalsyms; ewi < nsyms; ewi++) { 27039172Sjkh Elf_Sym *sp, symswap; 27139172Sjkh Elf_Word mapswap; 27239172Sjkh 27339172Sjkh sp = &symtabp[ewi]; 27439172Sjkh 27539172Sjkh /* if it's on our keep list, don't move it */ 27639172Sjkh if (in_keep_list(strtabp + sp->st_name)) 27739172Sjkh continue; 27839172Sjkh 27939172Sjkh /* if it's an undefined symbol, keep it */ 28039172Sjkh if (sp->st_shndx == SHN_UNDEF) 28139172Sjkh continue; 28239172Sjkh 28339172Sjkh /* adjust the symbol so that it's local */ 28439172Sjkh sp->st_info = 28539172Sjkh ELF_ST_INFO(STB_LOCAL, sp->st_info); 28639172Sjkh/* (STB_LOCAL << 4) | ELF_SYM_TYPE(sp->st_info); *//* XXX */ 28739172Sjkh 28839172Sjkh /* 28939172Sjkh * move the symbol to its new location 29039172Sjkh */ 29139172Sjkh 29239172Sjkh /* note that symbols in those locations have been swapped */ 29339172Sjkh mapswap = symrvmap[ewi]; 29439172Sjkh symrvmap[ewi] = symrvmap[nlocalsyms]; 29539172Sjkh symrvmap[nlocalsyms] = mapswap; 29639172Sjkh 29739172Sjkh /* and swap the symbols */ 29839172Sjkh symswap = *sp; 29939172Sjkh *sp = symtabp[nlocalsyms]; 30039172Sjkh symtabp[nlocalsyms] = symswap; 30139172Sjkh 30239172Sjkh nlocalsyms++; /* note new local sym */ 30339172Sjkh } 30439172Sjkh symtabshdr->sh_info = nlocalsyms; 30539172Sjkh 30639172Sjkh /* set up symbol # -> location mapping table */ 30739172Sjkh for (ewi = 0; ewi < nsyms; ewi++) 30839172Sjkh symfwmap[symrvmap[ewi]] = ewi; 30939172Sjkh 31039172Sjkh /* any rela tables */ 31139172Sjkh for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) { 31239172Sjkh Elf_Rela *relap = tmpl->mem; 31339172Sjkh 31439172Sjkh for (ewi = 0; ewi < tmpl->size / sizeof(*relap); ewi++) { 31539172Sjkh relap[ewi].r_info = 31639172Sjkh#if (ELFSIZE == 32) /* XXX */ 31739172Sjkh symfwmap[ELF_R_SYM(relap[ewi].r_info)] << 8 | 31839172Sjkh ELF_R_TYPE(relap[ewi].r_info); 31939172Sjkh#elif (ELFSIZE == 64) /* XXX */ 32039172Sjkh symfwmap[ELF_R_SYM(relap[ewi].r_info)] << 32 | 32139172Sjkh ELF_R_TYPE(relap[ewi].r_info); 32239172Sjkh#endif /* XXX */ 32339172Sjkh } 32439172Sjkh } 32539172Sjkh 32639172Sjkh /* any rel tables */ 32739172Sjkh for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) { 32839172Sjkh Elf_Rel *relp = tmpl->mem; 32939172Sjkh 33039172Sjkh for (ewi = 0; ewi < tmpl->size / sizeof *relp; ewi++) { 33139172Sjkh relp[ewi].r_info = 33239172Sjkh#if (ELFSIZE == 32) /* XXX */ 33339172Sjkh symfwmap[ELF_R_SYM(relp[ewi].r_info)] << 8 | 33439172Sjkh ELF_R_TYPE(relp[ewi].r_info); 33539172Sjkh#elif (ELFSIZE == 64) /* XXX */ 33639172Sjkh symfwmap[ELF_R_SYM(relp[ewi].r_info)] << 32 | 33739172Sjkh ELF_R_TYPE(relp[ewi].r_info); 33839172Sjkh#endif /* XXX */ 33939172Sjkh } 34039172Sjkh } 34139172Sjkh 34239172Sjkh /* 34339172Sjkh * write new tables to the file 34439172Sjkh */ 34539172Sjkh if (xwriteatoff(fd, shdrp, ehdr.e_shoff, shdrsize, fn) != shdrsize) 34639172Sjkh goto bad; 34739172Sjkh if (xwriteatoff(fd, symtabp, symtabshdr->sh_offset, 34839172Sjkh symtabshdr->sh_size, fn) != symtabshdr->sh_size) 34939172Sjkh goto bad; 35039172Sjkh for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) { 35139172Sjkh if (xwriteatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) != 35239172Sjkh tmpl->size) 35339172Sjkh goto bad; 35439172Sjkh } 35539172Sjkh for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) { 35639172Sjkh if (xwriteatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) != 35739172Sjkh tmpl->size) 35839172Sjkh goto bad; 35939172Sjkh } 36039172Sjkh 36139172Sjkhout: 36239172Sjkh if (shdrp != NULL) 36339172Sjkh free(shdrp); 36439172Sjkh if (symtabp != NULL) 36539172Sjkh free(symtabp); 36639172Sjkh if (strtabp != NULL) 36739172Sjkh free(strtabp); 36839172Sjkh if (symfwmap != NULL) 36939172Sjkh free(symfwmap); 37039172Sjkh if (symrvmap != NULL) 37139172Sjkh free(symrvmap); 37239172Sjkh while ((tmpl = relalist) != NULL) { 37339172Sjkh relalist = tmpl->next; 37439172Sjkh if (tmpl->mem != NULL) 37539172Sjkh free(tmpl->mem); 37639172Sjkh free(tmpl); 37739172Sjkh } 37839172Sjkh while ((tmpl = rellist) != NULL) { 37939172Sjkh rellist = tmpl->next; 38039172Sjkh if (tmpl->mem != NULL) 38139172Sjkh free(tmpl->mem); 38239172Sjkh free(tmpl); 38339172Sjkh } 38439172Sjkh return (rv); 38539172Sjkh 38639172Sjkhbad: 38739172Sjkh rv = 1; 38839172Sjkh goto out; 38939172Sjkh} 39039172Sjkh 39139172Sjkh#endif /* include this size of ELF */ 392