Initial import from FreeBSD RELENG_4:
[games.git] / usr.sbin / crunch / crunchide / exec_elf32.c
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 static const char rcsid[] =
37   "$FreeBSD: src/usr.sbin/crunch/crunchide/exec_elf32.c,v 1.1.6.2 2002/07/25 09:33:17 ru Exp $";
38 #endif
39  
40 #ifndef ELFSIZE
41 #define ELFSIZE         32
42 #endif
43
44 #include <sys/types.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 #elif (ELFSIZE == 64)
62 #include <sys/elf64.h>
63 #endif
64 #include <sys/elf_generic.h>
65
66 #define CONCAT(x,y)     __CONCAT(x,y)
67 #define ELFNAME(x)      CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x)))
68 #define ELFNAME2(x,y)   CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y))))
69 #define ELFNAMEEND(x)   CONCAT(x,CONCAT(_elf,ELFSIZE))
70 #define ELFDEFNNAME(x)  CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x)))
71
72 struct listelem {
73         struct listelem *next;
74         void *mem;
75         off_t file;
76         size_t size;
77 };
78
79 static ssize_t
80 xreadatoff(int fd, void *buf, off_t off, size_t size, const char *fn)
81 {
82         ssize_t rv;
83
84         if (lseek(fd, off, SEEK_SET) != off) {
85                 perror(fn);
86                 return -1;
87         }
88         if ((rv = read(fd, buf, size)) != size) {
89                 fprintf(stderr, "%s: read error: %s\n", fn,
90                     rv == -1 ? strerror(errno) : "short read");
91                 return -1;
92         }
93         return size;
94 }
95
96 static ssize_t
97 xwriteatoff(int fd, void *buf, off_t off, size_t size, const char *fn)
98 {
99         ssize_t rv;
100
101         if (lseek(fd, off, SEEK_SET) != off) {
102                 perror(fn);
103                 return -1;
104         }
105         if ((rv = write(fd, buf, size)) != size) {
106                 fprintf(stderr, "%s: write error: %s\n", fn,
107                     rv == -1 ? strerror(errno) : "short write");
108                 return -1;
109         }
110         return size;
111 }
112
113 static void *
114 xmalloc(size_t size, const char *fn, const char *use)
115 {
116         void *rv;
117
118         rv = malloc(size);
119         if (rv == NULL)
120                 fprintf(stderr, "%s: out of memory (allocating for %s)\n",
121                     fn, use);
122         return (rv);
123 }
124
125 int
126 ELFNAMEEND(check)(int fd, const char *fn)
127 {
128         Elf_Ehdr eh;
129         struct stat sb;
130
131         /*
132          * Check the header to maek sure it's an ELF file (of the
133          * appropriate size).
134          */
135         if (fstat(fd, &sb) == -1)
136                 return 0;
137         if (sb.st_size < sizeof eh)
138                 return 0;
139         if (read(fd, &eh, sizeof eh) != sizeof eh)
140                 return 0;
141
142         if (IS_ELF(eh) == 0)
143                 return 0;
144
145         switch (eh.e_machine) {
146         case EM_386: break;
147         case EM_ALPHA: break;
148 /*        ELFDEFNNAME(MACHDEP_ID_CASES) */
149
150         default:
151                 return 0;
152         }
153
154         return 1;
155 }
156
157 int
158 ELFNAMEEND(hide)(int fd, const char *fn)
159 {
160         Elf_Ehdr ehdr;
161         Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr;
162         Elf_Sym *symtabp = NULL;
163         char *strtabp = NULL;
164         Elf_Word *symfwmap = NULL, *symrvmap = NULL, nsyms, nlocalsyms, ewi;
165         struct listelem *relalist = NULL, *rellist = NULL, *tmpl;
166         ssize_t shdrsize;
167         int rv, i, weird;
168
169         rv = 0;
170         if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr)
171                 goto bad;
172
173         shdrsize = ehdr.e_shnum * ehdr.e_shentsize;
174         if ((shdrp = xmalloc(shdrsize, fn, "section header table")) == NULL)
175                 goto bad;
176         if (xreadatoff(fd, shdrp, ehdr.e_shoff, shdrsize, fn) != shdrsize)
177                 goto bad;
178
179         symtabshdr = strtabshdr = NULL;
180         weird = 0;
181         for (i = 0; i < ehdr.e_shnum; i++) {
182                 switch (shdrp[i].sh_type) {
183                 case SHT_SYMTAB:
184                         if (symtabshdr != NULL)
185                                 weird = 1;
186                         symtabshdr = &shdrp[i];
187                         strtabshdr = &shdrp[shdrp[i].sh_link];
188                         break;
189                 case SHT_RELA:
190                         tmpl = xmalloc(sizeof *tmpl, fn, "rela list element");
191                         if (tmpl == NULL)
192                                 goto bad;
193                         tmpl->mem = NULL;
194                         tmpl->file = shdrp[i].sh_offset;
195                         tmpl->size = shdrp[i].sh_size;
196                         tmpl->next = relalist;
197                         relalist = tmpl;
198                         break;
199                 case SHT_REL:
200                         tmpl = xmalloc(sizeof *tmpl, fn, "rel list element");
201                         if (tmpl == NULL)
202                                 goto bad;
203                         tmpl->mem = NULL;
204                         tmpl->file = shdrp[i].sh_offset;
205                         tmpl->size = shdrp[i].sh_size;
206                         tmpl->next = rellist;
207                         rellist = tmpl;
208                         break;
209                 }
210         }
211         if (symtabshdr == NULL)
212                 goto out;
213         if (strtabshdr == NULL)
214                 weird = 1;
215         if (weird) {
216                 fprintf(stderr, "%s: weird executable (unsupported)\n", fn);
217                 goto bad;
218         }
219
220         /*
221          * load up everything we need
222          */
223
224         /* symbol table */
225         if ((symtabp = xmalloc(symtabshdr->sh_size, fn, "symbol table"))
226             == NULL)
227                 goto bad;
228         if (xreadatoff(fd, symtabp, symtabshdr->sh_offset, symtabshdr->sh_size,
229             fn) != symtabshdr->sh_size)
230                 goto bad;
231
232         /* string table */
233         if ((strtabp = xmalloc(strtabshdr->sh_size, fn, "string table"))
234             == NULL)
235                 goto bad;
236         if (xreadatoff(fd, strtabp, strtabshdr->sh_offset, strtabshdr->sh_size,
237             fn) != strtabshdr->sh_size)
238                 goto bad;
239
240         /* any rela tables */
241         for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) {
242                 if ((tmpl->mem = xmalloc(tmpl->size, fn, "rela table"))
243                     == NULL)
244                         goto bad;
245                 if (xreadatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) !=
246                     tmpl->size)
247                         goto bad;
248         }
249
250         /* any rel tables */
251         for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) {
252                 if ((tmpl->mem = xmalloc(tmpl->size, fn, "rel table"))
253                     == NULL)
254                         goto bad;
255                 if (xreadatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) !=
256                     tmpl->size)
257                         goto bad;
258         }
259
260         /* Prepare data structures for symbol movement. */
261         nsyms = symtabshdr->sh_size / symtabshdr->sh_entsize;
262         nlocalsyms = symtabshdr->sh_info;
263         if ((symfwmap = xmalloc(nsyms * sizeof (Elf_Word), fn,
264             "symbol forward mapping table")) == NULL)
265                 goto bad;
266         if ((symrvmap = xmalloc(nsyms * sizeof (Elf_Word), fn,
267             "symbol reverse mapping table")) == NULL)
268                 goto bad;
269
270         /* init location -> symbol # table */
271         for (ewi = 0; ewi < nsyms; ewi++)
272                 symrvmap[ewi] = ewi;
273
274         /* move symbols, making them local */
275         for (ewi = nlocalsyms; ewi < nsyms; ewi++) {
276                 Elf_Sym *sp, symswap;
277                 Elf_Word mapswap;
278
279                 sp = &symtabp[ewi];
280
281                 /* if it's on our keep list, don't move it */
282                 if (in_keep_list(strtabp + sp->st_name))
283                         continue;
284
285                 /* if it's an undefined symbol, keep it */
286                 if (sp->st_shndx == SHN_UNDEF)
287                         continue;
288
289                 /* adjust the symbol so that it's local */
290                 sp->st_info =
291                     ELF_ST_INFO(STB_LOCAL, sp->st_info);
292 /*                  (STB_LOCAL << 4) | ELF_SYM_TYPE(sp->st_info); *//* XXX */
293
294                 /*
295                  * move the symbol to its new location
296                  */
297
298                 /* note that symbols in those locations have been swapped */
299                 mapswap = symrvmap[ewi];
300                 symrvmap[ewi] = symrvmap[nlocalsyms];
301                 symrvmap[nlocalsyms] = mapswap;
302
303                 /* and swap the symbols */
304                 symswap = *sp;
305                 *sp = symtabp[nlocalsyms];
306                 symtabp[nlocalsyms] = symswap;
307
308                 nlocalsyms++;                   /* note new local sym */
309         }
310         symtabshdr->sh_info = nlocalsyms;
311
312         /* set up symbol # -> location mapping table */
313         for (ewi = 0; ewi < nsyms; ewi++)
314                 symfwmap[symrvmap[ewi]] = ewi;
315
316         /* any rela tables */
317         for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) {
318                 Elf_Rela *relap = tmpl->mem;
319
320                 for (ewi = 0; ewi < tmpl->size / sizeof(*relap); ewi++) {
321                         relap[ewi].r_info =
322 #if (ELFSIZE == 32)                                     /* XXX */
323                             symfwmap[ELF_R_SYM(relap[ewi].r_info)] << 8 |
324                             ELF_R_TYPE(relap[ewi].r_info);
325 #elif (ELFSIZE == 64)                                   /* XXX */
326                             symfwmap[ELF_R_SYM(relap[ewi].r_info)] << 32 |
327                             ELF_R_TYPE(relap[ewi].r_info);
328 #endif                                                  /* XXX */
329                 }
330         }
331
332         /* any rel tables */
333         for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) {
334                 Elf_Rel *relp = tmpl->mem;
335
336                 for (ewi = 0; ewi < tmpl->size / sizeof *relp; ewi++) {
337                         relp[ewi].r_info =
338 #if (ELFSIZE == 32)                                     /* XXX */
339                             symfwmap[ELF_R_SYM(relp[ewi].r_info)] << 8 |
340                             ELF_R_TYPE(relp[ewi].r_info);
341 #elif (ELFSIZE == 64)                                   /* XXX */
342                             symfwmap[ELF_R_SYM(relp[ewi].r_info)] << 32 |
343                             ELF_R_TYPE(relp[ewi].r_info);
344 #endif                                                  /* XXX */
345                 }
346         }
347
348         /*
349          * write new tables to the file
350          */
351         if (xwriteatoff(fd, shdrp, ehdr.e_shoff, shdrsize, fn) != shdrsize)
352                 goto bad;
353         if (xwriteatoff(fd, symtabp, symtabshdr->sh_offset,
354             symtabshdr->sh_size, fn) != symtabshdr->sh_size)
355                 goto bad;
356         for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) {
357                 if (xwriteatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) !=
358                     tmpl->size)
359                         goto bad;
360         }
361         for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) {
362                 if (xwriteatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) !=
363                     tmpl->size)
364                         goto bad;
365         }
366
367 out:
368         if (shdrp != NULL)
369                 free(shdrp);
370         if (symtabp != NULL)
371                 free(symtabp);
372         if (strtabp != NULL)
373                 free(strtabp);
374         if (symfwmap != NULL)
375                 free(symfwmap);
376         if (symrvmap != NULL)
377                 free(symrvmap);
378         while ((tmpl = relalist) != NULL) {
379                 relalist = tmpl->next;
380                 if (tmpl->mem != NULL)
381                         free(tmpl->mem);
382                 free(tmpl);
383         }
384         while ((tmpl = rellist) != NULL) {
385                 rellist = tmpl->next;
386                 if (tmpl->mem != NULL)
387                         free(tmpl->mem);
388                 free(tmpl);
389         }
390         return (rv);
391
392 bad:
393         rv = 1;
394         goto out;
395 }
396
397 #endif /* include this size of ELF */