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