]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/file/src/readelf.c
Merge bmake-20200606
[FreeBSD/FreeBSD.git] / contrib / file / src / readelf.c
1 /*
2  * Copyright (c) Christos Zoulas 2003.
3  * All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice immediately at the beginning of the file, without modification,
10  *    this list of conditions, and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 #include "file.h"
28
29 #ifndef lint
30 FILE_RCSID("@(#)$File: readelf.c,v 1.168 2019/12/16 03:49:19 christos Exp $")
31 #endif
32
33 #ifdef BUILTIN_ELF
34 #include <string.h>
35 #include <ctype.h>
36 #include <stdlib.h>
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40
41 #include "readelf.h"
42 #include "magic.h"
43
44 #ifdef  ELFCORE
45 private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t,
46     off_t, int *, uint16_t *);
47 #endif
48 private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t,
49     off_t, int, int *, uint16_t *);
50 private int doshn(struct magic_set *, int, int, int, off_t, int, size_t,
51     off_t, int, int, int *, uint16_t *);
52 private size_t donote(struct magic_set *, void *, size_t, size_t, int,
53     int, size_t, int *, uint16_t *, int, off_t, int, off_t);
54
55 #define ELF_ALIGN(a)    ((((a) + align - 1) / align) * align)
56
57 #define isquote(c) (strchr("'\"`", (c)) != NULL)
58
59 private uint16_t getu16(int, uint16_t);
60 private uint32_t getu32(int, uint32_t);
61 private uint64_t getu64(int, uint64_t);
62
63 #define MAX_PHNUM       128
64 #define MAX_SHNUM       32768
65 #define SIZE_UNKNOWN    CAST(off_t, -1)
66
67 private int
68 toomany(struct magic_set *ms, const char *name, uint16_t num)
69 {
70         if (file_printf(ms, ", too many %s (%u)", name, num) == -1)
71                 return -1;
72         return 1;
73 }
74
75 private uint16_t
76 getu16(int swap, uint16_t value)
77 {
78         union {
79                 uint16_t ui;
80                 char c[2];
81         } retval, tmpval;
82
83         if (swap) {
84                 tmpval.ui = value;
85
86                 retval.c[0] = tmpval.c[1];
87                 retval.c[1] = tmpval.c[0];
88
89                 return retval.ui;
90         } else
91                 return value;
92 }
93
94 private uint32_t
95 getu32(int swap, uint32_t value)
96 {
97         union {
98                 uint32_t ui;
99                 char c[4];
100         } retval, tmpval;
101
102         if (swap) {
103                 tmpval.ui = value;
104
105                 retval.c[0] = tmpval.c[3];
106                 retval.c[1] = tmpval.c[2];
107                 retval.c[2] = tmpval.c[1];
108                 retval.c[3] = tmpval.c[0];
109
110                 return retval.ui;
111         } else
112                 return value;
113 }
114
115 private uint64_t
116 getu64(int swap, uint64_t value)
117 {
118         union {
119                 uint64_t ui;
120                 char c[8];
121         } retval, tmpval;
122
123         if (swap) {
124                 tmpval.ui = value;
125
126                 retval.c[0] = tmpval.c[7];
127                 retval.c[1] = tmpval.c[6];
128                 retval.c[2] = tmpval.c[5];
129                 retval.c[3] = tmpval.c[4];
130                 retval.c[4] = tmpval.c[3];
131                 retval.c[5] = tmpval.c[2];
132                 retval.c[6] = tmpval.c[1];
133                 retval.c[7] = tmpval.c[0];
134
135                 return retval.ui;
136         } else
137                 return value;
138 }
139
140 #define elf_getu16(swap, value) getu16(swap, value)
141 #define elf_getu32(swap, value) getu32(swap, value)
142 #define elf_getu64(swap, value) getu64(swap, value)
143
144 #define xsh_addr        (clazz == ELFCLASS32                    \
145                          ? CAST(void *, &sh32)                  \
146                          : CAST(void *, &sh64))
147 #define xsh_sizeof      (clazz == ELFCLASS32                    \
148                          ? sizeof(sh32)                         \
149                          : sizeof(sh64))
150 #define xsh_size        CAST(size_t, (clazz == ELFCLASS32       \
151                          ? elf_getu32(swap, sh32.sh_size)       \
152                          : elf_getu64(swap, sh64.sh_size)))
153 #define xsh_offset      CAST(off_t, (clazz == ELFCLASS32        \
154                          ? elf_getu32(swap, sh32.sh_offset)     \
155                          : elf_getu64(swap, sh64.sh_offset)))
156 #define xsh_type        (clazz == ELFCLASS32                    \
157                          ? elf_getu32(swap, sh32.sh_type)       \
158                          : elf_getu32(swap, sh64.sh_type))
159 #define xsh_name        (clazz == ELFCLASS32                    \
160                          ? elf_getu32(swap, sh32.sh_name)       \
161                          : elf_getu32(swap, sh64.sh_name))
162
163 #define xph_addr        (clazz == ELFCLASS32                    \
164                          ? CAST(void *, &ph32)                  \
165                          : CAST(void *, &ph64))
166 #define xph_sizeof      (clazz == ELFCLASS32                    \
167                          ? sizeof(ph32)                         \
168                          : sizeof(ph64))
169 #define xph_type        (clazz == ELFCLASS32                    \
170                          ? elf_getu32(swap, ph32.p_type)        \
171                          : elf_getu32(swap, ph64.p_type))
172 #define xph_offset      CAST(off_t, (clazz == ELFCLASS32        \
173                          ? elf_getu32(swap, ph32.p_offset)      \
174                          : elf_getu64(swap, ph64.p_offset)))
175 #define xph_align       CAST(size_t, (clazz == ELFCLASS32       \
176                          ? CAST(off_t, (ph32.p_align ?          \
177                             elf_getu32(swap, ph32.p_align) : 4))\
178                          : CAST(off_t, (ph64.p_align ?          \
179                             elf_getu64(swap, ph64.p_align) : 4))))
180 #define xph_vaddr       CAST(size_t, (clazz == ELFCLASS32       \
181                          ? CAST(off_t, (ph32.p_vaddr ?          \
182                             elf_getu32(swap, ph32.p_vaddr) : 4))\
183                          : CAST(off_t, (ph64.p_vaddr ?          \
184                             elf_getu64(swap, ph64.p_vaddr) : 4))))
185 #define xph_filesz      CAST(size_t, (clazz == ELFCLASS32       \
186                          ? elf_getu32(swap, ph32.p_filesz)      \
187                          : elf_getu64(swap, ph64.p_filesz)))
188 #define xph_memsz       CAST(size_t, ((clazz == ELFCLASS32      \
189                          ? elf_getu32(swap, ph32.p_memsz)       \
190                          : elf_getu64(swap, ph64.p_memsz))))
191 #define xnh_addr        (clazz == ELFCLASS32                    \
192                          ? CAST(void *, &nh32)                  \
193                          : CAST(void *, &nh64))
194 #define xnh_sizeof      (clazz == ELFCLASS32                    \
195                          ? sizeof(nh32)                         \
196                          : sizeof(nh64))
197 #define xnh_type        (clazz == ELFCLASS32                    \
198                          ? elf_getu32(swap, nh32.n_type)        \
199                          : elf_getu32(swap, nh64.n_type))
200 #define xnh_namesz      (clazz == ELFCLASS32                    \
201                          ? elf_getu32(swap, nh32.n_namesz)      \
202                          : elf_getu32(swap, nh64.n_namesz))
203 #define xnh_descsz      (clazz == ELFCLASS32                    \
204                          ? elf_getu32(swap, nh32.n_descsz)      \
205                          : elf_getu32(swap, nh64.n_descsz))
206
207 #define xdh_addr        (clazz == ELFCLASS32                    \
208                          ? CAST(void *, &dh32)                  \
209                          : CAST(void *, &dh64))
210 #define xdh_sizeof      (clazz == ELFCLASS32                    \
211                          ? sizeof(dh32)                         \
212                          : sizeof(dh64))
213 #define xdh_tag         (clazz == ELFCLASS32                    \
214                          ? elf_getu32(swap, dh32.d_tag)         \
215                          : elf_getu64(swap, dh64.d_tag))
216 #define xdh_val         (clazz == ELFCLASS32                    \
217                          ? elf_getu32(swap, dh32.d_un.d_val)    \
218                          : elf_getu64(swap, dh64.d_un.d_val))
219
220 #define xcap_addr       (clazz == ELFCLASS32                    \
221                          ? CAST(void *, &cap32)                 \
222                          : CAST(void *, &cap64))
223 #define xcap_sizeof     (clazz == ELFCLASS32                    \
224                          ? sizeof(cap32)                        \
225                          : sizeof(cap64))
226 #define xcap_tag        (clazz == ELFCLASS32                    \
227                          ? elf_getu32(swap, cap32.c_tag)        \
228                          : elf_getu64(swap, cap64.c_tag))
229 #define xcap_val        (clazz == ELFCLASS32                    \
230                          ? elf_getu32(swap, cap32.c_un.c_val)   \
231                          : elf_getu64(swap, cap64.c_un.c_val))
232
233 #define xauxv_addr      (clazz == ELFCLASS32                    \
234                          ? CAST(void *, &auxv32)                \
235                          : CAST(void *, &auxv64))
236 #define xauxv_sizeof    (clazz == ELFCLASS32                    \
237                          ? sizeof(auxv32)                       \
238                          : sizeof(auxv64))
239 #define xauxv_type      (clazz == ELFCLASS32                    \
240                          ? elf_getu32(swap, auxv32.a_type)      \
241                          : elf_getu64(swap, auxv64.a_type))
242 #define xauxv_val       (clazz == ELFCLASS32                    \
243                          ? elf_getu32(swap, auxv32.a_v)         \
244                          : elf_getu64(swap, auxv64.a_v))
245
246 #define prpsoffsets(i)  (clazz == ELFCLASS32                    \
247                          ? prpsoffsets32[i]                     \
248                          : prpsoffsets64[i])
249
250 #ifdef ELFCORE
251 /*
252  * Try larger offsets first to avoid false matches
253  * from earlier data that happen to look like strings.
254  */
255 static const size_t     prpsoffsets32[] = {
256 #ifdef USE_NT_PSINFO
257         104,            /* SunOS 5.x (command line) */
258         88,             /* SunOS 5.x (short name) */
259 #endif /* USE_NT_PSINFO */
260
261         100,            /* SunOS 5.x (command line) */
262         84,             /* SunOS 5.x (short name) */
263
264         44,             /* Linux (command line) */
265         28,             /* Linux (short name) */
266
267         48,             /* Linux PowerPC (command line) */
268         32,             /* Linux PowerPC (short name) */
269
270         8,              /* FreeBSD */
271 };
272
273 static const size_t     prpsoffsets64[] = {
274 #ifdef USE_NT_PSINFO
275         152,            /* SunOS 5.x (command line) */
276         136,            /* SunOS 5.x (short name) */
277 #endif /* USE_NT_PSINFO */
278
279         136,            /* SunOS 5.x, 64-bit (command line) */
280         120,            /* SunOS 5.x, 64-bit (short name) */
281
282         56,             /* Linux (command line) */
283         40,             /* Linux (tested on core from 2.4.x, short name) */
284
285         16,             /* FreeBSD, 64-bit */
286 };
287
288 #define NOFFSETS32      __arraycount(prpsoffsets32)
289 #define NOFFSETS64      __arraycount(prpsoffsets64)
290
291 #define NOFFSETS        (clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
292
293 /*
294  * Look through the program headers of an executable image, searching
295  * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or
296  * "FreeBSD"; if one is found, try looking in various places in its
297  * contents for a 16-character string containing only printable
298  * characters - if found, that string should be the name of the program
299  * that dropped core.  Note: right after that 16-character string is,
300  * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and
301  * Linux, a longer string (80 characters, in 5.x, probably other
302  * SVR4-flavored systems, and Linux) containing the start of the
303  * command line for that program.
304  *
305  * SunOS 5.x core files contain two PT_NOTE sections, with the types
306  * NT_PRPSINFO (old) and NT_PSINFO (new).  These structs contain the
307  * same info about the command name and command line, so it probably
308  * isn't worthwhile to look for NT_PSINFO, but the offsets are provided
309  * above (see USE_NT_PSINFO), in case we ever decide to do so.  The
310  * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent;
311  * the SunOS 5.x file command relies on this (and prefers the latter).
312  *
313  * The signal number probably appears in a section of type NT_PRSTATUS,
314  * but that's also rather OS-dependent, in ways that are harder to
315  * dissect with heuristics, so I'm not bothering with the signal number.
316  * (I suppose the signal number could be of interest in situations where
317  * you don't have the binary of the program that dropped core; if you
318  * *do* have that binary, the debugger will probably tell you what
319  * signal it was.)
320  */
321
322 #define OS_STYLE_SVR4           0
323 #define OS_STYLE_FREEBSD        1
324 #define OS_STYLE_NETBSD         2
325
326 private const char os_style_names[][8] = {
327         "SVR4",
328         "FreeBSD",
329         "NetBSD",
330 };
331
332 #define FLAGS_CORE_STYLE                0x0003
333
334 #define FLAGS_DID_CORE                  0x0004
335 #define FLAGS_DID_OS_NOTE               0x0008
336 #define FLAGS_DID_BUILD_ID              0x0010
337 #define FLAGS_DID_CORE_STYLE            0x0020
338 #define FLAGS_DID_NETBSD_PAX            0x0040
339 #define FLAGS_DID_NETBSD_MARCH          0x0080
340 #define FLAGS_DID_NETBSD_CMODEL         0x0100
341 #define FLAGS_DID_NETBSD_EMULATION      0x0200
342 #define FLAGS_DID_NETBSD_UNKNOWN        0x0400
343 #define FLAGS_IS_CORE                   0x0800
344 #define FLAGS_DID_AUXV                  0x1000
345
346 private int
347 dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
348     int num, size_t size, off_t fsize, int *flags, uint16_t *notecount)
349 {
350         Elf32_Phdr ph32;
351         Elf64_Phdr ph64;
352         size_t offset, len;
353         unsigned char nbuf[BUFSIZ];
354         ssize_t bufsize;
355         off_t ph_off = off;
356         int ph_num = num;
357
358         if (num == 0) {
359                 if (file_printf(ms, ", no program header") == -1)
360                         return -1;
361                 return 0;
362         }
363         if (size != xph_sizeof) {
364                 if (file_printf(ms, ", corrupted program header size") == -1)
365                         return -1;
366                 return 0;
367         }
368
369         /*
370          * Loop through all the program headers.
371          */
372         for ( ; num; num--) {
373                 if (pread(fd, xph_addr, xph_sizeof, off) <
374                     CAST(ssize_t, xph_sizeof)) {
375                         file_badread(ms);
376                         return -1;
377                 }
378                 off += size;
379
380                 if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
381                         /* Perhaps warn here */
382                         continue;
383                 }
384
385                 if (xph_type != PT_NOTE)
386                         continue;
387
388                 /*
389                  * This is a PT_NOTE section; loop through all the notes
390                  * in the section.
391                  */
392                 len = xph_filesz < sizeof(nbuf) ? xph_filesz : sizeof(nbuf);
393                 if ((bufsize = pread(fd, nbuf, len, xph_offset)) == -1) {
394                         file_badread(ms);
395                         return -1;
396                 }
397                 offset = 0;
398                 for (;;) {
399                         if (offset >= CAST(size_t, bufsize))
400                                 break;
401                         offset = donote(ms, nbuf, offset, CAST(size_t, bufsize),
402                             clazz, swap, 4, flags, notecount, fd, ph_off,
403                             ph_num, fsize);
404                         if (offset == 0)
405                                 break;
406
407                 }
408         }
409         return 0;
410 }
411 #endif
412
413 static int
414 do_note_netbsd_version(struct magic_set *ms, int swap, void *v)
415 {
416         uint32_t desc;
417         memcpy(&desc, v, sizeof(desc));
418         desc = elf_getu32(swap, desc);
419
420         if (file_printf(ms, ", for NetBSD") == -1)
421                 return -1;
422         /*
423          * The version number used to be stuck as 199905, and was thus
424          * basically content-free.  Newer versions of NetBSD have fixed
425          * this and now use the encoding of __NetBSD_Version__:
426          *
427          *      MMmmrrpp00
428          *
429          * M = major version
430          * m = minor version
431          * r = release ["",A-Z,Z[A-Z] but numeric]
432          * p = patchlevel
433          */
434         if (desc > 100000000U) {
435                 uint32_t ver_patch = (desc / 100) % 100;
436                 uint32_t ver_rel = (desc / 10000) % 100;
437                 uint32_t ver_min = (desc / 1000000) % 100;
438                 uint32_t ver_maj = desc / 100000000;
439
440                 if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1)
441                         return -1;
442                 if (ver_rel == 0 && ver_patch != 0) {
443                         if (file_printf(ms, ".%u", ver_patch) == -1)
444                                 return -1;
445                 } else if (ver_rel != 0) {
446                         while (ver_rel > 26) {
447                                 if (file_printf(ms, "Z") == -1)
448                                         return -1;
449                                 ver_rel -= 26;
450                         }
451                         if (file_printf(ms, "%c", 'A' + ver_rel - 1)
452                             == -1)
453                                 return -1;
454                 }
455         }
456         return 0;
457 }
458
459 static int
460 do_note_freebsd_version(struct magic_set *ms, int swap, void *v)
461 {
462         uint32_t desc;
463
464         memcpy(&desc, v, sizeof(desc));
465         desc = elf_getu32(swap, desc);
466         if (file_printf(ms, ", for FreeBSD") == -1)
467                 return -1;
468
469         /*
470          * Contents is __FreeBSD_version, whose relation to OS
471          * versions is defined by a huge table in the Porter's
472          * Handbook.  This is the general scheme:
473          *
474          * Releases:
475          *      Mmp000 (before 4.10)
476          *      Mmi0p0 (before 5.0)
477          *      Mmm0p0
478          *
479          * Development branches:
480          *      Mmpxxx (before 4.6)
481          *      Mmp1xx (before 4.10)
482          *      Mmi1xx (before 5.0)
483          *      M000xx (pre-M.0)
484          *      Mmm1xx
485          *
486          * M = major version
487          * m = minor version
488          * i = minor version increment (491000 -> 4.10)
489          * p = patchlevel
490          * x = revision
491          *
492          * The first release of FreeBSD to use ELF by default
493          * was version 3.0.
494          */
495         if (desc == 460002) {
496                 if (file_printf(ms, " 4.6.2") == -1)
497                         return -1;
498         } else if (desc < 460100) {
499                 if (file_printf(ms, " %d.%d", desc / 100000,
500                     desc / 10000 % 10) == -1)
501                         return -1;
502                 if (desc / 1000 % 10 > 0)
503                         if (file_printf(ms, ".%d", desc / 1000 % 10) == -1)
504                                 return -1;
505                 if ((desc % 1000 > 0) || (desc % 100000 == 0))
506                         if (file_printf(ms, " (%d)", desc) == -1)
507                                 return -1;
508         } else if (desc < 500000) {
509                 if (file_printf(ms, " %d.%d", desc / 100000,
510                     desc / 10000 % 10 + desc / 1000 % 10) == -1)
511                         return -1;
512                 if (desc / 100 % 10 > 0) {
513                         if (file_printf(ms, " (%d)", desc) == -1)
514                                 return -1;
515                 } else if (desc / 10 % 10 > 0) {
516                         if (file_printf(ms, ".%d", desc / 10 % 10) == -1)
517                                 return -1;
518                 }
519         } else {
520                 if (file_printf(ms, " %d.%d", desc / 100000,
521                     desc / 1000 % 100) == -1)
522                         return -1;
523                 if ((desc / 100 % 10 > 0) ||
524                     (desc % 100000 / 100 == 0)) {
525                         if (file_printf(ms, " (%d)", desc) == -1)
526                                 return -1;
527                 } else if (desc / 10 % 10 > 0) {
528                         if (file_printf(ms, ".%d", desc / 10 % 10) == -1)
529                                 return -1;
530                 }
531         }
532         return 0;
533 }
534
535 private int
536 /*ARGSUSED*/
537 do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
538     int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz,
539     size_t noff, size_t doff, int *flags)
540 {
541         if (namesz == 4 && strcmp(RCAST(char *, &nbuf[noff]), "GNU") == 0 &&
542             type == NT_GNU_BUILD_ID && (descsz >= 4 && descsz <= 20)) {
543                 uint8_t desc[20];
544                 const char *btype;
545                 uint32_t i;
546                 *flags |= FLAGS_DID_BUILD_ID;
547                 switch (descsz) {
548                 case 8:
549                     btype = "xxHash";
550                     break;
551                 case 16:
552                     btype = "md5/uuid";
553                     break;
554                 case 20:
555                     btype = "sha1";
556                     break;
557                 default:
558                     btype = "unknown";
559                     break;
560                 }
561                 if (file_printf(ms, ", BuildID[%s]=", btype) == -1)
562                         return -1;
563                 memcpy(desc, &nbuf[doff], descsz);
564                 for (i = 0; i < descsz; i++)
565                     if (file_printf(ms, "%02x", desc[i]) == -1)
566                         return -1;
567                 return 1;
568         }
569         if (namesz == 4 && strcmp(RCAST(char *, &nbuf[noff]), "Go") == 0 &&
570             type == NT_GO_BUILD_ID && descsz < 128) {
571                 if (file_printf(ms, ", Go BuildID=%.*s",
572                     CAST(int, descsz), RCAST(char *, &nbuf[doff])) == -1)
573                         return -1;
574                 return 1;
575         }
576         return 0;
577 }
578
579 private int
580 do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
581     int swap, uint32_t namesz, uint32_t descsz,
582     size_t noff, size_t doff, int *flags)
583 {
584         const char *name = RCAST(const char *, &nbuf[noff]);
585
586         if (namesz == 5 && strcmp(name, "SuSE") == 0 &&
587                 type == NT_GNU_VERSION && descsz == 2) {
588                 *flags |= FLAGS_DID_OS_NOTE;
589                 if (file_printf(ms, ", for SuSE %d.%d", nbuf[doff],
590                     nbuf[doff + 1]) == -1)
591                     return -1;
592             return 1;
593         }
594
595         if (namesz == 4 && strcmp(name, "GNU") == 0 &&
596             type == NT_GNU_VERSION && descsz == 16) {
597                 uint32_t desc[4];
598                 memcpy(desc, &nbuf[doff], sizeof(desc));
599
600                 *flags |= FLAGS_DID_OS_NOTE;
601                 if (file_printf(ms, ", for GNU/") == -1)
602                         return -1;
603                 switch (elf_getu32(swap, desc[0])) {
604                 case GNU_OS_LINUX:
605                         if (file_printf(ms, "Linux") == -1)
606                                 return -1;
607                         break;
608                 case GNU_OS_HURD:
609                         if (file_printf(ms, "Hurd") == -1)
610                                 return -1;
611                         break;
612                 case GNU_OS_SOLARIS:
613                         if (file_printf(ms, "Solaris") == -1)
614                                 return -1;
615                         break;
616                 case GNU_OS_KFREEBSD:
617                         if (file_printf(ms, "kFreeBSD") == -1)
618                                 return -1;
619                         break;
620                 case GNU_OS_KNETBSD:
621                         if (file_printf(ms, "kNetBSD") == -1)
622                                 return -1;
623                         break;
624                 default:
625                         if (file_printf(ms, "<unknown>") == -1)
626                                 return -1;
627                 }
628                 if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
629                     elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1)
630                         return -1;
631                 return 1;
632         }
633
634         if (namesz == 7 && strcmp(name, "NetBSD") == 0) {
635                 if (type == NT_NETBSD_VERSION && descsz == 4) {
636                         *flags |= FLAGS_DID_OS_NOTE;
637                         if (do_note_netbsd_version(ms, swap, &nbuf[doff]) == -1)
638                                 return -1;
639                         return 1;
640                 }
641         }
642
643         if (namesz == 8 && strcmp(name, "FreeBSD") == 0) {
644                 if (type == NT_FREEBSD_VERSION && descsz == 4) {
645                         *flags |= FLAGS_DID_OS_NOTE;
646                         if (do_note_freebsd_version(ms, swap, &nbuf[doff])
647                             == -1)
648                                 return -1;
649                         return 1;
650                 }
651         }
652
653         if (namesz == 8 && strcmp(name, "OpenBSD") == 0 &&
654             type == NT_OPENBSD_VERSION && descsz == 4) {
655                 *flags |= FLAGS_DID_OS_NOTE;
656                 if (file_printf(ms, ", for OpenBSD") == -1)
657                         return -1;
658                 /* Content of note is always 0 */
659                 return 1;
660         }
661
662         if (namesz == 10 && strcmp(name, "DragonFly") == 0 &&
663             type == NT_DRAGONFLY_VERSION && descsz == 4) {
664                 uint32_t desc;
665                 *flags |= FLAGS_DID_OS_NOTE;
666                 if (file_printf(ms, ", for DragonFly") == -1)
667                         return -1;
668                 memcpy(&desc, &nbuf[doff], sizeof(desc));
669                 desc = elf_getu32(swap, desc);
670                 if (file_printf(ms, " %d.%d.%d", desc / 100000,
671                     desc / 10000 % 10, desc % 10000) == -1)
672                         return -1;
673                 return 1;
674         }
675         return 0;
676 }
677
678 private int
679 do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
680     int swap, uint32_t namesz, uint32_t descsz,
681     size_t noff, size_t doff, int *flags)
682 {
683         const char *name = RCAST(const char *, &nbuf[noff]);
684
685         if (namesz == 4 && strcmp(name, "PaX") == 0 &&
686             type == NT_NETBSD_PAX && descsz == 4) {
687                 static const char *pax[] = {
688                     "+mprotect",
689                     "-mprotect",
690                     "+segvguard",
691                     "-segvguard",
692                     "+ASLR",
693                     "-ASLR",
694                 };
695                 uint32_t desc;
696                 size_t i;
697                 int did = 0;
698
699                 *flags |= FLAGS_DID_NETBSD_PAX;
700                 memcpy(&desc, &nbuf[doff], sizeof(desc));
701                 desc = elf_getu32(swap, desc);
702
703                 if (desc && file_printf(ms, ", PaX: ") == -1)
704                         return -1;
705
706                 for (i = 0; i < __arraycount(pax); i++) {
707                         if (((1 << CAST(int, i)) & desc) == 0)
708                                 continue;
709                         if (file_printf(ms, "%s%s", did++ ? "," : "",
710                             pax[i]) == -1)
711                                 return -1;
712                 }
713                 return 1;
714         }
715         return 0;
716 }
717
718 private int
719 do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
720     int swap, uint32_t namesz, uint32_t descsz,
721     size_t noff, size_t doff, int *flags, size_t size, int clazz)
722 {
723 #ifdef ELFCORE
724         const char *name = RCAST(const char *, &nbuf[noff]);
725
726         int os_style = -1;
727         /*
728          * Sigh.  The 2.0.36 kernel in Debian 2.1, at
729          * least, doesn't correctly implement name
730          * sections, in core dumps, as specified by
731          * the "Program Linking" section of "UNIX(R) System
732          * V Release 4 Programmer's Guide: ANSI C and
733          * Programming Support Tools", because my copy
734          * clearly says "The first 'namesz' bytes in 'name'
735          * contain a *null-terminated* [emphasis mine]
736          * character representation of the entry's owner
737          * or originator", but the 2.0.36 kernel code
738          * doesn't include the terminating null in the
739          * name....
740          */
741         if ((namesz == 4 && strncmp(name, "CORE", 4) == 0) ||
742             (namesz == 5 && strcmp(name, "CORE") == 0)) {
743                 os_style = OS_STYLE_SVR4;
744         }
745
746         if ((namesz == 8 && strcmp(name, "FreeBSD") == 0)) {
747                 os_style = OS_STYLE_FREEBSD;
748         }
749
750         if ((namesz >= 11 && strncmp(name, "NetBSD-CORE", 11)
751             == 0)) {
752                 os_style = OS_STYLE_NETBSD;
753         }
754
755         if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
756                 if (file_printf(ms, ", %s-style", os_style_names[os_style])
757                     == -1)
758                         return -1;
759                 *flags |= FLAGS_DID_CORE_STYLE;
760                 *flags |= os_style;
761         }
762
763         switch (os_style) {
764         case OS_STYLE_NETBSD:
765                 if (type == NT_NETBSD_CORE_PROCINFO) {
766                         char sbuf[512];
767                         struct NetBSD_elfcore_procinfo pi;
768                         memset(&pi, 0, sizeof(pi));
769                         memcpy(&pi, nbuf + doff, MIN(descsz, sizeof(pi)));
770
771                         if (file_printf(ms, ", from '%.31s', pid=%u, uid=%u, "
772                             "gid=%u, nlwps=%u, lwp=%u (signal %u/code %u)",
773                             file_printable(sbuf, sizeof(sbuf),
774                             RCAST(char *, pi.cpi_name), sizeof(pi.cpi_name)),
775                             elf_getu32(swap, CAST(uint32_t, pi.cpi_pid)),
776                             elf_getu32(swap, pi.cpi_euid),
777                             elf_getu32(swap, pi.cpi_egid),
778                             elf_getu32(swap, pi.cpi_nlwps),
779                             elf_getu32(swap, CAST(uint32_t, pi.cpi_siglwp)),
780                             elf_getu32(swap, pi.cpi_signo),
781                             elf_getu32(swap, pi.cpi_sigcode)) == -1)
782                                 return -1;
783
784                         *flags |= FLAGS_DID_CORE;
785                         return 1;
786                 }
787                 break;
788
789         case OS_STYLE_FREEBSD:
790                 if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
791                         size_t argoff, pidoff;
792
793                         if (clazz == ELFCLASS32)
794                                 argoff = 4 + 4 + 17;
795                         else
796                                 argoff = 4 + 4 + 8 + 17;
797                         if (file_printf(ms, ", from '%.80s'", nbuf + doff +
798                             argoff) == -1)
799                                 return -1;
800                         pidoff = argoff + 81 + 2;
801                         if (doff + pidoff + 4 <= size) {
802                                 if (file_printf(ms, ", pid=%u",
803                                     elf_getu32(swap, *RCAST(uint32_t *, (nbuf +
804                                     doff + pidoff)))) == -1)
805                                         return -1;
806                         }
807                         *flags |= FLAGS_DID_CORE;
808                 }                           
809                 break;
810
811         default:
812                 if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
813                         size_t i, j;
814                         unsigned char c;
815                         /*
816                          * Extract the program name.  We assume
817                          * it to be 16 characters (that's what it
818                          * is in SunOS 5.x and Linux).
819                          *
820                          * Unfortunately, it's at a different offset
821                          * in various OSes, so try multiple offsets.
822                          * If the characters aren't all printable,
823                          * reject it.
824                          */
825                         for (i = 0; i < NOFFSETS; i++) {
826                                 unsigned char *cname, *cp;
827                                 size_t reloffset = prpsoffsets(i);
828                                 size_t noffset = doff + reloffset;
829                                 size_t k;
830                                 for (j = 0; j < 16; j++, noffset++,
831                                     reloffset++) {
832                                         /*
833                                          * Make sure we're not past
834                                          * the end of the buffer; if
835                                          * we are, just give up.
836                                          */
837                                         if (noffset >= size)
838                                                 goto tryanother;
839
840                                         /*
841                                          * Make sure we're not past
842                                          * the end of the contents;
843                                          * if we are, this obviously
844                                          * isn't the right offset.
845                                          */
846                                         if (reloffset >= descsz)
847                                                 goto tryanother;
848
849                                         c = nbuf[noffset];
850                                         if (c == '\0') {
851                                                 /*
852                                                  * A '\0' at the
853                                                  * beginning is
854                                                  * obviously wrong.
855                                                  * Any other '\0'
856                                                  * means we're done.
857                                                  */
858                                                 if (j == 0)
859                                                         goto tryanother;
860                                                 else
861                                                         break;
862                                         } else {
863                                                 /*
864                                                  * A nonprintable
865                                                  * character is also
866                                                  * wrong.
867                                                  */
868                                                 if (!isprint(c) || isquote(c))
869                                                         goto tryanother;
870                                         }
871                                 }
872                                 /*
873                                  * Well, that worked.
874                                  */
875
876                                 /*
877                                  * Try next offsets, in case this match is
878                                  * in the middle of a string.
879                                  */
880                                 for (k = i + 1 ; k < NOFFSETS; k++) {
881                                         size_t no;
882                                         int adjust = 1;
883                                         if (prpsoffsets(k) >= prpsoffsets(i))
884                                                 continue;
885                                         for (no = doff + prpsoffsets(k);
886                                              no < doff + prpsoffsets(i); no++)
887                                                 adjust = adjust
888                                                          && isprint(nbuf[no]);
889                                         if (adjust)
890                                                 i = k;
891                                 }
892
893                                 cname = CAST(unsigned char *,
894                                     &nbuf[doff + prpsoffsets(i)]);
895                                 for (cp = cname; cp < nbuf + size && *cp
896                                     && isprint(*cp); cp++)
897                                         continue;
898                                 /*
899                                  * Linux apparently appends a space at the end
900                                  * of the command line: remove it.
901                                  */
902                                 while (cp > cname && isspace(cp[-1]))
903                                         cp--;
904                                 if (file_printf(ms, ", from '%.*s'",
905                                     CAST(int, cp - cname), cname) == -1)
906                                         return -1;
907                                 *flags |= FLAGS_DID_CORE;
908                                 return 1;
909
910                         tryanother:
911                                 ;
912                         }
913                 }
914                 break;
915         }
916 #endif
917         return 0;
918 }
919
920 private off_t
921 get_offset_from_virtaddr(struct magic_set *ms, int swap, int clazz, int fd,
922     off_t off, int num, off_t fsize, uint64_t virtaddr)
923 {
924         Elf32_Phdr ph32;
925         Elf64_Phdr ph64;
926
927         /*
928          * Loop through all the program headers and find the header with
929          * virtual address in which the "virtaddr" belongs to.
930          */
931         for ( ; num; num--) {
932                 if (pread(fd, xph_addr, xph_sizeof, off) <
933                     CAST(ssize_t, xph_sizeof)) {
934                         file_badread(ms);
935                         return -1;
936                 }
937                 off += xph_sizeof;
938
939                 if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
940                         /* Perhaps warn here */
941                         continue;
942                 }
943
944                 if (virtaddr >= xph_vaddr && virtaddr < xph_vaddr + xph_filesz)
945                         return xph_offset + (virtaddr - xph_vaddr);
946         }
947         return 0;
948 }
949
950 private size_t
951 get_string_on_virtaddr(struct magic_set *ms,
952     int swap, int clazz, int fd, off_t ph_off, int ph_num,
953     off_t fsize, uint64_t virtaddr, char *buf, ssize_t buflen)
954 {
955         char *bptr;
956         off_t offset;
957
958         if (buflen == 0)
959                 return 0;
960
961         offset = get_offset_from_virtaddr(ms, swap, clazz, fd, ph_off, ph_num,
962             fsize, virtaddr);
963         if (offset < 0 ||
964             (buflen = pread(fd, buf, CAST(size_t, buflen), offset)) <= 0) {
965                 file_badread(ms);
966                 return 0;
967         }
968
969         buf[buflen - 1] = '\0';
970
971         /* We expect only printable characters, so return if buffer contains
972          * non-printable character before the '\0' or just '\0'. */
973         for (bptr = buf; *bptr && isprint(CAST(unsigned char, *bptr)); bptr++)
974                 continue;
975         if (*bptr != '\0')
976                 return 0;
977
978         return bptr - buf;
979 }
980
981
982 /*ARGSUSED*/
983 private int
984 do_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
985     int swap, uint32_t namesz __attribute__((__unused__)),
986     uint32_t descsz __attribute__((__unused__)),
987     size_t noff __attribute__((__unused__)), size_t doff,
988     int *flags, size_t size __attribute__((__unused__)), int clazz,
989     int fd, off_t ph_off, int ph_num, off_t fsize)
990 {
991 #ifdef ELFCORE
992         Aux32Info auxv32;
993         Aux64Info auxv64;
994         size_t elsize = xauxv_sizeof;
995         const char *tag;
996         int is_string;
997         size_t nval;
998
999         if ((*flags & (FLAGS_IS_CORE|FLAGS_DID_CORE_STYLE)) !=
1000             (FLAGS_IS_CORE|FLAGS_DID_CORE_STYLE))
1001                 return 0;
1002
1003         switch (*flags & FLAGS_CORE_STYLE) {
1004         case OS_STYLE_SVR4:
1005                 if (type != NT_AUXV)
1006                         return 0;
1007                 break;
1008 #ifdef notyet
1009         case OS_STYLE_NETBSD:
1010                 if (type != NT_NETBSD_CORE_AUXV)
1011                         return 0;
1012                 break;
1013         case OS_STYLE_FREEBSD:
1014                 if (type != NT_FREEBSD_PROCSTAT_AUXV)
1015                         return 0;
1016                 break;
1017 #endif
1018         default:
1019                 return 0;
1020         }
1021
1022         *flags |= FLAGS_DID_AUXV;
1023
1024         nval = 0;
1025         for (size_t off = 0; off + elsize <= descsz; off += elsize) {
1026                 memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof);
1027                 /* Limit processing to 50 vector entries to prevent DoS */
1028                 if (nval++ >= 50) {
1029                         file_error(ms, 0, "Too many ELF Auxv elements");
1030                         return 1;
1031                 }
1032
1033                 switch(xauxv_type) {
1034                 case AT_LINUX_EXECFN:
1035                         is_string = 1;
1036                         tag = "execfn";
1037                         break;
1038                 case AT_LINUX_PLATFORM:
1039                         is_string = 1;
1040                         tag = "platform";
1041                         break;
1042                 case AT_LINUX_UID:
1043                         is_string = 0;
1044                         tag = "real uid";
1045                         break;
1046                 case AT_LINUX_GID:
1047                         is_string = 0;
1048                         tag = "real gid";
1049                         break;
1050                 case AT_LINUX_EUID:
1051                         is_string = 0;
1052                         tag = "effective uid";
1053                         break;
1054                 case AT_LINUX_EGID:
1055                         is_string = 0;
1056                         tag = "effective gid";
1057                         break;
1058                 default:
1059                         is_string = 0;
1060                         tag = NULL;
1061                         break;
1062                 }
1063
1064                 if (tag == NULL)
1065                         continue;
1066
1067                 if (is_string) {
1068                         char buf[256];
1069                         ssize_t buflen;
1070                         buflen = get_string_on_virtaddr(ms, swap, clazz, fd,
1071                             ph_off, ph_num, fsize, xauxv_val, buf, sizeof(buf));
1072
1073                         if (buflen == 0)
1074                                 continue;
1075
1076                         if (file_printf(ms, ", %s: '%s'", tag, buf) == -1)
1077                                 return -1;
1078                 } else {
1079                         if (file_printf(ms, ", %s: %d", tag,
1080                             CAST(int, xauxv_val)) == -1)
1081                                 return -1;
1082                 }
1083         }
1084         return 1;
1085 #else
1086         return 0;
1087 #endif
1088 }
1089
1090 private size_t
1091 dodynamic(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
1092     int clazz, int swap)
1093 {
1094         Elf32_Dyn dh32;
1095         Elf64_Dyn dh64;
1096         unsigned char *dbuf = CAST(unsigned char *, vbuf);
1097
1098         if (xdh_sizeof + offset > size) {
1099                 /*
1100                  * We're out of note headers.
1101                  */
1102                 return xdh_sizeof + offset;
1103         }
1104
1105         memcpy(xdh_addr, &dbuf[offset], xdh_sizeof);
1106         offset += xdh_sizeof;
1107
1108         switch (xdh_tag) {
1109         case DT_FLAGS_1:
1110                 if (xdh_val & DF_1_PIE)
1111                         ms->mode |= 0111;
1112                 else
1113                         ms->mode &= ~0111;
1114                 break;
1115         default:
1116                 break;
1117         }
1118         return offset;
1119 }
1120
1121
1122 private size_t
1123 donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
1124     int clazz, int swap, size_t align, int *flags, uint16_t *notecount,
1125     int fd, off_t ph_off, int ph_num, off_t fsize)
1126 {
1127         Elf32_Nhdr nh32;
1128         Elf64_Nhdr nh64;
1129         size_t noff, doff;
1130         uint32_t namesz, descsz;
1131         unsigned char *nbuf = CAST(unsigned char *, vbuf);
1132
1133         if (*notecount == 0)
1134                 return 0;
1135         --*notecount;
1136
1137         if (xnh_sizeof + offset > size) {
1138                 /*
1139                  * We're out of note headers.
1140                  */
1141                 return xnh_sizeof + offset;
1142         }
1143         /*XXX: GCC */
1144         memset(&nh32, 0, sizeof(nh32));
1145         memset(&nh64, 0, sizeof(nh64));
1146
1147         memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
1148         offset += xnh_sizeof;
1149
1150         namesz = xnh_namesz;
1151         descsz = xnh_descsz;
1152
1153         if ((namesz == 0) && (descsz == 0)) {
1154                 /*
1155                  * We're out of note headers.
1156                  */
1157                 return (offset >= size) ? offset : size;
1158         }
1159
1160         if (namesz & 0x80000000) {
1161                 if (file_printf(ms, ", bad note name size %#lx",
1162                     CAST(unsigned long, namesz)) == -1)
1163                         return -1;
1164             return 0;
1165         }
1166
1167         if (descsz & 0x80000000) {
1168                 if (file_printf(ms, ", bad note description size %#lx",
1169                     CAST(unsigned long, descsz)) == -1)
1170                         return -1;
1171             return 0;
1172         }
1173
1174         noff = offset;
1175         doff = ELF_ALIGN(offset + namesz);
1176
1177         if (offset + namesz > size) {
1178                 /*
1179                  * We're past the end of the buffer.
1180                  */
1181                 return doff;
1182         }
1183
1184         offset = ELF_ALIGN(doff + descsz);
1185         if (doff + descsz > size) {
1186                 /*
1187                  * We're past the end of the buffer.
1188                  */
1189                 return (offset >= size) ? offset : size;
1190         }
1191
1192
1193         if ((*flags & FLAGS_DID_OS_NOTE) == 0) {
1194                 if (do_os_note(ms, nbuf, xnh_type, swap,
1195                     namesz, descsz, noff, doff, flags))
1196                         return offset;
1197         }
1198
1199         if ((*flags & FLAGS_DID_BUILD_ID) == 0) {
1200                 if (do_bid_note(ms, nbuf, xnh_type, swap,
1201                     namesz, descsz, noff, doff, flags))
1202                         return offset;
1203         }
1204
1205         if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) {
1206                 if (do_pax_note(ms, nbuf, xnh_type, swap,
1207                     namesz, descsz, noff, doff, flags))
1208                         return offset;
1209         }
1210
1211         if ((*flags & FLAGS_DID_CORE) == 0) {
1212                 if (do_core_note(ms, nbuf, xnh_type, swap,
1213                     namesz, descsz, noff, doff, flags, size, clazz))
1214                         return offset;
1215         }
1216
1217         if ((*flags & FLAGS_DID_AUXV) == 0) {
1218                 if (do_auxv_note(ms, nbuf, xnh_type, swap,
1219                         namesz, descsz, noff, doff, flags, size, clazz,
1220                         fd, ph_off, ph_num, fsize))
1221                         return offset;
1222         }
1223
1224         if (namesz == 7 && strcmp(RCAST(char *, &nbuf[noff]), "NetBSD") == 0) {
1225                 int descw, flag;
1226                 const char *str, *tag;
1227                 if (descsz > 100)
1228                         descsz = 100;
1229                 switch (xnh_type) {
1230                 case NT_NETBSD_VERSION:
1231                         return offset;
1232                 case NT_NETBSD_MARCH:
1233                         flag = FLAGS_DID_NETBSD_MARCH;
1234                         tag = "compiled for";
1235                         break;
1236                 case NT_NETBSD_CMODEL:
1237                         flag = FLAGS_DID_NETBSD_CMODEL;
1238                         tag = "compiler model";
1239                         break;
1240                 case NT_NETBSD_EMULATION:
1241                         flag = FLAGS_DID_NETBSD_EMULATION;
1242                         tag = "emulation:";
1243                         break;
1244                 default:
1245                         if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
1246                                 return offset;
1247                         *flags |= FLAGS_DID_NETBSD_UNKNOWN;
1248                         if (file_printf(ms, ", note=%u", xnh_type) == -1)
1249                                 return offset;
1250                         return offset;
1251                 }
1252
1253                 if (*flags & flag)
1254                         return offset;
1255                 str = RCAST(const char *, &nbuf[doff]);
1256                 descw = CAST(int, descsz);
1257                 *flags |= flag;
1258                 file_printf(ms, ", %s: %.*s", tag, descw, str);
1259                 return offset;
1260         }
1261
1262         return offset;
1263 }
1264
1265 /* SunOS 5.x hardware capability descriptions */
1266 typedef struct cap_desc {
1267         uint64_t cd_mask;
1268         const char *cd_name;
1269 } cap_desc_t;
1270
1271 static const cap_desc_t cap_desc_sparc[] = {
1272         { AV_SPARC_MUL32,               "MUL32" },
1273         { AV_SPARC_DIV32,               "DIV32" },
1274         { AV_SPARC_FSMULD,              "FSMULD" },
1275         { AV_SPARC_V8PLUS,              "V8PLUS" },
1276         { AV_SPARC_POPC,                "POPC" },
1277         { AV_SPARC_VIS,                 "VIS" },
1278         { AV_SPARC_VIS2,                "VIS2" },
1279         { AV_SPARC_ASI_BLK_INIT,        "ASI_BLK_INIT" },
1280         { AV_SPARC_FMAF,                "FMAF" },
1281         { AV_SPARC_FJFMAU,              "FJFMAU" },
1282         { AV_SPARC_IMA,                 "IMA" },
1283         { 0, NULL }
1284 };
1285
1286 static const cap_desc_t cap_desc_386[] = {
1287         { AV_386_FPU,                   "FPU" },
1288         { AV_386_TSC,                   "TSC" },
1289         { AV_386_CX8,                   "CX8" },
1290         { AV_386_SEP,                   "SEP" },
1291         { AV_386_AMD_SYSC,              "AMD_SYSC" },
1292         { AV_386_CMOV,                  "CMOV" },
1293         { AV_386_MMX,                   "MMX" },
1294         { AV_386_AMD_MMX,               "AMD_MMX" },
1295         { AV_386_AMD_3DNow,             "AMD_3DNow" },
1296         { AV_386_AMD_3DNowx,            "AMD_3DNowx" },
1297         { AV_386_FXSR,                  "FXSR" },
1298         { AV_386_SSE,                   "SSE" },
1299         { AV_386_SSE2,                  "SSE2" },
1300         { AV_386_PAUSE,                 "PAUSE" },
1301         { AV_386_SSE3,                  "SSE3" },
1302         { AV_386_MON,                   "MON" },
1303         { AV_386_CX16,                  "CX16" },
1304         { AV_386_AHF,                   "AHF" },
1305         { AV_386_TSCP,                  "TSCP" },
1306         { AV_386_AMD_SSE4A,             "AMD_SSE4A" },
1307         { AV_386_POPCNT,                "POPCNT" },
1308         { AV_386_AMD_LZCNT,             "AMD_LZCNT" },
1309         { AV_386_SSSE3,                 "SSSE3" },
1310         { AV_386_SSE4_1,                "SSE4.1" },
1311         { AV_386_SSE4_2,                "SSE4.2" },
1312         { 0, NULL }
1313 };
1314
1315 private int
1316 doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
1317     size_t size, off_t fsize, int mach, int strtab, int *flags,
1318     uint16_t *notecount)
1319 {
1320         Elf32_Shdr sh32;
1321         Elf64_Shdr sh64;
1322         int stripped = 1, has_debug_info = 0;
1323         size_t nbadcap = 0;
1324         void *nbuf;
1325         off_t noff, coff, name_off;
1326         uint64_t cap_hw1 = 0;   /* SunOS 5.x hardware capabilities */
1327         uint64_t cap_sf1 = 0;   /* SunOS 5.x software capabilities */
1328         char name[50];
1329         ssize_t namesize;
1330
1331         if (num == 0) {
1332                 if (file_printf(ms, ", no section header") == -1)
1333                         return -1;
1334                 return 0;
1335         }
1336         if (size != xsh_sizeof) {
1337                 if (file_printf(ms, ", corrupted section header size") == -1)
1338                         return -1;
1339                 return 0;
1340         }
1341
1342         /* Read offset of name section to be able to read section names later */
1343         if (pread(fd, xsh_addr, xsh_sizeof, CAST(off_t, (off + size * strtab)))
1344             < CAST(ssize_t, xsh_sizeof)) {
1345                 if (file_printf(ms, ", missing section headers") == -1)
1346                         return -1;
1347                 return 0;
1348         }
1349         name_off = xsh_offset;
1350
1351         if (fsize != SIZE_UNKNOWN && fsize < name_off) {
1352                 if (file_printf(ms, ", too large section header offset %jd",
1353                     (intmax_t)name_off) == -1)
1354                         return -1;
1355                 return 0;
1356         }
1357
1358         for ( ; num; num--) {
1359                 /* Read the name of this section. */
1360                 if ((namesize = pread(fd, name, sizeof(name) - 1,
1361                     name_off + xsh_name)) == -1) {
1362                         file_badread(ms);
1363                         return -1;
1364                 }
1365                 name[namesize] = '\0';
1366                 if (strcmp(name, ".debug_info") == 0) {
1367                         has_debug_info = 1;
1368                         stripped = 0;
1369                 }
1370
1371                 if (pread(fd, xsh_addr, xsh_sizeof, off) <
1372                     CAST(ssize_t, xsh_sizeof)) {
1373                         file_badread(ms);
1374                         return -1;
1375                 }
1376                 off += size;
1377
1378                 /* Things we can determine before we seek */
1379                 switch (xsh_type) {
1380                 case SHT_SYMTAB:
1381 #if 0
1382                 case SHT_DYNSYM:
1383 #endif
1384                         stripped = 0;
1385                         break;
1386                 default:
1387                         if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) {
1388                                 /* Perhaps warn here */
1389                                 continue;
1390                         }
1391                         break;
1392                 }
1393
1394
1395                 /* Things we can determine when we seek */
1396                 switch (xsh_type) {
1397                 case SHT_NOTE:
1398                         if (CAST(uintmax_t, (xsh_size + xsh_offset)) >
1399                             CAST(uintmax_t, fsize)) {
1400                                 if (file_printf(ms,
1401                                     ", note offset/size %#" INTMAX_T_FORMAT
1402                                     "x+%#" INTMAX_T_FORMAT "x exceeds"
1403                                     " file size %#" INTMAX_T_FORMAT "x",
1404                                     CAST(uintmax_t, xsh_offset),
1405                                     CAST(uintmax_t, xsh_size),
1406                                     CAST(uintmax_t, fsize)) == -1)
1407                                         return -1;
1408                                 return 0;
1409                         }
1410                         if ((nbuf = malloc(xsh_size)) == NULL) {
1411                                 file_error(ms, errno, "Cannot allocate memory"
1412                                     " for note");
1413                                 return -1;
1414                         }
1415                         if (pread(fd, nbuf, xsh_size, xsh_offset) <
1416                             CAST(ssize_t, xsh_size)) {
1417                                 file_badread(ms);
1418                                 free(nbuf);
1419                                 return -1;
1420                         }
1421
1422                         noff = 0;
1423                         for (;;) {
1424                                 if (noff >= CAST(off_t, xsh_size))
1425                                         break;
1426                                 noff = donote(ms, nbuf, CAST(size_t, noff),
1427                                     xsh_size, clazz, swap, 4, flags, notecount,
1428                                     fd, 0, 0, 0);
1429                                 if (noff == 0)
1430                                         break;
1431                         }
1432                         free(nbuf);
1433                         break;
1434                 case SHT_SUNW_cap:
1435                         switch (mach) {
1436                         case EM_SPARC:
1437                         case EM_SPARCV9:
1438                         case EM_IA_64:
1439                         case EM_386:
1440                         case EM_AMD64:
1441                                 break;
1442                         default:
1443                                 goto skip;
1444                         }
1445
1446                         if (nbadcap > 5)
1447                                 break;
1448                         if (lseek(fd, xsh_offset, SEEK_SET)
1449                             == CAST(off_t, -1)) {
1450                                 file_badseek(ms);
1451                                 return -1;
1452                         }
1453                         coff = 0;
1454                         for (;;) {
1455                                 Elf32_Cap cap32;
1456                                 Elf64_Cap cap64;
1457                                 char cbuf[/*CONSTCOND*/
1458                                     MAX(sizeof(cap32), sizeof(cap64))];
1459                                 if ((coff += xcap_sizeof) >
1460                                     CAST(off_t, xsh_size))
1461                                         break;
1462                                 if (read(fd, cbuf, CAST(size_t, xcap_sizeof)) !=
1463                                     CAST(ssize_t, xcap_sizeof)) {
1464                                         file_badread(ms);
1465                                         return -1;
1466                                 }
1467                                 if (cbuf[0] == 'A') {
1468 #ifdef notyet
1469                                         char *p = cbuf + 1;
1470                                         uint32_t len, tag;
1471                                         memcpy(&len, p, sizeof(len));
1472                                         p += 4;
1473                                         len = getu32(swap, len);
1474                                         if (memcmp("gnu", p, 3) != 0) {
1475                                             if (file_printf(ms,
1476                                                 ", unknown capability %.3s", p)
1477                                                 == -1)
1478                                                 return -1;
1479                                             break;
1480                                         }
1481                                         p += strlen(p) + 1;
1482                                         tag = *p++;
1483                                         memcpy(&len, p, sizeof(len));
1484                                         p += 4;
1485                                         len = getu32(swap, len);
1486                                         if (tag != 1) {
1487                                             if (file_printf(ms, ", unknown gnu"
1488                                                 " capability tag %d", tag)
1489                                                 == -1)
1490                                                 return -1;
1491                                             break;
1492                                         }
1493                                         // gnu attributes
1494 #endif
1495                                         break;
1496                                 }
1497                                 memcpy(xcap_addr, cbuf, xcap_sizeof);
1498                                 switch (xcap_tag) {
1499                                 case CA_SUNW_NULL:
1500                                         break;
1501                                 case CA_SUNW_HW_1:
1502                                         cap_hw1 |= xcap_val;
1503                                         break;
1504                                 case CA_SUNW_SF_1:
1505                                         cap_sf1 |= xcap_val;
1506                                         break;
1507                                 default:
1508                                         if (file_printf(ms,
1509                                             ", with unknown capability "
1510                                             "%#" INT64_T_FORMAT "x = %#"
1511                                             INT64_T_FORMAT "x",
1512                                             CAST(unsigned long long, xcap_tag),
1513                                             CAST(unsigned long long, xcap_val))
1514                                             == -1)
1515                                                 return -1;
1516                                         if (nbadcap++ > 2)
1517                                                 coff = xsh_size;
1518                                         break;
1519                                 }
1520                         }
1521                         /*FALLTHROUGH*/
1522                 skip:
1523                 default:
1524                         break;
1525                 }
1526         }
1527
1528         if (has_debug_info) {
1529                 if (file_printf(ms, ", with debug_info") == -1)
1530                         return -1;
1531         }
1532         if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
1533                 return -1;
1534         if (cap_hw1) {
1535                 const cap_desc_t *cdp;
1536                 switch (mach) {
1537                 case EM_SPARC:
1538                 case EM_SPARC32PLUS:
1539                 case EM_SPARCV9:
1540                         cdp = cap_desc_sparc;
1541                         break;
1542                 case EM_386:
1543                 case EM_IA_64:
1544                 case EM_AMD64:
1545                         cdp = cap_desc_386;
1546                         break;
1547                 default:
1548                         cdp = NULL;
1549                         break;
1550                 }
1551                 if (file_printf(ms, ", uses") == -1)
1552                         return -1;
1553                 if (cdp) {
1554                         while (cdp->cd_name) {
1555                                 if (cap_hw1 & cdp->cd_mask) {
1556                                         if (file_printf(ms,
1557                                             " %s", cdp->cd_name) == -1)
1558                                                 return -1;
1559                                         cap_hw1 &= ~cdp->cd_mask;
1560                                 }
1561                                 ++cdp;
1562                         }
1563                         if (cap_hw1)
1564                                 if (file_printf(ms,
1565                                     " unknown hardware capability %#"
1566                                     INT64_T_FORMAT "x",
1567                                     CAST(unsigned long long, cap_hw1)) == -1)
1568                                         return -1;
1569                 } else {
1570                         if (file_printf(ms,
1571                             " hardware capability %#" INT64_T_FORMAT "x",
1572                             CAST(unsigned long long, cap_hw1)) == -1)
1573                                 return -1;
1574                 }
1575         }
1576         if (cap_sf1) {
1577                 if (cap_sf1 & SF1_SUNW_FPUSED) {
1578                         if (file_printf(ms,
1579                             (cap_sf1 & SF1_SUNW_FPKNWN)
1580                             ? ", uses frame pointer"
1581                             : ", not known to use frame pointer") == -1)
1582                                 return -1;
1583                 }
1584                 cap_sf1 &= ~SF1_SUNW_MASK;
1585                 if (cap_sf1)
1586                         if (file_printf(ms,
1587                             ", with unknown software capability %#"
1588                             INT64_T_FORMAT "x",
1589                             CAST(unsigned long long, cap_sf1)) == -1)
1590                                 return -1;
1591         }
1592         return 0;
1593 }
1594
1595 /*
1596  * Look through the program headers of an executable image, searching
1597  * for a PT_INTERP section; if one is found, it's dynamically linked,
1598  * otherwise it's statically linked.
1599  */
1600 private int
1601 dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
1602     int num, size_t size, off_t fsize, int sh_num, int *flags,
1603     uint16_t *notecount)
1604 {
1605         Elf32_Phdr ph32;
1606         Elf64_Phdr ph64;
1607         const char *linking_style = "statically";
1608         unsigned char nbuf[BUFSIZ];
1609         char ibuf[BUFSIZ];
1610         char interp[BUFSIZ];
1611         ssize_t bufsize;
1612         size_t offset, align, len;
1613
1614         if (num == 0) {
1615                 if (file_printf(ms, ", no program header") == -1)
1616                         return -1;
1617                 return 0;
1618         }
1619         if (size != xph_sizeof) {
1620                 if (file_printf(ms, ", corrupted program header size") == -1)
1621                         return -1;
1622                 return 0;
1623         }
1624
1625         interp[0] = '\0';
1626         for ( ; num; num--) {
1627                 int doread;
1628                 if (pread(fd, xph_addr, xph_sizeof, off) <
1629                     CAST(ssize_t, xph_sizeof)) {
1630                         file_badread(ms);
1631                         return -1;
1632                 }
1633
1634                 off += size;
1635                 bufsize = 0;
1636                 align = 4;
1637
1638                 /* Things we can determine before we seek */
1639                 switch (xph_type) {
1640                 case PT_DYNAMIC:
1641                         doread = 1;
1642                         break;
1643                 case PT_NOTE:
1644                         if (sh_num)     /* Did this through section headers */
1645                                 continue;
1646                         if (((align = xph_align) & 0x80000000UL) != 0 ||
1647                             align < 4) {
1648                                 if (file_printf(ms,
1649                                     ", invalid note alignment %#lx",
1650                                     CAST(unsigned long, align)) == -1)
1651                                         return -1;
1652                                 align = 4;
1653                         }
1654                         /*FALLTHROUGH*/
1655                 case PT_INTERP:
1656                         linking_style = "dynamically";
1657                         doread = 1;
1658                         break;
1659                 default:
1660                         doread = 0;
1661                         if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
1662                                 /* Maybe warn here? */
1663                                 continue;
1664                         }
1665                         break;
1666                 }
1667
1668                 if (doread) {
1669                         len = xph_filesz < sizeof(nbuf) ? xph_filesz
1670                             : sizeof(nbuf);
1671                         bufsize = pread(fd, nbuf, len, xph_offset);
1672                         if (bufsize == -1) {
1673                                 file_badread(ms);
1674                                 return -1;
1675                         }
1676                 } else
1677                         len = 0;
1678
1679                 /* Things we can determine when we seek */
1680                 switch (xph_type) {
1681                 case PT_DYNAMIC:
1682                         offset = 0;
1683                         // Let DF_1 determine if we are PIE or not.
1684                         ms->mode &= ~0111;
1685                         for (;;) {
1686                                 if (offset >= CAST(size_t, bufsize))
1687                                         break;
1688                                 offset = dodynamic(ms, nbuf, offset,
1689                                     CAST(size_t, bufsize), clazz, swap);
1690                                 if (offset == 0)
1691                                         break;
1692                         }
1693                         break;
1694
1695                 case PT_INTERP:
1696                         if (bufsize && nbuf[0]) {
1697                                 nbuf[bufsize - 1] = '\0';
1698                                 memcpy(interp, nbuf, CAST(size_t, bufsize));
1699                         } else
1700                                 strlcpy(interp, "*empty*", sizeof(interp));
1701                         break;
1702                 case PT_NOTE:
1703                         /*
1704                          * This is a PT_NOTE section; loop through all the notes
1705                          * in the section.
1706                          */
1707                         offset = 0;
1708                         for (;;) {
1709                                 if (offset >= CAST(size_t, bufsize))
1710                                         break;
1711                                 offset = donote(ms, nbuf, offset,
1712                                     CAST(size_t, bufsize), clazz, swap, align,
1713                                     flags, notecount, fd, 0, 0, 0);
1714                                 if (offset == 0)
1715                                         break;
1716                         }
1717                         break;
1718                 default:
1719                         break;
1720                 }
1721         }
1722         if (file_printf(ms, ", %s linked", linking_style)
1723             == -1)
1724                 return -1;
1725         if (interp[0])
1726                 if (file_printf(ms, ", interpreter %s",
1727                     file_printable(ibuf, sizeof(ibuf), interp, sizeof(interp)))
1728                         == -1)
1729                         return -1;
1730         return 0;
1731 }
1732
1733
1734 protected int
1735 file_tryelf(struct magic_set *ms, const struct buffer *b)
1736 {
1737         int fd = b->fd;
1738         const unsigned char *buf = CAST(const unsigned char *, b->fbuf);
1739         size_t nbytes = b->flen;
1740         union {
1741                 int32_t l;
1742                 char c[sizeof(int32_t)];
1743         } u;
1744         int clazz;
1745         int swap;
1746         struct stat st;
1747         const struct stat *stp;
1748         off_t fsize;
1749         int flags = 0;
1750         Elf32_Ehdr elf32hdr;
1751         Elf64_Ehdr elf64hdr;
1752         uint16_t type, phnum, shnum, notecount;
1753
1754         if (ms->flags & (MAGIC_MIME|MAGIC_APPLE|MAGIC_EXTENSION))
1755                 return 0;
1756         /*
1757          * ELF executables have multiple section headers in arbitrary
1758          * file locations and thus file(1) cannot determine it from easily.
1759          * Instead we traverse thru all section headers until a symbol table
1760          * one is found or else the binary is stripped.
1761          * Return immediately if it's not ELF (so we avoid pipe2file unless
1762          * needed).
1763          */
1764         if (buf[EI_MAG0] != ELFMAG0
1765             || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
1766             || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
1767                 return 0;
1768
1769         /*
1770          * If we cannot seek, it must be a pipe, socket or fifo.
1771          */
1772         if((lseek(fd, CAST(off_t, 0), SEEK_SET) == CAST(off_t, -1))
1773             && (errno == ESPIPE))
1774                 fd = file_pipe2file(ms, fd, buf, nbytes);
1775
1776         if (fd == -1) {
1777                 file_badread(ms);
1778                 return -1;
1779         }
1780
1781         stp = &b->st;
1782         /*
1783          * b->st.st_size != 0 if previous fstat() succeeded,
1784          * which is likely, we can avoid extra stat() call.
1785          */
1786         if (b->st.st_size == 0) {
1787                 stp = &st;
1788                 if (fstat(fd, &st) == -1) {
1789                         file_badread(ms);
1790                         return -1;
1791                 }
1792         }
1793         if (S_ISREG(stp->st_mode) || stp->st_size != 0)
1794                 fsize = stp->st_size;
1795         else
1796                 fsize = SIZE_UNKNOWN;
1797
1798         clazz = buf[EI_CLASS];
1799
1800         switch (clazz) {
1801         case ELFCLASS32:
1802 #undef elf_getu
1803 #define elf_getu(a, b)  elf_getu32(a, b)
1804 #undef elfhdr
1805 #define elfhdr elf32hdr
1806 #include "elfclass.h"
1807         case ELFCLASS64:
1808 #undef elf_getu
1809 #define elf_getu(a, b)  elf_getu64(a, b)
1810 #undef elfhdr
1811 #define elfhdr elf64hdr
1812 #include "elfclass.h"
1813         default:
1814             if (file_printf(ms, ", unknown class %d", clazz) == -1)
1815                     return -1;
1816             break;
1817         }
1818         return 0;
1819 }
1820 #endif