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