Path: blob/main/usr.sbin/crunch/crunchide/exec_elf32.c
103755 views
/*-1* SPDX-License-Identifier: BSD-4-Clause2*3* Copyright (c) 1997 Christopher G. Demetriou. All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13* 3. All advertising materials mentioning features or use of this software14* must display the following acknowledgement:15* This product includes software developed by Christopher G. Demetriou16* for the NetBSD Project.17* 4. The name of the author may not be used to endorse or promote products18* derived from this software without specific prior written permission19*20* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR21* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES22* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.23* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,24* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT25* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,26* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY27* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT28* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF29* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.30*/3132#include <sys/cdefs.h>33#ifndef lint34#if 035__RCSID("$NetBSD: exec_elf32.c,v 1.6 1999/09/20 04:12:16 christos Exp $");36#endif37#endif38#ifndef ELFSIZE39#define ELFSIZE 3240#endif4142#include <sys/types.h>43#include <sys/endian.h>44#include <sys/stat.h>4546#include <errno.h>47#include <limits.h>48#include <stddef.h>49#include <stdio.h>50#include <stdlib.h>51#include <string.h>52#include <unistd.h>5354#include "extern.h"5556#if (defined(NLIST_ELF32) && (ELFSIZE == 32)) || \57(defined(NLIST_ELF64) && (ELFSIZE == 64))5859#define __ELF_WORD_SIZE ELFSIZE60#if (ELFSIZE == 32)61#include <sys/elf32.h>62#define xewtoh(x) ((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))63#define htoxew(x) ((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))64#define wewtoh(x) ((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))65#define htowew(x) ((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))66#elif (ELFSIZE == 64)67#include <sys/elf64.h>68#define xewtoh(x) ((data == ELFDATA2MSB) ? be64toh(x) : le64toh(x))69#define htoxew(x) ((data == ELFDATA2MSB) ? htobe64(x) : htole64(x))70/* elf64 Elf64_Word are 32 bits */71#define wewtoh(x) ((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))72#define htowew(x) ((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))73#endif74#include <sys/elf_generic.h>7576#define CONCAT(x,y) __CONCAT(x,y)77#define ELFNAME(x) CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x)))78#define ELFNAME2(x,y) CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y))))79#define ELFNAMEEND(x) CONCAT(x,CONCAT(_elf,ELFSIZE))80#define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x)))81#ifndef ELFCLASS82#define ELFCLASS CONCAT(ELFCLASS,ELFSIZE)83#endif8485#define xe16toh(x) ((data == ELFDATA2MSB) ? be16toh(x) : le16toh(x))86#define xe32toh(x) ((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))87#define htoxe32(x) ((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))8889struct shlayout {90Elf_Shdr *shdr;91void *bufp;92};9394static ssize_t95xreadatoff(int fd, void *buf, off_t off, size_t size, const char *fn)96{97ssize_t rv;9899if (lseek(fd, off, SEEK_SET) != off) {100perror(fn);101return -1;102}103if ((size_t)(rv = read(fd, buf, size)) != size) {104fprintf(stderr, "%s: read error: %s\n", fn,105rv == -1 ? strerror(errno) : "short read");106return -1;107}108return size;109}110111static ssize_t112xwriteatoff(int fd, void *buf, off_t off, size_t size, const char *fn)113{114ssize_t rv;115116if (lseek(fd, off, SEEK_SET) != off) {117perror(fn);118return -1;119}120if ((size_t)(rv = write(fd, buf, size)) != size) {121fprintf(stderr, "%s: write error: %s\n", fn,122rv == -1 ? strerror(errno) : "short write");123return -1;124}125return size;126}127128static void *129xmalloc(size_t size, const char *fn, const char *use)130{131void *rv;132133rv = malloc(size);134if (rv == NULL)135fprintf(stderr, "%s: out of memory (allocating for %s)\n",136fn, use);137return (rv);138}139140static void *141xrealloc(void *ptr, size_t size, const char *fn, const char *use)142{143void *rv;144145rv = realloc(ptr, size);146if (rv == NULL) {147free(ptr);148fprintf(stderr, "%s: out of memory (reallocating for %s)\n",149fn, use);150}151return (rv);152}153154int155ELFNAMEEND(check)(int fd, const char *fn __unused)156{157Elf_Ehdr eh;158struct stat sb;159unsigned char data;160161/*162* Check the header to make sure it's an ELF file (of the163* appropriate size).164*/165if (fstat(fd, &sb) == -1)166return 0;167if (sb.st_size < (off_t)(sizeof eh))168return 0;169if (read(fd, &eh, sizeof eh) != sizeof eh)170return 0;171172if (IS_ELF(eh) == 0 || eh.e_ident[EI_CLASS] != ELFCLASS)173return 0;174175data = eh.e_ident[EI_DATA];176177switch (xe16toh(eh.e_machine)) {178case EM_386: break;179case EM_ALPHA: break;180#ifndef EM_AARCH64181#define EM_AARCH64 183182#endif183case EM_AARCH64: break;184case EM_ARM: break;185case EM_MIPS: break;186case /* EM_MIPS_RS3_LE */ EM_MIPS_RS4_BE: break;187case EM_PPC: break;188case EM_PPC64: break;189#ifndef EM_RISCV190#define EM_RISCV 243191#endif192case EM_RISCV: break;193case EM_S390: break;194case EM_SPARCV9: break;195case EM_X86_64: break;196/* ELFDEFNNAME(MACHDEP_ID_CASES) */197198default:199return 0;200}201202return 1;203}204205/*206* This function 'hides' (some of) ELF executable file's symbols.207* It hides them by renaming them to "_$$hide$$ <filename> <symbolname>".208* Symbols in the global keep list, or which are marked as being undefined,209* are left alone.210*211* An old version of this code shuffled various tables around, turning212* global symbols to be hidden into local symbols. That lost on the213* mips, because CALL16 relocs must reference global symbols, and, if214* those symbols were being hidden, they were no longer global.215*216* The new renaming behaviour doesn't take global symbols out of the217* namespace. However, it's ... unlikely that there will ever be218* any collisions in practice because of the new method.219*/220int221ELFNAMEEND(hide)(int fd, const char *fn)222{223Elf_Ehdr ehdr;224struct shlayout *layoutp = NULL;225Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr, *shstrtabshdr;226Elf_Shdr shdrshdr;227Elf_Sym *symtabp = NULL;228char *shstrtabp = NULL, *strtabp = NULL;229Elf_Size nsyms, ewi;230Elf_Off off;231ssize_t shdrsize;232int rv, i, weird, l, m, r, strtabidx;233size_t nstrtab_size, nstrtab_nextoff, fn_size, size;234char *nstrtabp = NULL;235unsigned char data;236const char *weirdreason = NULL;237void *buf;238Elf_Half shnum;239240rv = 0;241if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr)242goto bad;243244data = ehdr.e_ident[EI_DATA];245shnum = xe16toh(ehdr.e_shnum);246247shdrsize = shnum * xe16toh(ehdr.e_shentsize);248if ((shdrp = xmalloc(shdrsize, fn, "section header table")) == NULL)249goto bad;250if (xreadatoff(fd, shdrp, xewtoh(ehdr.e_shoff), shdrsize, fn) !=251shdrsize)252goto bad;253254symtabshdr = strtabshdr = shstrtabshdr = NULL;255weird = 0;256for (i = 0; i < shnum; i++) {257switch (xe32toh(shdrp[i].sh_type)) {258case SHT_SYMTAB:259if (symtabshdr != NULL) {260weird = 1;261weirdreason = "multiple symbol tables";262}263symtabshdr = &shdrp[i];264strtabshdr = &shdrp[xe32toh(shdrp[i].sh_link)];265break;266case SHT_STRTAB:267if (i == xe16toh(ehdr.e_shstrndx))268shstrtabshdr = &shdrp[i];269break;270}271}272if (symtabshdr == NULL)273goto out;274if (strtabshdr == NULL) {275weird = 1;276weirdreason = "string table does not exist";277}278if (shstrtabshdr == NULL) {279weird = 1;280weirdreason = "section header string table does not exist";281}282if (strtabshdr == shstrtabshdr) {283weird = 1;284weirdreason = "combined strtab and shstrtab not supported";285}286if (weirdreason == NULL)287weirdreason = "unsupported";288if (weird) {289fprintf(stderr, "%s: weird executable (%s)\n", fn, weirdreason);290goto bad;291}292293/*294* sort section layout table by offset295*/296layoutp = xmalloc((shnum + 1) * sizeof(struct shlayout),297fn, "layout table");298if (layoutp == NULL)299goto bad;300301/* add a pseudo entry to represent the section header table */302shdrshdr.sh_offset = ehdr.e_shoff;303shdrshdr.sh_size = htoxew(shdrsize);304shdrshdr.sh_addralign = htoxew(ELFSIZE / 8);305layoutp[shnum].shdr = &shdrshdr;306307/* insert and sort normal section headers */308for (i = shnum; i-- != 0;) {309l = i + 1;310r = shnum;311while (l <= r) {312m = ( l + r) / 2;313if (xewtoh(shdrp[i].sh_offset) >314xewtoh(layoutp[m].shdr->sh_offset))315l = m + 1;316else317r = m - 1;318}319320if (r != i) {321memmove(&layoutp[i], &layoutp[i + 1],322sizeof(struct shlayout) * (r - i));323}324325layoutp[r].shdr = &shdrp[i];326layoutp[r].bufp = NULL;327}328++shnum;329330/*331* load up everything we need332*/333334/* load section string table for debug use */335if ((size = xewtoh(shstrtabshdr->sh_size)) == 0)336goto bad;337if ((shstrtabp = xmalloc(size, fn, "section string table")) == NULL)338goto bad;339if ((size_t)xreadatoff(fd, shstrtabp, xewtoh(shstrtabshdr->sh_offset),340size, fn) != size)341goto bad;342if (shstrtabp[size - 1] != '\0')343goto bad;344345/* we need symtab, strtab, and everything behind strtab */346strtabidx = INT_MAX;347for (i = 0; i < shnum; i++) {348if (layoutp[i].shdr == &shdrshdr) {349/* not load section header again */350layoutp[i].bufp = shdrp;351continue;352}353if (layoutp[i].shdr == shstrtabshdr) {354/* not load section string table again */355layoutp[i].bufp = shstrtabp;356continue;357}358359if (layoutp[i].shdr == strtabshdr)360strtabidx = i;361if (layoutp[i].shdr == symtabshdr || i >= strtabidx) {362off = xewtoh(layoutp[i].shdr->sh_offset);363if ((size = xewtoh(layoutp[i].shdr->sh_size)) == 0)364goto bad;365layoutp[i].bufp = xmalloc(size, fn,366shstrtabp + xewtoh(layoutp[i].shdr->sh_name));367if (layoutp[i].bufp == NULL)368goto bad;369if ((size_t)xreadatoff(fd, layoutp[i].bufp, off, size, fn) !=370size)371goto bad;372373/* set symbol table and string table */374if (layoutp[i].shdr == symtabshdr) {375symtabp = layoutp[i].bufp;376} else if (layoutp[i].shdr == strtabshdr) {377strtabp = layoutp[i].bufp;378if (strtabp[size - 1] != '\0')379goto bad;380}381}382}383384nstrtab_size = 256;385nstrtabp = xmalloc(nstrtab_size, fn, "new string table");386if (nstrtabp == NULL)387goto bad;388nstrtab_nextoff = 0;389390fn_size = strlen(fn);391392/* Prepare data structures for symbol movement. */393nsyms = xewtoh(symtabshdr->sh_size) / xewtoh(symtabshdr->sh_entsize);394395/* move symbols, making them local */396for (ewi = 0; ewi < nsyms; ewi++) {397Elf_Sym *sp = &symtabp[ewi];398const char *symname = strtabp + xe32toh(sp->st_name);399size_t newent_len;400/*401* make sure there's size for the next entry, even if it's402* as large as it can be.403*404* "_$$hide$$ <filename> <symname><NUL>" ->405* 9 + 3 + sizes of fn and sym name406*/407while ((nstrtab_size - nstrtab_nextoff) <408strlen(symname) + fn_size + 12) {409nstrtab_size *= 2;410nstrtabp = xrealloc(nstrtabp, nstrtab_size, fn,411"new string table");412if (nstrtabp == NULL)413goto bad;414}415416sp->st_name = htowew(nstrtab_nextoff);417418/* if it's a keeper or is undefined, don't rename it. */419if (in_keep_list(symname) ||420(xe16toh(sp->st_shndx) == SHN_UNDEF)) {421newent_len = sprintf(nstrtabp + nstrtab_nextoff,422"%s", symname) + 1;423} else {424newent_len = sprintf(nstrtabp + nstrtab_nextoff,425"_$$hide$$ %s %s", fn, symname) + 1;426}427nstrtab_nextoff += newent_len;428}429strtabshdr->sh_size = htoxew(nstrtab_nextoff);430431/*432* update section header table in ascending order of offset433*/434for (i = strtabidx + 1; i < shnum; i++) {435Elf_Off soff, align;436soff = xewtoh(layoutp[i - 1].shdr->sh_offset) +437xewtoh(layoutp[i - 1].shdr->sh_size);438align = xewtoh(layoutp[i].shdr->sh_addralign);439soff = (soff + (align - 1)) & ~(align - 1);440layoutp[i].shdr->sh_offset = htoxew(soff);441}442443/*444* write data to the file in descending order of offset445*/446for (i = shnum; i-- != 0;) {447if (layoutp[i].shdr == strtabshdr) {448/* new string table */449buf = nstrtabp;450} else451buf = layoutp[i].bufp;452453if (layoutp[i].shdr == &shdrshdr ||454layoutp[i].shdr == symtabshdr || i >= strtabidx) {455if (buf == NULL)456goto bad;457458/*459* update the offset of section header table in elf460* header if needed.461*/462if (layoutp[i].shdr == &shdrshdr &&463ehdr.e_shoff != shdrshdr.sh_offset) {464ehdr.e_shoff = shdrshdr.sh_offset;465off = offsetof(Elf_Ehdr, e_shoff);466size = sizeof(Elf_Off);467if ((size_t)xwriteatoff(fd, &ehdr.e_shoff, off, size,468fn) != size)469goto bad;470}471472off = xewtoh(layoutp[i].shdr->sh_offset);473size = xewtoh(layoutp[i].shdr->sh_size);474if ((size_t)xwriteatoff(fd, buf, off, size, fn) != size)475goto bad;476}477}478479out:480if (layoutp != NULL) {481for (i = 0; i < shnum; i++) {482if (layoutp[i].bufp != NULL)483free(layoutp[i].bufp);484}485free(layoutp);486}487free(nstrtabp);488return (rv);489490bad:491rv = 1;492goto out;493}494495#endif /* include this size of ELF */496497498