]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - usr.sbin/crunch/crunchide/exec_elf32.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.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_ARM
179 #define EM_ARM          40
180 #endif
181         case EM_ARM: break;
182 #ifndef EM_MIPS
183 #define EM_MIPS         8
184 #endif
185 #ifndef EM_MIPS_RS4_BE          /* same as EM_MIPS_RS3_LE */
186 #define EM_MIPS_RS4_BE  10
187 #endif
188         case EM_MIPS: break;
189         case /* EM_MIPS_RS3_LE */ EM_MIPS_RS4_BE: break;
190 #ifndef EM_IA_64
191 #define EM_IA_64        50
192 #endif
193         case EM_IA_64: break;
194 #ifndef EM_PPC
195 #define EM_PPC          20
196 #endif
197         case EM_PPC: break;
198 #ifndef EM_PPC64
199 #define EM_PPC64        21
200 #endif
201         case EM_PPC64: break;
202 #ifndef EM_SPARCV9
203 #define EM_SPARCV9      43
204 #endif
205         case EM_SPARCV9: break;
206 #ifndef EM_X86_64
207 #define EM_X86_64       62
208 #endif
209         case EM_X86_64: break;
210 /*        ELFDEFNNAME(MACHDEP_ID_CASES) */
211
212         default:
213                 return 0;
214         }
215
216         return 1;
217 }
218
219 /*
220  * This function 'hides' (some of) ELF executable file's symbols.
221  * It hides them by renaming them to "_$$hide$$ <filename> <symbolname>".
222  * Symbols in the global keep list, or which are marked as being undefined,
223  * are left alone.
224  *
225  * An old version of this code shuffled various tables around, turning
226  * global symbols to be hidden into local symbols.  That lost on the
227  * mips, because CALL16 relocs must reference global symbols, and, if
228  * those symbols were being hidden, they were no longer global.
229  *
230  * The new renaming behaviour doesn't take global symbols out of the
231  * namespace.  However, it's ... unlikely that there will ever be
232  * any collisions in practice because of the new method.
233  */
234 int
235 ELFNAMEEND(hide)(int fd, const char *fn)
236 {
237         Elf_Ehdr ehdr;
238         struct shlayout *layoutp = NULL;
239         Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr, *shstrtabshdr;
240         Elf_Shdr shdrshdr;
241         Elf_Sym *symtabp = NULL;
242         char *shstrtabp = NULL, *strtabp = NULL;
243         Elf_Size nsyms, ewi;
244         Elf_Off off;
245         ssize_t shdrsize;
246         int rv, i, weird, l, m, r, strtabidx;
247         size_t nstrtab_size, nstrtab_nextoff, fn_size, size;
248         char *nstrtabp = NULL;
249         unsigned char data;
250         const char *weirdreason = NULL;
251         void *buf;
252         Elf_Half shnum;
253
254         rv = 0;
255         if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr)
256                 goto bad;
257
258         data = ehdr.e_ident[EI_DATA];
259         shnum = xe16toh(ehdr.e_shnum);
260
261         shdrsize = shnum * xe16toh(ehdr.e_shentsize);
262         if ((shdrp = xmalloc(shdrsize, fn, "section header table")) == NULL)
263                 goto bad;
264         if (xreadatoff(fd, shdrp, xewtoh(ehdr.e_shoff), shdrsize, fn) !=
265             shdrsize)
266                 goto bad;
267
268         symtabshdr = strtabshdr = shstrtabshdr = NULL;
269         weird = 0;
270         for (i = 0; i < shnum; i++) {
271                 switch (xe32toh(shdrp[i].sh_type)) {
272                 case SHT_SYMTAB:
273                         if (symtabshdr != NULL) {
274                                 weird = 1;
275                                 weirdreason = "multiple symbol tables";
276                         }
277                         symtabshdr = &shdrp[i];
278                         strtabshdr = &shdrp[xe32toh(shdrp[i].sh_link)];
279                         break;
280                 case SHT_STRTAB:
281                         if (i == xe16toh(ehdr.e_shstrndx))
282                                 shstrtabshdr = &shdrp[i];
283                         break;
284                 }
285         }
286         if (symtabshdr == NULL)
287                 goto out;
288         if (strtabshdr == NULL) {
289                 weird = 1;
290                 weirdreason = "string table does not exist";
291         }
292         if (shstrtabshdr == NULL) {
293                 weird = 1;
294                 weirdreason = "section header string table does not exist";
295         }
296         if (weirdreason == NULL)
297                 weirdreason = "unsupported";
298         if (weird) {
299                 fprintf(stderr, "%s: weird executable (%s)\n", fn, weirdreason);
300                 goto bad;
301         }
302
303         /*
304          * sort section layout table by offset
305          */
306         layoutp = xmalloc((shnum + 1) * sizeof(struct shlayout),
307             fn, "layout table");
308         if (layoutp == NULL)
309                 goto bad;
310
311         /* add a pseudo entry to represent the section header table */
312         shdrshdr.sh_offset = ehdr.e_shoff;
313         shdrshdr.sh_size = htoxew(shdrsize);
314         shdrshdr.sh_addralign = htoxew(ELFSIZE / 8);
315         layoutp[shnum].shdr = &shdrshdr;
316
317         /* insert and sort normal section headers */
318         for (i = shnum; i-- != 0;) {
319                 l = i + 1;
320                 r = shnum;
321                 while (l <= r) {
322                         m = ( l + r) / 2;
323                         if (xewtoh(shdrp[i].sh_offset) >
324                             xewtoh(layoutp[m].shdr->sh_offset))
325                                 l = m + 1;
326                         else
327                                 r = m - 1;
328                 }
329
330                 if (r != i) {
331                         memmove(&layoutp[i], &layoutp[i + 1],
332                             sizeof(struct shlayout) * (r - i));
333                 }
334
335                 layoutp[r].shdr = &shdrp[i];
336                 layoutp[r].bufp = NULL;
337         }
338         ++shnum;
339
340         /*
341          * load up everything we need
342          */
343
344         /* load section string table for debug use */
345         if ((size = xewtoh(shstrtabshdr->sh_size)) == 0)
346                 goto bad;
347         if ((shstrtabp = xmalloc(size, fn, "section string table")) == NULL)
348                 goto bad;
349         if ((size_t)xreadatoff(fd, shstrtabp, xewtoh(shstrtabshdr->sh_offset),
350             size, fn) != size)
351                 goto bad;
352         if (shstrtabp[size - 1] != '\0')
353                 goto bad;
354
355         /* we need symtab, strtab, and everything behind strtab */
356         strtabidx = INT_MAX;
357         for (i = 0; i < shnum; i++) {
358                 if (layoutp[i].shdr == &shdrshdr) {
359                         /* not load section header again */
360                         layoutp[i].bufp = shdrp;
361                         continue;
362                 }
363                 if (layoutp[i].shdr == shstrtabshdr) {
364                         /* not load section string table again */
365                         layoutp[i].bufp = shstrtabp;
366                         continue;
367                 }
368
369                 if (layoutp[i].shdr == strtabshdr)
370                         strtabidx = i;
371                 if (layoutp[i].shdr == symtabshdr || i >= strtabidx) {
372                         off = xewtoh(layoutp[i].shdr->sh_offset);
373                         if ((size = xewtoh(layoutp[i].shdr->sh_size)) == 0)
374                                 goto bad;
375                         layoutp[i].bufp = xmalloc(size, fn,
376                             shstrtabp + xewtoh(layoutp[i].shdr->sh_name));
377                         if (layoutp[i].bufp == NULL)
378                                 goto bad;
379                         if ((size_t)xreadatoff(fd, layoutp[i].bufp, off, size, fn) !=
380                             size)
381                                 goto bad;
382
383                         /* set symbol table and string table */
384                         if (layoutp[i].shdr == symtabshdr) {
385                                 symtabp = layoutp[i].bufp;
386                         } else if (layoutp[i].shdr == strtabshdr) {
387                                 strtabp = layoutp[i].bufp;
388                                 if (strtabp[size - 1] != '\0')
389                                         goto bad;
390                         }
391                 }
392         }
393
394         nstrtab_size = 256;
395         nstrtabp = xmalloc(nstrtab_size, fn, "new string table");
396         if (nstrtabp == NULL)
397                 goto bad;
398         nstrtab_nextoff = 0;
399
400         fn_size = strlen(fn);
401
402         /* Prepare data structures for symbol movement. */
403         nsyms = xewtoh(symtabshdr->sh_size) / xewtoh(symtabshdr->sh_entsize);
404
405         /* move symbols, making them local */
406         for (ewi = 0; ewi < nsyms; ewi++) {
407                 Elf_Sym *sp = &symtabp[ewi];
408                 const char *symname = strtabp + xe32toh(sp->st_name);
409                 size_t newent_len;
410                 /*
411                  * make sure there's size for the next entry, even if it's
412                  * as large as it can be.
413                  *
414                  * "_$$hide$$ <filename> <symname><NUL>" ->
415                  *    9 + 3 + sizes of fn and sym name
416                  */
417                 while ((nstrtab_size - nstrtab_nextoff) <
418                     strlen(symname) + fn_size + 12) {
419                         nstrtab_size *= 2;
420                         nstrtabp = xrealloc(nstrtabp, nstrtab_size, fn,
421                             "new string table");
422                         if (nstrtabp == NULL)
423                                 goto bad;
424                 }
425
426                 sp->st_name = htowew(nstrtab_nextoff);
427
428                 /* if it's a keeper or is undefined, don't rename it. */
429                 if (in_keep_list(symname) ||
430                     (xe16toh(sp->st_shndx) == SHN_UNDEF)) {
431                         newent_len = sprintf(nstrtabp + nstrtab_nextoff,
432                             "%s", symname) + 1;
433                 } else {
434                         newent_len = sprintf(nstrtabp + nstrtab_nextoff,
435                             "_$$hide$$ %s %s", fn, symname) + 1;
436                 }
437                 nstrtab_nextoff += newent_len;
438         }
439         strtabshdr->sh_size = htoxew(nstrtab_nextoff);
440
441         /*
442          * update section header table in ascending order of offset
443          */
444         for (i = strtabidx + 1; i < shnum; i++) {
445                 Elf_Off off, align;
446                 off = xewtoh(layoutp[i - 1].shdr->sh_offset) +
447                     xewtoh(layoutp[i - 1].shdr->sh_size);
448                 align = xewtoh(layoutp[i].shdr->sh_addralign);
449                 off = (off + (align - 1)) & ~(align - 1);
450                 layoutp[i].shdr->sh_offset = htoxew(off);
451         }
452
453         /*
454          * write data to the file in descending order of offset
455          */
456         for (i = shnum; i-- != 0;) {
457                 if (layoutp[i].shdr == strtabshdr) {
458                         /* new string table */
459                         buf = nstrtabp;
460                 } else
461                         buf = layoutp[i].bufp;
462
463                 if (layoutp[i].shdr == &shdrshdr ||
464                     layoutp[i].shdr == symtabshdr || i >= strtabidx) {
465                         if (buf == NULL)
466                                 goto bad;
467
468                         /*
469                          * update the offset of section header table in elf
470                          * header if needed.
471                          */
472                         if (layoutp[i].shdr == &shdrshdr &&
473                             ehdr.e_shoff != shdrshdr.sh_offset) {
474                                 ehdr.e_shoff = shdrshdr.sh_offset;
475                                 off = offsetof(Elf_Ehdr, e_shoff);
476                                 size = sizeof(Elf_Off);
477                                 if ((size_t)xwriteatoff(fd, &ehdr.e_shoff, off, size,
478                                     fn) != size)
479                                         goto bad;
480                         }
481
482                         off = xewtoh(layoutp[i].shdr->sh_offset);
483                         size = xewtoh(layoutp[i].shdr->sh_size);
484                         if ((size_t)xwriteatoff(fd, buf, off, size, fn) != size)
485                                 goto bad;
486                 }
487         }
488
489 out:
490         if (layoutp != NULL) {
491                 for (i = 0; i < shnum; i++) {
492                         if (layoutp[i].bufp != NULL)
493                                 free(layoutp[i].bufp);
494                 }
495                 free(layoutp);
496         }
497         free(nstrtabp);
498         return (rv);
499
500 bad:
501         rv = 1;
502         goto out;
503 }
504
505 #endif /* include this size of ELF */