]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/crunch/crunchide/exec_elf32.c
Sync crunchide(1) arch support with HEAD
[FreeBSD/stable/10.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.6 1999/09/20 04:12:16 christos Exp $");
35 #endif
36 #endif
37 __FBSDID("$FreeBSD$");
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 <limits.h>
49 #include <stddef.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54
55 #include "extern.h"
56
57 #if (defined(NLIST_ELF32) && (ELFSIZE == 32)) || \
58     (defined(NLIST_ELF64) && (ELFSIZE == 64))
59
60 #define __ELF_WORD_SIZE ELFSIZE
61 #if (ELFSIZE == 32)
62 #include <sys/elf32.h>
63 #define xewtoh(x)       ((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))
64 #define htoxew(x)       ((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))
65 #define wewtoh(x)       ((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))
66 #define htowew(x)       ((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))
67 #elif (ELFSIZE == 64)
68 #include <sys/elf64.h>
69 #define xewtoh(x)       ((data == ELFDATA2MSB) ? be64toh(x) : le64toh(x))
70 #define htoxew(x)       ((data == ELFDATA2MSB) ? htobe64(x) : htole64(x))
71 /* elf64 Elf64_Word are 32 bits */
72 #define wewtoh(x)       ((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))
73 #define htowew(x)       ((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))
74 #endif
75 #include <sys/elf_generic.h>
76
77 #define CONCAT(x,y)     __CONCAT(x,y)
78 #define ELFNAME(x)      CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x)))
79 #define ELFNAME2(x,y)   CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y))))
80 #define ELFNAMEEND(x)   CONCAT(x,CONCAT(_elf,ELFSIZE))
81 #define ELFDEFNNAME(x)  CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x)))
82
83 #define xe16toh(x)      ((data == ELFDATA2MSB) ? be16toh(x) : le16toh(x))
84 #define xe32toh(x)      ((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))
85 #define htoxe32(x)      ((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))
86
87 struct shlayout {
88         Elf_Shdr *shdr;
89         void *bufp;
90 };
91
92 static ssize_t
93 xreadatoff(int fd, void *buf, off_t off, size_t size, const char *fn)
94 {
95         ssize_t rv;
96
97         if (lseek(fd, off, SEEK_SET) != off) {
98                 perror(fn);
99                 return -1;
100         }
101         if ((size_t)(rv = read(fd, buf, size)) != size) {
102                 fprintf(stderr, "%s: read error: %s\n", fn,
103                     rv == -1 ? strerror(errno) : "short read");
104                 return -1;
105         }
106         return size;
107 }
108
109 static ssize_t
110 xwriteatoff(int fd, void *buf, off_t off, size_t size, const char *fn)
111 {
112         ssize_t rv;
113
114         if (lseek(fd, off, SEEK_SET) != off) {
115                 perror(fn);
116                 return -1;
117         }
118         if ((size_t)(rv = write(fd, buf, size)) != size) {
119                 fprintf(stderr, "%s: write error: %s\n", fn,
120                     rv == -1 ? strerror(errno) : "short write");
121                 return -1;
122         }
123         return size;
124 }
125
126 static void *
127 xmalloc(size_t size, const char *fn, const char *use)
128 {
129         void *rv;
130
131         rv = malloc(size);
132         if (rv == NULL)
133                 fprintf(stderr, "%s: out of memory (allocating for %s)\n",
134                     fn, use);
135         return (rv);
136 }
137
138 static void *
139 xrealloc(void *ptr, size_t size, const char *fn, const char *use)
140 {
141         void *rv;
142                 
143         rv = realloc(ptr, size);
144         if (rv == NULL) {
145                 free(ptr);
146                 fprintf(stderr, "%s: out of memory (reallocating for %s)\n",
147                     fn, use);
148         }
149         return (rv);
150
151
152 int
153 ELFNAMEEND(check)(int fd, const char *fn)
154 {
155         Elf_Ehdr eh;
156         struct stat sb;
157         unsigned char data;
158
159         /*
160          * Check the header to maek sure it's an ELF file (of the
161          * appropriate size).
162          */
163         if (fstat(fd, &sb) == -1)
164                 return 0;
165         if (sb.st_size < (off_t)(sizeof eh))
166                 return 0;
167         if (read(fd, &eh, sizeof eh) != sizeof eh)
168                 return 0;
169
170         if (IS_ELF(eh) == 0)
171                 return 0;
172
173         data = eh.e_ident[EI_DATA];
174
175         switch (xe16toh(eh.e_machine)) {
176         case EM_386: break;
177         case EM_ALPHA: break;
178 #ifndef EM_AARCH64
179 #define EM_AARCH64      183
180 #endif
181         case EM_AARCH64: break;
182         case EM_ARM: break;
183         case EM_MIPS: break;
184         case /* EM_MIPS_RS3_LE */ EM_MIPS_RS4_BE: break;
185         case EM_PPC: break;
186         case EM_PPC64: break;
187 #ifndef EM_RISCV
188 #define EM_RISCV        243
189 #endif
190         case EM_RISCV: break;
191         case EM_SPARCV9: break;
192         case EM_X86_64: break;
193 /*        ELFDEFNNAME(MACHDEP_ID_CASES) */
194
195         default:
196                 return 0;
197         }
198
199         return 1;
200 }
201
202 /*
203  * This function 'hides' (some of) ELF executable file's symbols.
204  * It hides them by renaming them to "_$$hide$$ <filename> <symbolname>".
205  * Symbols in the global keep list, or which are marked as being undefined,
206  * are left alone.
207  *
208  * An old version of this code shuffled various tables around, turning
209  * global symbols to be hidden into local symbols.  That lost on the
210  * mips, because CALL16 relocs must reference global symbols, and, if
211  * those symbols were being hidden, they were no longer global.
212  *
213  * The new renaming behaviour doesn't take global symbols out of the
214  * namespace.  However, it's ... unlikely that there will ever be
215  * any collisions in practice because of the new method.
216  */
217 int
218 ELFNAMEEND(hide)(int fd, const char *fn)
219 {
220         Elf_Ehdr ehdr;
221         struct shlayout *layoutp = NULL;
222         Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr, *shstrtabshdr;
223         Elf_Shdr shdrshdr;
224         Elf_Sym *symtabp = NULL;
225         char *shstrtabp = NULL, *strtabp = NULL;
226         Elf_Size nsyms, ewi;
227         Elf_Off off;
228         ssize_t shdrsize;
229         int rv, i, weird, l, m, r, strtabidx;
230         size_t nstrtab_size, nstrtab_nextoff, fn_size, size;
231         char *nstrtabp = NULL;
232         unsigned char data;
233         const char *weirdreason = NULL;
234         void *buf;
235         Elf_Half shnum;
236
237         rv = 0;
238         if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr)
239                 goto bad;
240
241         data = ehdr.e_ident[EI_DATA];
242         shnum = xe16toh(ehdr.e_shnum);
243
244         shdrsize = shnum * xe16toh(ehdr.e_shentsize);
245         if ((shdrp = xmalloc(shdrsize, fn, "section header table")) == NULL)
246                 goto bad;
247         if (xreadatoff(fd, shdrp, xewtoh(ehdr.e_shoff), shdrsize, fn) !=
248             shdrsize)
249                 goto bad;
250
251         symtabshdr = strtabshdr = shstrtabshdr = NULL;
252         weird = 0;
253         for (i = 0; i < shnum; i++) {
254                 switch (xe32toh(shdrp[i].sh_type)) {
255                 case SHT_SYMTAB:
256                         if (symtabshdr != NULL) {
257                                 weird = 1;
258                                 weirdreason = "multiple symbol tables";
259                         }
260                         symtabshdr = &shdrp[i];
261                         strtabshdr = &shdrp[xe32toh(shdrp[i].sh_link)];
262                         break;
263                 case SHT_STRTAB:
264                         if (i == xe16toh(ehdr.e_shstrndx))
265                                 shstrtabshdr = &shdrp[i];
266                         break;
267                 }
268         }
269         if (symtabshdr == NULL)
270                 goto out;
271         if (strtabshdr == NULL) {
272                 weird = 1;
273                 weirdreason = "string table does not exist";
274         }
275         if (shstrtabshdr == NULL) {
276                 weird = 1;
277                 weirdreason = "section header string table does not exist";
278         }
279         if (weirdreason == NULL)
280                 weirdreason = "unsupported";
281         if (weird) {
282                 fprintf(stderr, "%s: weird executable (%s)\n", fn, weirdreason);
283                 goto bad;
284         }
285
286         /*
287          * sort section layout table by offset
288          */
289         layoutp = xmalloc((shnum + 1) * sizeof(struct shlayout),
290             fn, "layout table");
291         if (layoutp == NULL)
292                 goto bad;
293
294         /* add a pseudo entry to represent the section header table */
295         shdrshdr.sh_offset = ehdr.e_shoff;
296         shdrshdr.sh_size = htoxew(shdrsize);
297         shdrshdr.sh_addralign = htoxew(ELFSIZE / 8);
298         layoutp[shnum].shdr = &shdrshdr;
299
300         /* insert and sort normal section headers */
301         for (i = shnum; i-- != 0;) {
302                 l = i + 1;
303                 r = shnum;
304                 while (l <= r) {
305                         m = ( l + r) / 2;
306                         if (xewtoh(shdrp[i].sh_offset) >
307                             xewtoh(layoutp[m].shdr->sh_offset))
308                                 l = m + 1;
309                         else
310                                 r = m - 1;
311                 }
312
313                 if (r != i) {
314                         memmove(&layoutp[i], &layoutp[i + 1],
315                             sizeof(struct shlayout) * (r - i));
316                 }
317
318                 layoutp[r].shdr = &shdrp[i];
319                 layoutp[r].bufp = NULL;
320         }
321         ++shnum;
322
323         /*
324          * load up everything we need
325          */
326
327         /* load section string table for debug use */
328         if ((size = xewtoh(shstrtabshdr->sh_size)) == 0)
329                 goto bad;
330         if ((shstrtabp = xmalloc(size, fn, "section string table")) == NULL)
331                 goto bad;
332         if ((size_t)xreadatoff(fd, shstrtabp, xewtoh(shstrtabshdr->sh_offset),
333             size, fn) != size)
334                 goto bad;
335         if (shstrtabp[size - 1] != '\0')
336                 goto bad;
337
338         /* we need symtab, strtab, and everything behind strtab */
339         strtabidx = INT_MAX;
340         for (i = 0; i < shnum; i++) {
341                 if (layoutp[i].shdr == &shdrshdr) {
342                         /* not load section header again */
343                         layoutp[i].bufp = shdrp;
344                         continue;
345                 }
346                 if (layoutp[i].shdr == shstrtabshdr) {
347                         /* not load section string table again */
348                         layoutp[i].bufp = shstrtabp;
349                         continue;
350                 }
351
352                 if (layoutp[i].shdr == strtabshdr)
353                         strtabidx = i;
354                 if (layoutp[i].shdr == symtabshdr || i >= strtabidx) {
355                         off = xewtoh(layoutp[i].shdr->sh_offset);
356                         if ((size = xewtoh(layoutp[i].shdr->sh_size)) == 0)
357                                 goto bad;
358                         layoutp[i].bufp = xmalloc(size, fn,
359                             shstrtabp + xewtoh(layoutp[i].shdr->sh_name));
360                         if (layoutp[i].bufp == NULL)
361                                 goto bad;
362                         if ((size_t)xreadatoff(fd, layoutp[i].bufp, off, size, fn) !=
363                             size)
364                                 goto bad;
365
366                         /* set symbol table and string table */
367                         if (layoutp[i].shdr == symtabshdr) {
368                                 symtabp = layoutp[i].bufp;
369                         } else if (layoutp[i].shdr == strtabshdr) {
370                                 strtabp = layoutp[i].bufp;
371                                 if (strtabp[size - 1] != '\0')
372                                         goto bad;
373                         }
374                 }
375         }
376
377         nstrtab_size = 256;
378         nstrtabp = xmalloc(nstrtab_size, fn, "new string table");
379         if (nstrtabp == NULL)
380                 goto bad;
381         nstrtab_nextoff = 0;
382
383         fn_size = strlen(fn);
384
385         /* Prepare data structures for symbol movement. */
386         nsyms = xewtoh(symtabshdr->sh_size) / xewtoh(symtabshdr->sh_entsize);
387
388         /* move symbols, making them local */
389         for (ewi = 0; ewi < nsyms; ewi++) {
390                 Elf_Sym *sp = &symtabp[ewi];
391                 const char *symname = strtabp + xe32toh(sp->st_name);
392                 size_t newent_len;
393                 /*
394                  * make sure there's size for the next entry, even if it's
395                  * as large as it can be.
396                  *
397                  * "_$$hide$$ <filename> <symname><NUL>" ->
398                  *    9 + 3 + sizes of fn and sym name
399                  */
400                 while ((nstrtab_size - nstrtab_nextoff) <
401                     strlen(symname) + fn_size + 12) {
402                         nstrtab_size *= 2;
403                         nstrtabp = xrealloc(nstrtabp, nstrtab_size, fn,
404                             "new string table");
405                         if (nstrtabp == NULL)
406                                 goto bad;
407                 }
408
409                 sp->st_name = htowew(nstrtab_nextoff);
410
411                 /* if it's a keeper or is undefined, don't rename it. */
412                 if (in_keep_list(symname) ||
413                     (xe16toh(sp->st_shndx) == SHN_UNDEF)) {
414                         newent_len = sprintf(nstrtabp + nstrtab_nextoff,
415                             "%s", symname) + 1;
416                 } else {
417                         newent_len = sprintf(nstrtabp + nstrtab_nextoff,
418                             "_$$hide$$ %s %s", fn, symname) + 1;
419                 }
420                 nstrtab_nextoff += newent_len;
421         }
422         strtabshdr->sh_size = htoxew(nstrtab_nextoff);
423
424         /*
425          * update section header table in ascending order of offset
426          */
427         for (i = strtabidx + 1; i < shnum; i++) {
428                 Elf_Off off, align;
429                 off = xewtoh(layoutp[i - 1].shdr->sh_offset) +
430                     xewtoh(layoutp[i - 1].shdr->sh_size);
431                 align = xewtoh(layoutp[i].shdr->sh_addralign);
432                 off = (off + (align - 1)) & ~(align - 1);
433                 layoutp[i].shdr->sh_offset = htoxew(off);
434         }
435
436         /*
437          * write data to the file in descending order of offset
438          */
439         for (i = shnum; i-- != 0;) {
440                 if (layoutp[i].shdr == strtabshdr) {
441                         /* new string table */
442                         buf = nstrtabp;
443                 } else
444                         buf = layoutp[i].bufp;
445
446                 if (layoutp[i].shdr == &shdrshdr ||
447                     layoutp[i].shdr == symtabshdr || i >= strtabidx) {
448                         if (buf == NULL)
449                                 goto bad;
450
451                         /*
452                          * update the offset of section header table in elf
453                          * header if needed.
454                          */
455                         if (layoutp[i].shdr == &shdrshdr &&
456                             ehdr.e_shoff != shdrshdr.sh_offset) {
457                                 ehdr.e_shoff = shdrshdr.sh_offset;
458                                 off = offsetof(Elf_Ehdr, e_shoff);
459                                 size = sizeof(Elf_Off);
460                                 if ((size_t)xwriteatoff(fd, &ehdr.e_shoff, off, size,
461                                     fn) != size)
462                                         goto bad;
463                         }
464
465                         off = xewtoh(layoutp[i].shdr->sh_offset);
466                         size = xewtoh(layoutp[i].shdr->sh_size);
467                         if ((size_t)xwriteatoff(fd, buf, off, size, fn) != size)
468                                 goto bad;
469                 }
470         }
471
472 out:
473         if (layoutp != NULL) {
474                 for (i = 0; i < shnum; i++) {
475                         if (layoutp[i].bufp != NULL)
476                                 free(layoutp[i].bufp);
477                 }
478                 free(layoutp);
479         }
480         free(nstrtabp);
481         return (rv);
482
483 bad:
484         rv = 1;
485         goto out;
486 }
487
488 #endif /* include this size of ELF */