exec_elf32.c revision 112767
1/*
2 * Copyright (c) 1997 Christopher G. Demetriou.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 * 3. All advertising materials mentioning features or use of this software
13 *    must display the following acknowledgement:
14 *      This product includes software developed by Christopher G. Demetriou
15 *	for the NetBSD Project.
16 * 4. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32#ifndef lint
33#if 0
34__RCSID("$NetBSD: exec_elf32.c,v 1.4 1997/08/12 06:07:24 mikel Exp $");
35#endif
36#endif
37__FBSDID("$FreeBSD: head/usr.sbin/crunch/crunchide/exec_elf32.c 112767 2003-03-29 03:03:42Z obrien $");
38
39#ifndef ELFSIZE
40#define ELFSIZE         32
41#endif
42
43#include <sys/types.h>
44#include <sys/endian.h>
45#include <sys/stat.h>
46
47#include <errno.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <unistd.h>
52
53#include "extern.h"
54
55#if (defined(NLIST_ELF32) && (ELFSIZE == 32)) || \
56    (defined(NLIST_ELF64) && (ELFSIZE == 64))
57
58#define	__ELF_WORD_SIZE ELFSIZE
59#if (ELFSIZE == 32)
60#include <sys/elf32.h>
61#define	xewtoh(x)	((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))
62#define	htoxew(x)	((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))
63#elif (ELFSIZE == 64)
64#include <sys/elf64.h>
65#define	xewtoh(x)	((data == ELFDATA2MSB) ? be64toh(x) : le64toh(x))
66#define	htoxew(x)	((data == ELFDATA2MSB) ? htobe64(x) : htole64(x))
67#endif
68#include <sys/elf_generic.h>
69
70#define CONCAT(x,y)     __CONCAT(x,y)
71#define ELFNAME(x)      CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x)))
72#define ELFNAME2(x,y)   CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y))))
73#define ELFNAMEEND(x)   CONCAT(x,CONCAT(_elf,ELFSIZE))
74#define ELFDEFNNAME(x)  CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x)))
75
76#define	xe16toh(x)	((data == ELFDATA2MSB) ? be16toh(x) : le16toh(x))
77#define	xe32toh(x)	((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))
78#define	htoxe32(x)	((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))
79
80struct listelem {
81	struct listelem *next;
82	void *mem;
83	off_t file;
84	size_t size;
85};
86
87static ssize_t
88xreadatoff(int fd, void *buf, off_t off, size_t size, const char *fn)
89{
90	ssize_t rv;
91
92	if (lseek(fd, off, SEEK_SET) != off) {
93		perror(fn);
94		return -1;
95	}
96	if ((rv = read(fd, buf, size)) != size) {
97		fprintf(stderr, "%s: read error: %s\n", fn,
98		    rv == -1 ? strerror(errno) : "short read");
99		return -1;
100	}
101	return size;
102}
103
104static ssize_t
105xwriteatoff(int fd, void *buf, off_t off, size_t size, const char *fn)
106{
107	ssize_t rv;
108
109	if (lseek(fd, off, SEEK_SET) != off) {
110		perror(fn);
111		return -1;
112	}
113	if ((rv = write(fd, buf, size)) != size) {
114		fprintf(stderr, "%s: write error: %s\n", fn,
115		    rv == -1 ? strerror(errno) : "short write");
116		return -1;
117	}
118	return size;
119}
120
121static void *
122xmalloc(size_t size, const char *fn, const char *use)
123{
124	void *rv;
125
126	rv = malloc(size);
127	if (rv == NULL)
128		fprintf(stderr, "%s: out of memory (allocating for %s)\n",
129		    fn, use);
130	return (rv);
131}
132
133int
134ELFNAMEEND(check)(int fd, const char *fn)
135{
136	Elf_Ehdr eh;
137	struct stat sb;
138	unsigned char data;
139
140	/*
141	 * Check the header to maek sure it's an ELF file (of the
142	 * appropriate size).
143	 */
144	if (fstat(fd, &sb) == -1)
145		return 0;
146	if (sb.st_size < sizeof eh)
147		return 0;
148	if (read(fd, &eh, sizeof eh) != sizeof eh)
149		return 0;
150
151	if (IS_ELF(eh) == 0)
152                return 0;
153
154	data = eh.e_ident[EI_DATA];
155
156	switch (xe16toh(eh.e_machine)) {
157	case EM_386: break;
158	case EM_ALPHA: break;
159#ifndef EM_IA_64
160#define	EM_IA_64	50
161#endif
162	case EM_IA_64: break;
163#ifndef EM_SPARCV9
164#define	EM_SPARCV9	43
165#endif
166	case EM_SPARCV9: break;
167/*        ELFDEFNNAME(MACHDEP_ID_CASES) */
168
169        default:
170                return 0;
171        }
172
173	return 1;
174}
175
176int
177ELFNAMEEND(hide)(int fd, const char *fn)
178{
179	Elf_Ehdr ehdr;
180	Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr;
181	Elf_Sym *symtabp = NULL;
182	char *strtabp = NULL;
183	Elf_Word *symfwmap = NULL, *symrvmap = NULL, nsyms, nlocalsyms, ewi;
184	struct listelem *relalist = NULL, *rellist = NULL, *tmpl;
185	ssize_t shdrsize;
186	int rv, i, weird;
187	unsigned char data;
188
189	rv = 0;
190	if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr)
191		goto bad;
192
193	data = ehdr.e_ident[EI_DATA];
194
195	shdrsize = xe16toh(ehdr.e_shnum) * xe16toh(ehdr.e_shentsize);
196	if ((shdrp = xmalloc(shdrsize, fn, "section header table")) == NULL)
197		goto bad;
198	if (xreadatoff(fd, shdrp, xewtoh(ehdr.e_shoff), shdrsize, fn) !=
199	    shdrsize)
200		goto bad;
201
202	symtabshdr = strtabshdr = NULL;
203	weird = 0;
204	for (i = 0; i < xe16toh(ehdr.e_shnum); i++) {
205		switch (xe32toh(shdrp[i].sh_type)) {
206		case SHT_SYMTAB:
207			if (symtabshdr != NULL)
208				weird = 1;
209			symtabshdr = &shdrp[i];
210			strtabshdr = &shdrp[xe32toh(shdrp[i].sh_link)];
211			break;
212		case SHT_RELA:
213			tmpl = xmalloc(sizeof *tmpl, fn, "rela list element");
214			if (tmpl == NULL)
215				goto bad;
216			tmpl->mem = NULL;
217			tmpl->file = shdrp[i].sh_offset;
218			tmpl->size = shdrp[i].sh_size;
219			tmpl->next = relalist;
220			relalist = tmpl;
221			break;
222		case SHT_REL:
223			tmpl = xmalloc(sizeof *tmpl, fn, "rel list element");
224			if (tmpl == NULL)
225				goto bad;
226			tmpl->mem = NULL;
227			tmpl->file = shdrp[i].sh_offset;
228			tmpl->size = shdrp[i].sh_size;
229			tmpl->next = rellist;
230			rellist = tmpl;
231			break;
232		}
233	}
234	if (symtabshdr == NULL)
235		goto out;
236	if (strtabshdr == NULL)
237		weird = 1;
238	if (weird) {
239		fprintf(stderr, "%s: weird executable (unsupported)\n", fn);
240		goto bad;
241	}
242
243	/*
244	 * load up everything we need
245	 */
246
247	/* symbol table */
248	if ((symtabp = xmalloc(xewtoh(symtabshdr->sh_size), fn, "symbol table"))
249	    == NULL)
250		goto bad;
251	if (xreadatoff(fd, symtabp, xewtoh(symtabshdr->sh_offset),
252	    xewtoh(symtabshdr->sh_size), fn) != xewtoh(symtabshdr->sh_size))
253		goto bad;
254
255	/* string table */
256	if ((strtabp = xmalloc(xewtoh(strtabshdr->sh_size), fn, "string table"))
257	    == NULL)
258		goto bad;
259	if (xreadatoff(fd, strtabp, xewtoh(strtabshdr->sh_offset),
260	    xewtoh(strtabshdr->sh_size), fn) != xewtoh(strtabshdr->sh_size))
261		goto bad;
262
263	/* any rela tables */
264	for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) {
265		if ((tmpl->mem = xmalloc(xewtoh(tmpl->size), fn, "rela table"))
266		    == NULL)
267			goto bad;
268		if (xreadatoff(fd, tmpl->mem, xewtoh(tmpl->file),
269		    xewtoh(tmpl->size), fn) != xewtoh(tmpl->size))
270			goto bad;
271	}
272
273	/* any rel tables */
274	for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) {
275		if ((tmpl->mem = xmalloc(xewtoh(tmpl->size), fn, "rel table"))
276		    == NULL)
277			goto bad;
278		if (xreadatoff(fd, tmpl->mem, xewtoh(tmpl->file),
279		    xewtoh(tmpl->size), fn) != xewtoh(tmpl->size))
280			goto bad;
281	}
282
283	/* Prepare data structures for symbol movement. */
284	nsyms = xewtoh(symtabshdr->sh_size) / xewtoh(symtabshdr->sh_entsize);
285	nlocalsyms = xe32toh(symtabshdr->sh_info);
286	if ((symfwmap = xmalloc(nsyms * sizeof (Elf_Word), fn,
287	    "symbol forward mapping table")) == NULL)
288		goto bad;
289	if ((symrvmap = xmalloc(nsyms * sizeof (Elf_Word), fn,
290	    "symbol reverse mapping table")) == NULL)
291		goto bad;
292
293	/* init location -> symbol # table */
294	for (ewi = 0; ewi < nsyms; ewi++)
295		symrvmap[ewi] = ewi;
296
297	/* move symbols, making them local */
298	for (ewi = nlocalsyms; ewi < nsyms; ewi++) {
299		Elf_Sym *sp, symswap;
300		Elf_Word mapswap;
301
302		sp = &symtabp[ewi];
303
304		/* if it's on our keep list, don't move it */
305		if (in_keep_list(strtabp + xe32toh(sp->st_name)))
306			continue;
307
308		/* if it's an undefined symbol, keep it */
309		if (xe16toh(sp->st_shndx) == SHN_UNDEF)
310			continue;
311
312		/* adjust the symbol so that it's local */
313		sp->st_info =
314		    ELF_ST_INFO(STB_LOCAL, sp->st_info);
315/*		    (STB_LOCAL << 4) | ELF_SYM_TYPE(sp->st_info); *//* XXX */
316
317		/*
318		 * move the symbol to its new location
319		 */
320
321		/* note that symbols in those locations have been swapped */
322		mapswap = symrvmap[ewi];
323		symrvmap[ewi] = symrvmap[nlocalsyms];
324		symrvmap[nlocalsyms] = mapswap;
325
326		/* and swap the symbols */
327		symswap = *sp;
328		*sp = symtabp[nlocalsyms];
329		symtabp[nlocalsyms] = symswap;
330
331		nlocalsyms++;			/* note new local sym */
332	}
333	symtabshdr->sh_info = htoxe32(nlocalsyms);
334
335	/* set up symbol # -> location mapping table */
336	for (ewi = 0; ewi < nsyms; ewi++)
337		symfwmap[symrvmap[ewi]] = ewi;
338
339	/* any rela tables */
340	for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) {
341		Elf_Rela *relap = tmpl->mem;
342
343		for (ewi = 0; ewi < xewtoh(tmpl->size) / sizeof(*relap); ewi++) {
344			relap[ewi].r_info = htoxew(ELF_R_INFO(
345			    symfwmap[ELF_R_SYM(xewtoh(relap[ewi].r_info))],
346			    ELF_R_TYPE(xewtoh(relap[ewi].r_info))
347			));
348		}
349	}
350
351	/* any rel tables */
352	for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) {
353		Elf_Rel *relp = tmpl->mem;
354
355		for (ewi = 0; ewi < xewtoh(tmpl->size) / sizeof *relp; ewi++) {
356			relp[ewi].r_info = htoxew(ELF_R_INFO(
357			    symfwmap[ELF_R_SYM(xewtoh(relp[ewi].r_info))],
358			    ELF_R_TYPE(xewtoh(relp[ewi].r_info))
359			));
360		}
361	}
362
363	/*
364	 * write new tables to the file
365	 */
366	if (xwriteatoff(fd, shdrp, xewtoh(ehdr.e_shoff), shdrsize, fn) !=
367	    shdrsize)
368		goto bad;
369	if (xwriteatoff(fd, symtabp, xewtoh(symtabshdr->sh_offset),
370	    xewtoh(symtabshdr->sh_size), fn) != xewtoh(symtabshdr->sh_size))
371		goto bad;
372	for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) {
373		if (xwriteatoff(fd, tmpl->mem, xewtoh(tmpl->file),
374		    xewtoh(tmpl->size), fn) != xewtoh(tmpl->size))
375			goto bad;
376	}
377	for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) {
378		if (xwriteatoff(fd, tmpl->mem, xewtoh(tmpl->file),
379		    xewtoh(tmpl->size), fn) != xewtoh(tmpl->size))
380			goto bad;
381	}
382
383out:
384	if (shdrp != NULL)
385		free(shdrp);
386	if (symtabp != NULL)
387		free(symtabp);
388	if (strtabp != NULL)
389		free(strtabp);
390	if (symfwmap != NULL)
391		free(symfwmap);
392	if (symrvmap != NULL)
393		free(symrvmap);
394	while ((tmpl = relalist) != NULL) {
395		relalist = tmpl->next;
396		if (tmpl->mem != NULL)
397			free(tmpl->mem);
398		free(tmpl);
399	}
400	while ((tmpl = rellist) != NULL) {
401		rellist = tmpl->next;
402		if (tmpl->mem != NULL)
403			free(tmpl->mem);
404		free(tmpl);
405	}
406	return (rv);
407
408bad:
409	rv = 1;
410	goto out;
411}
412
413#endif /* include this size of ELF */
414