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