]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/file/src/readelf.c
MFC r323278: Fix an incorrectly used conditional causing buffer overflow.
[FreeBSD/stable/10.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.128 2016/10/04 21:43:10 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_DID_CORE                  0x001
314 #define FLAGS_DID_OS_NOTE               0x002
315 #define FLAGS_DID_BUILD_ID              0x004
316 #define FLAGS_DID_CORE_STYLE            0x008
317 #define FLAGS_DID_NETBSD_PAX            0x010
318 #define FLAGS_DID_NETBSD_MARCH          0x020
319 #define FLAGS_DID_NETBSD_CMODEL         0x040
320 #define FLAGS_DID_NETBSD_UNKNOWN        0x080
321 #define FLAGS_IS_CORE                   0x100
322 #define FLAGS_DID_AUXV                  0x200
323
324 private int
325 dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
326     int num, size_t size, off_t fsize, int *flags, uint16_t *notecount)
327 {
328         Elf32_Phdr ph32;
329         Elf64_Phdr ph64;
330         size_t offset, len;
331         unsigned char nbuf[BUFSIZ];
332         ssize_t bufsize;
333         off_t ph_off = off;
334         int ph_num = num;
335
336         if (size != xph_sizeof) {
337                 if (file_printf(ms, ", corrupted program header size") == -1)
338                         return -1;
339                 return 0;
340         }
341
342         /*
343          * Loop through all the program headers.
344          */
345         for ( ; num; num--) {
346                 if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
347                         file_badread(ms);
348                         return -1;
349                 }
350                 off += size;
351
352                 if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
353                         /* Perhaps warn here */
354                         continue;
355                 }
356
357                 if (xph_type != PT_NOTE)
358                         continue;
359
360                 /*
361                  * This is a PT_NOTE section; loop through all the notes
362                  * in the section.
363                  */
364                 len = xph_filesz < sizeof(nbuf) ? xph_filesz : sizeof(nbuf);
365                 if ((bufsize = pread(fd, nbuf, len, xph_offset)) == -1) {
366                         file_badread(ms);
367                         return -1;
368                 }
369                 offset = 0;
370                 for (;;) {
371                         if (offset >= (size_t)bufsize)
372                                 break;
373                         offset = donote(ms, nbuf, offset, (size_t)bufsize,
374                             clazz, swap, 4, flags, notecount, fd, ph_off,
375                             ph_num, fsize);
376                         if (offset == 0)
377                                 break;
378
379                 }
380         }
381         return 0;
382 }
383 #endif
384
385 static void
386 do_note_netbsd_version(struct magic_set *ms, int swap, void *v)
387 {
388         uint32_t desc;
389         (void)memcpy(&desc, v, sizeof(desc));
390         desc = elf_getu32(swap, desc);
391
392         if (file_printf(ms, ", for NetBSD") == -1)
393                 return;
394         /*
395          * The version number used to be stuck as 199905, and was thus
396          * basically content-free.  Newer versions of NetBSD have fixed
397          * this and now use the encoding of __NetBSD_Version__:
398          *
399          *      MMmmrrpp00
400          *
401          * M = major version
402          * m = minor version
403          * r = release ["",A-Z,Z[A-Z] but numeric]
404          * p = patchlevel
405          */
406         if (desc > 100000000U) {
407                 uint32_t ver_patch = (desc / 100) % 100;
408                 uint32_t ver_rel = (desc / 10000) % 100;
409                 uint32_t ver_min = (desc / 1000000) % 100;
410                 uint32_t ver_maj = desc / 100000000;
411
412                 if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1)
413                         return;
414                 if (ver_rel == 0 && ver_patch != 0) {
415                         if (file_printf(ms, ".%u", ver_patch) == -1)
416                                 return;
417                 } else if (ver_rel != 0) {
418                         while (ver_rel > 26) {
419                                 if (file_printf(ms, "Z") == -1)
420                                         return;
421                                 ver_rel -= 26;
422                         }
423                         if (file_printf(ms, "%c", 'A' + ver_rel - 1)
424                             == -1)
425                                 return;
426                 }
427         }
428 }
429
430 static void
431 do_note_freebsd_version(struct magic_set *ms, int swap, void *v)
432 {
433         uint32_t desc;
434
435         (void)memcpy(&desc, v, sizeof(desc));
436         desc = elf_getu32(swap, desc);
437         if (file_printf(ms, ", for FreeBSD") == -1)
438                 return;
439
440         /*
441          * Contents is __FreeBSD_version, whose relation to OS
442          * versions is defined by a huge table in the Porter's
443          * Handbook.  This is the general scheme:
444          * 
445          * Releases:
446          *      Mmp000 (before 4.10)
447          *      Mmi0p0 (before 5.0)
448          *      Mmm0p0
449          * 
450          * Development branches:
451          *      Mmpxxx (before 4.6)
452          *      Mmp1xx (before 4.10)
453          *      Mmi1xx (before 5.0)
454          *      M000xx (pre-M.0)
455          *      Mmm1xx
456          * 
457          * M = major version
458          * m = minor version
459          * i = minor version increment (491000 -> 4.10)
460          * p = patchlevel
461          * x = revision
462          * 
463          * The first release of FreeBSD to use ELF by default
464          * was version 3.0.
465          */
466         if (desc == 460002) {
467                 if (file_printf(ms, " 4.6.2") == -1)
468                         return;
469         } else if (desc < 460100) {
470                 if (file_printf(ms, " %d.%d", desc / 100000,
471                     desc / 10000 % 10) == -1)
472                         return;
473                 if (desc / 1000 % 10 > 0)
474                         if (file_printf(ms, ".%d", desc / 1000 % 10) == -1)
475                                 return;
476                 if ((desc % 1000 > 0) || (desc % 100000 == 0))
477                         if (file_printf(ms, " (%d)", desc) == -1)
478                                 return;
479         } else if (desc < 500000) {
480                 if (file_printf(ms, " %d.%d", desc / 100000,
481                     desc / 10000 % 10 + desc / 1000 % 10) == -1)
482                         return;
483                 if (desc / 100 % 10 > 0) {
484                         if (file_printf(ms, " (%d)", desc) == -1)
485                                 return;
486                 } else if (desc / 10 % 10 > 0) {
487                         if (file_printf(ms, ".%d", desc / 10 % 10) == -1)
488                                 return;
489                 }
490         } else {
491                 if (file_printf(ms, " %d.%d", desc / 100000,
492                     desc / 1000 % 100) == -1)
493                         return;
494                 if ((desc / 100 % 10 > 0) ||
495                     (desc % 100000 / 100 == 0)) {
496                         if (file_printf(ms, " (%d)", desc) == -1)
497                                 return;
498                 } else if (desc / 10 % 10 > 0) {
499                         if (file_printf(ms, ".%d", desc / 10 % 10) == -1)
500                                 return;
501                 }
502         }
503 }
504
505 private int
506 /*ARGSUSED*/
507 do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
508     int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz,
509     size_t noff, size_t doff, int *flags)
510 {
511         if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
512             type == NT_GNU_BUILD_ID && (descsz >= 4 && descsz <= 20)) {
513                 uint8_t desc[20];
514                 const char *btype;
515                 uint32_t i;
516                 *flags |= FLAGS_DID_BUILD_ID;
517                 switch (descsz) {
518                 case 8:
519                     btype = "xxHash";
520                     break;
521                 case 16:
522                     btype = "md5/uuid";
523                     break;
524                 case 20:
525                     btype = "sha1";
526                     break;
527                 default:
528                     btype = "unknown";
529                     break;
530                 }
531                 if (file_printf(ms, ", BuildID[%s]=", btype) == -1)
532                         return 1;
533                 (void)memcpy(desc, &nbuf[doff], descsz);
534                 for (i = 0; i < descsz; i++)
535                     if (file_printf(ms, "%02x", desc[i]) == -1)
536                         return 1;
537                 return 1;
538         }
539         return 0;
540 }
541
542 private int
543 do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
544     int swap, uint32_t namesz, uint32_t descsz,
545     size_t noff, size_t doff, int *flags)
546 {
547         if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 &&
548             type == NT_GNU_VERSION && descsz == 2) {
549             *flags |= FLAGS_DID_OS_NOTE;
550             file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]);
551             return 1;
552         }
553
554         if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
555             type == NT_GNU_VERSION && descsz == 16) {
556                 uint32_t desc[4];
557                 (void)memcpy(desc, &nbuf[doff], sizeof(desc));
558
559                 *flags |= FLAGS_DID_OS_NOTE;
560                 if (file_printf(ms, ", for GNU/") == -1)
561                         return 1;
562                 switch (elf_getu32(swap, desc[0])) {
563                 case GNU_OS_LINUX:
564                         if (file_printf(ms, "Linux") == -1)
565                                 return 1;
566                         break;
567                 case GNU_OS_HURD:
568                         if (file_printf(ms, "Hurd") == -1)
569                                 return 1;
570                         break;
571                 case GNU_OS_SOLARIS:
572                         if (file_printf(ms, "Solaris") == -1)
573                                 return 1;
574                         break;
575                 case GNU_OS_KFREEBSD:
576                         if (file_printf(ms, "kFreeBSD") == -1)
577                                 return 1;
578                         break;
579                 case GNU_OS_KNETBSD:
580                         if (file_printf(ms, "kNetBSD") == -1)
581                                 return 1;
582                         break;
583                 default:
584                         if (file_printf(ms, "<unknown>") == -1)
585                                 return 1; 
586                 }
587                 if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
588                     elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1)
589                         return 1;
590                 return 1;
591         }
592
593         if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
594                 if (type == NT_NETBSD_VERSION && descsz == 4) {
595                         *flags |= FLAGS_DID_OS_NOTE;
596                         do_note_netbsd_version(ms, swap, &nbuf[doff]);
597                         return 1;
598                 }
599         }
600
601         if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) {
602                 if (type == NT_FREEBSD_VERSION && descsz == 4) {
603                         *flags |= FLAGS_DID_OS_NOTE;
604                         do_note_freebsd_version(ms, swap, &nbuf[doff]);
605                         return 1;
606                 }
607         }
608
609         if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
610             type == NT_OPENBSD_VERSION && descsz == 4) {
611                 *flags |= FLAGS_DID_OS_NOTE;
612                 if (file_printf(ms, ", for OpenBSD") == -1)
613                         return 1;
614                 /* Content of note is always 0 */
615                 return 1;
616         }
617
618         if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
619             type == NT_DRAGONFLY_VERSION && descsz == 4) {
620                 uint32_t desc;
621                 *flags |= FLAGS_DID_OS_NOTE;
622                 if (file_printf(ms, ", for DragonFly") == -1)
623                         return 1;
624                 (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
625                 desc = elf_getu32(swap, desc);
626                 if (file_printf(ms, " %d.%d.%d", desc / 100000,
627                     desc / 10000 % 10, desc % 10000) == -1)
628                         return 1;
629                 return 1;
630         }
631         return 0;
632 }
633
634 private int
635 do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
636     int swap, uint32_t namesz, uint32_t descsz,
637     size_t noff, size_t doff, int *flags)
638 {
639         if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 &&
640             type == NT_NETBSD_PAX && descsz == 4) {
641                 static const char *pax[] = {
642                     "+mprotect",
643                     "-mprotect",
644                     "+segvguard",
645                     "-segvguard",
646                     "+ASLR",
647                     "-ASLR",
648                 };
649                 uint32_t desc;
650                 size_t i;
651                 int did = 0;
652
653                 *flags |= FLAGS_DID_NETBSD_PAX;
654                 (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
655                 desc = elf_getu32(swap, desc);
656
657                 if (desc && file_printf(ms, ", PaX: ") == -1)
658                         return 1;
659
660                 for (i = 0; i < __arraycount(pax); i++) {
661                         if (((1 << (int)i) & desc) == 0)
662                                 continue;
663                         if (file_printf(ms, "%s%s", did++ ? "," : "",
664                             pax[i]) == -1)
665                                 return 1;
666                 }
667                 return 1;
668         }
669         return 0;
670 }
671
672 private int
673 do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
674     int swap, uint32_t namesz, uint32_t descsz,
675     size_t noff, size_t doff, int *flags, size_t size, int clazz)
676 {
677 #ifdef ELFCORE
678         int os_style = -1;
679         /*
680          * Sigh.  The 2.0.36 kernel in Debian 2.1, at
681          * least, doesn't correctly implement name
682          * sections, in core dumps, as specified by
683          * the "Program Linking" section of "UNIX(R) System
684          * V Release 4 Programmer's Guide: ANSI C and
685          * Programming Support Tools", because my copy
686          * clearly says "The first 'namesz' bytes in 'name'
687          * contain a *null-terminated* [emphasis mine]
688          * character representation of the entry's owner
689          * or originator", but the 2.0.36 kernel code
690          * doesn't include the terminating null in the
691          * name....
692          */
693         if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) ||
694             (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) {
695                 os_style = OS_STYLE_SVR4;
696         } 
697
698         if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) {
699                 os_style = OS_STYLE_FREEBSD;
700         }
701
702         if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11)
703             == 0)) {
704                 os_style = OS_STYLE_NETBSD;
705         }
706
707         if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
708                 if (file_printf(ms, ", %s-style", os_style_names[os_style])
709                     == -1)
710                         return 1;
711                 *flags |= FLAGS_DID_CORE_STYLE;
712         }
713
714         switch (os_style) {
715         case OS_STYLE_NETBSD:
716                 if (type == NT_NETBSD_CORE_PROCINFO) {
717                         char sbuf[512];
718                         uint32_t signo;
719                         /*
720                          * Extract the program name.  It is at
721                          * offset 0x7c, and is up to 32-bytes,
722                          * including the terminating NUL.
723                          */
724                         if (file_printf(ms, ", from '%.31s'",
725                             file_printable(sbuf, sizeof(sbuf),
726                             (const char *)&nbuf[doff + 0x7c])) == -1)
727                                 return 1;
728                         
729                         /*
730                          * Extract the signal number.  It is at
731                          * offset 0x08.
732                          */
733                         (void)memcpy(&signo, &nbuf[doff + 0x08],
734                             sizeof(signo));
735                         if (file_printf(ms, " (signal %u)",
736                             elf_getu32(swap, signo)) == -1)
737                                 return 1;
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, 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 (type != NT_AUXV || (*flags & FLAGS_IS_CORE) == 0)
928                 return 0;
929
930         *flags |= FLAGS_DID_AUXV;
931
932         nval = 0;
933         for (size_t off = 0; off + elsize <= descsz; off += elsize) {
934                 (void)memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof);
935                 /* Limit processing to 50 vector entries to prevent DoS */
936                 if (nval++ >= 50) {
937                         file_error(ms, 0, "Too many ELF Auxv elements");
938                         return 1;
939                 }
940
941                 switch(xauxv_type) {
942                 case AT_LINUX_EXECFN:
943                         is_string = 1;
944                         tag = "execfn";
945                         break;
946                 case AT_LINUX_PLATFORM:
947                         is_string = 1;
948                         tag = "platform";
949                         break;
950                 case AT_LINUX_UID:
951                         is_string = 0;
952                         tag = "real uid";
953                         break;
954                 case AT_LINUX_GID:
955                         is_string = 0;
956                         tag = "real gid";
957                         break;
958                 case AT_LINUX_EUID:
959                         is_string = 0;
960                         tag = "effective uid";
961                         break;
962                 case AT_LINUX_EGID:
963                         is_string = 0;
964                         tag = "effective gid";
965                         break;
966                 default:
967                         is_string = 0;
968                         tag = NULL;
969                         break;
970                 }
971
972                 if (tag == NULL)
973                         continue;
974
975                 if (is_string) {
976                         char buf[256];
977                         ssize_t buflen;
978                         buflen = get_string_on_virtaddr(ms, swap, clazz, fd,
979                             ph_off, ph_num, fsize, xauxv_val, buf, sizeof(buf));
980
981                         if (buflen == 0)
982                                 continue;
983                         
984                         if (file_printf(ms, ", %s: '%s'", tag, buf) == -1)
985                                 return 0;
986                 } else {
987                         if (file_printf(ms, ", %s: %d", tag, (int) xauxv_val)
988                             == -1)
989                                 return 0;
990                 }
991         }
992         return 1;
993 #else
994         return 0;
995 #endif
996 }
997
998 private size_t
999 donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
1000     int clazz, int swap, size_t align, int *flags, uint16_t *notecount,
1001     int fd, off_t ph_off, int ph_num, off_t fsize)
1002 {
1003         Elf32_Nhdr nh32;
1004         Elf64_Nhdr nh64;
1005         size_t noff, doff;
1006         uint32_t namesz, descsz;
1007         unsigned char *nbuf = CAST(unsigned char *, vbuf);
1008
1009         if (*notecount == 0)
1010                 return 0;
1011         --*notecount;
1012
1013         if (xnh_sizeof + offset > size) {
1014                 /*
1015                  * We're out of note headers.
1016                  */
1017                 return xnh_sizeof + offset;
1018         }
1019
1020         (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
1021         offset += xnh_sizeof;
1022
1023         namesz = xnh_namesz;
1024         descsz = xnh_descsz;
1025
1026         if ((namesz == 0) && (descsz == 0)) {
1027                 /*
1028                  * We're out of note headers.
1029                  */
1030                 return (offset >= size) ? offset : size;
1031         }
1032
1033         if (namesz & 0x80000000) {
1034             (void)file_printf(ms, ", bad note name size 0x%lx",
1035                 (unsigned long)namesz);
1036             return 0;
1037         }
1038
1039         if (descsz & 0x80000000) {
1040             (void)file_printf(ms, ", bad note description size 0x%lx",
1041                 (unsigned long)descsz);
1042             return 0;
1043         }
1044
1045         noff = offset;
1046         doff = ELF_ALIGN(offset + namesz);
1047
1048         if (offset + namesz > size) {
1049                 /*
1050                  * We're past the end of the buffer.
1051                  */
1052                 return doff;
1053         }
1054
1055         offset = ELF_ALIGN(doff + descsz);
1056         if (doff + descsz > size) {
1057                 /*
1058                  * We're past the end of the buffer.
1059                  */
1060                 return (offset >= size) ? offset : size;
1061         }
1062
1063
1064         if ((*flags & FLAGS_DID_OS_NOTE) == 0) {
1065                 if (do_os_note(ms, nbuf, xnh_type, swap,
1066                     namesz, descsz, noff, doff, flags))
1067                         return offset;
1068         }
1069
1070         if ((*flags & FLAGS_DID_BUILD_ID) == 0) {
1071                 if (do_bid_note(ms, nbuf, xnh_type, swap,
1072                     namesz, descsz, noff, doff, flags))
1073                         return offset;
1074         }
1075                 
1076         if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) {
1077                 if (do_pax_note(ms, nbuf, xnh_type, swap,
1078                     namesz, descsz, noff, doff, flags))
1079                         return offset;
1080         }
1081
1082         if ((*flags & FLAGS_DID_CORE) == 0) {
1083                 if (do_core_note(ms, nbuf, xnh_type, swap,
1084                     namesz, descsz, noff, doff, flags, size, clazz))
1085                         return offset;
1086         }
1087
1088         if ((*flags & FLAGS_DID_AUXV) == 0) {
1089                 if (do_auxv_note(ms, nbuf, xnh_type, swap,
1090                         namesz, descsz, noff, doff, flags, size, clazz,
1091                         fd, ph_off, ph_num, fsize))
1092                         return offset;
1093         }
1094
1095         if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
1096                 if (descsz > 100)
1097                         descsz = 100;
1098                 switch (xnh_type) {
1099                 case NT_NETBSD_VERSION:
1100                         return offset;
1101                 case NT_NETBSD_MARCH:
1102                         if (*flags & FLAGS_DID_NETBSD_MARCH)
1103                                 return offset;
1104                         *flags |= FLAGS_DID_NETBSD_MARCH;
1105                         if (file_printf(ms, ", compiled for: %.*s",
1106                             (int)descsz, (const char *)&nbuf[doff]) == -1)
1107                                 return offset;
1108                         break;
1109                 case NT_NETBSD_CMODEL:
1110                         if (*flags & FLAGS_DID_NETBSD_CMODEL)
1111                                 return offset;
1112                         *flags |= FLAGS_DID_NETBSD_CMODEL;
1113                         if (file_printf(ms, ", compiler model: %.*s",
1114                             (int)descsz, (const char *)&nbuf[doff]) == -1)
1115                                 return offset;
1116                         break;
1117                 default:
1118                         if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
1119                                 return offset;
1120                         *flags |= FLAGS_DID_NETBSD_UNKNOWN;
1121                         if (file_printf(ms, ", note=%u", xnh_type) == -1)
1122                                 return offset;
1123                         break;
1124                 }
1125                 return offset;
1126         }
1127
1128         return offset;
1129 }
1130
1131 /* SunOS 5.x hardware capability descriptions */
1132 typedef struct cap_desc {
1133         uint64_t cd_mask;
1134         const char *cd_name;
1135 } cap_desc_t;
1136
1137 static const cap_desc_t cap_desc_sparc[] = {
1138         { AV_SPARC_MUL32,               "MUL32" },
1139         { AV_SPARC_DIV32,               "DIV32" },
1140         { AV_SPARC_FSMULD,              "FSMULD" },
1141         { AV_SPARC_V8PLUS,              "V8PLUS" },
1142         { AV_SPARC_POPC,                "POPC" },
1143         { AV_SPARC_VIS,                 "VIS" },
1144         { AV_SPARC_VIS2,                "VIS2" },
1145         { AV_SPARC_ASI_BLK_INIT,        "ASI_BLK_INIT" },
1146         { AV_SPARC_FMAF,                "FMAF" },
1147         { AV_SPARC_FJFMAU,              "FJFMAU" },
1148         { AV_SPARC_IMA,                 "IMA" },
1149         { 0, NULL }
1150 };
1151
1152 static const cap_desc_t cap_desc_386[] = {
1153         { AV_386_FPU,                   "FPU" },
1154         { AV_386_TSC,                   "TSC" },
1155         { AV_386_CX8,                   "CX8" },
1156         { AV_386_SEP,                   "SEP" },
1157         { AV_386_AMD_SYSC,              "AMD_SYSC" },
1158         { AV_386_CMOV,                  "CMOV" },
1159         { AV_386_MMX,                   "MMX" },
1160         { AV_386_AMD_MMX,               "AMD_MMX" },
1161         { AV_386_AMD_3DNow,             "AMD_3DNow" },
1162         { AV_386_AMD_3DNowx,            "AMD_3DNowx" },
1163         { AV_386_FXSR,                  "FXSR" },
1164         { AV_386_SSE,                   "SSE" },
1165         { AV_386_SSE2,                  "SSE2" },
1166         { AV_386_PAUSE,                 "PAUSE" },
1167         { AV_386_SSE3,                  "SSE3" },
1168         { AV_386_MON,                   "MON" },
1169         { AV_386_CX16,                  "CX16" },
1170         { AV_386_AHF,                   "AHF" },
1171         { AV_386_TSCP,                  "TSCP" },
1172         { AV_386_AMD_SSE4A,             "AMD_SSE4A" },
1173         { AV_386_POPCNT,                "POPCNT" },
1174         { AV_386_AMD_LZCNT,             "AMD_LZCNT" },
1175         { AV_386_SSSE3,                 "SSSE3" },
1176         { AV_386_SSE4_1,                "SSE4.1" },
1177         { AV_386_SSE4_2,                "SSE4.2" },
1178         { 0, NULL }
1179 };
1180
1181 private int
1182 doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
1183     size_t size, off_t fsize, int mach, int strtab, int *flags,
1184     uint16_t *notecount)
1185 {
1186         Elf32_Shdr sh32;
1187         Elf64_Shdr sh64;
1188         int stripped = 1;
1189         size_t nbadcap = 0;
1190         void *nbuf;
1191         off_t noff, coff, name_off;
1192         uint64_t cap_hw1 = 0;   /* SunOS 5.x hardware capabilites */
1193         uint64_t cap_sf1 = 0;   /* SunOS 5.x software capabilites */
1194         char name[50];
1195         ssize_t namesize;
1196
1197         if (size != xsh_sizeof) {
1198                 if (file_printf(ms, ", corrupted section header size") == -1)
1199                         return -1;
1200                 return 0;
1201         }
1202
1203         /* Read offset of name section to be able to read section names later */
1204         if (pread(fd, xsh_addr, xsh_sizeof, CAST(off_t, (off + size * strtab)))
1205             < (ssize_t)xsh_sizeof) {
1206                 file_badread(ms);
1207                 return -1;
1208         }
1209         name_off = xsh_offset;
1210
1211         for ( ; num; num--) {
1212                 /* Read the name of this section. */
1213                 if ((namesize = pread(fd, name, sizeof(name) - 1, name_off + xsh_name)) == -1) {
1214                         file_badread(ms);
1215                         return -1;
1216                 }
1217                 name[namesize] = '\0';
1218                 if (strcmp(name, ".debug_info") == 0)
1219                         stripped = 0;
1220
1221                 if (pread(fd, xsh_addr, xsh_sizeof, off) < (ssize_t)xsh_sizeof) {
1222                         file_badread(ms);
1223                         return -1;
1224                 }
1225                 off += size;
1226
1227                 /* Things we can determine before we seek */
1228                 switch (xsh_type) {
1229                 case SHT_SYMTAB:
1230 #if 0
1231                 case SHT_DYNSYM:
1232 #endif
1233                         stripped = 0;
1234                         break;
1235                 default:
1236                         if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) {
1237                                 /* Perhaps warn here */
1238                                 continue;
1239                         }
1240                         break;
1241                 }
1242
1243
1244                 /* Things we can determine when we seek */
1245                 switch (xsh_type) {
1246                 case SHT_NOTE:
1247                         if ((uintmax_t)(xsh_size + xsh_offset) >
1248                             (uintmax_t)fsize) {
1249                                 if (file_printf(ms,
1250                                     ", note offset/size 0x%" INTMAX_T_FORMAT
1251                                     "x+0x%" INTMAX_T_FORMAT "x exceeds"
1252                                     " file size 0x%" INTMAX_T_FORMAT "x",
1253                                     (uintmax_t)xsh_offset, (uintmax_t)xsh_size,
1254                                     (uintmax_t)fsize) == -1)
1255                                         return -1;
1256                                 return 0; 
1257                         }
1258                         if ((nbuf = malloc(xsh_size)) == NULL) {
1259                                 file_error(ms, errno, "Cannot allocate memory"
1260                                     " for note");
1261                                 return -1;
1262                         }
1263                         if (pread(fd, nbuf, xsh_size, xsh_offset) <
1264                             (ssize_t)xsh_size) {
1265                                 file_badread(ms);
1266                                 free(nbuf);
1267                                 return -1;
1268                         }
1269
1270                         noff = 0;
1271                         for (;;) {
1272                                 if (noff >= (off_t)xsh_size)
1273                                         break;
1274                                 noff = donote(ms, nbuf, (size_t)noff,
1275                                     xsh_size, clazz, swap, 4, flags, notecount,
1276                                     fd, 0, 0, 0);
1277                                 if (noff == 0)
1278                                         break;
1279                         }
1280                         free(nbuf);
1281                         break;
1282                 case SHT_SUNW_cap:
1283                         switch (mach) {
1284                         case EM_SPARC:
1285                         case EM_SPARCV9:
1286                         case EM_IA_64:
1287                         case EM_386:
1288                         case EM_AMD64:
1289                                 break;
1290                         default:
1291                                 goto skip;
1292                         }
1293
1294                         if (nbadcap > 5)
1295                                 break;
1296                         if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) {
1297                                 file_badseek(ms);
1298                                 return -1;
1299                         }
1300                         coff = 0;
1301                         for (;;) {
1302                                 Elf32_Cap cap32;
1303                                 Elf64_Cap cap64;
1304                                 char cbuf[/*CONSTCOND*/
1305                                     MAX(sizeof cap32, sizeof cap64)];
1306                                 if ((coff += xcap_sizeof) > (off_t)xsh_size)
1307                                         break;
1308                                 if (read(fd, cbuf, (size_t)xcap_sizeof) !=
1309                                     (ssize_t)xcap_sizeof) {
1310                                         file_badread(ms);
1311                                         return -1;
1312                                 }
1313                                 if (cbuf[0] == 'A') {
1314 #ifdef notyet
1315                                         char *p = cbuf + 1;
1316                                         uint32_t len, tag;
1317                                         memcpy(&len, p, sizeof(len));
1318                                         p += 4;
1319                                         len = getu32(swap, len);
1320                                         if (memcmp("gnu", p, 3) != 0) {
1321                                             if (file_printf(ms,
1322                                                 ", unknown capability %.3s", p)
1323                                                 == -1)
1324                                                 return -1;
1325                                             break;
1326                                         }
1327                                         p += strlen(p) + 1;
1328                                         tag = *p++;
1329                                         memcpy(&len, p, sizeof(len));
1330                                         p += 4;
1331                                         len = getu32(swap, len);
1332                                         if (tag != 1) {
1333                                             if (file_printf(ms, ", unknown gnu"
1334                                                 " capability tag %d", tag)
1335                                                 == -1)
1336                                                 return -1;
1337                                             break;
1338                                         }
1339                                         // gnu attributes 
1340 #endif
1341                                         break;
1342                                 }
1343                                 (void)memcpy(xcap_addr, cbuf, xcap_sizeof);
1344                                 switch (xcap_tag) {
1345                                 case CA_SUNW_NULL:
1346                                         break;
1347                                 case CA_SUNW_HW_1:
1348                                         cap_hw1 |= xcap_val;
1349                                         break;
1350                                 case CA_SUNW_SF_1:
1351                                         cap_sf1 |= xcap_val;
1352                                         break;
1353                                 default:
1354                                         if (file_printf(ms,
1355                                             ", with unknown capability "
1356                                             "0x%" INT64_T_FORMAT "x = 0x%"
1357                                             INT64_T_FORMAT "x",
1358                                             (unsigned long long)xcap_tag,
1359                                             (unsigned long long)xcap_val) == -1)
1360                                                 return -1;
1361                                         if (nbadcap++ > 2)
1362                                                 coff = xsh_size;
1363                                         break;
1364                                 }
1365                         }
1366                         /*FALLTHROUGH*/
1367                 skip:
1368                 default:
1369                         break;
1370                 }
1371         }
1372
1373         if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
1374                 return -1;
1375         if (cap_hw1) {
1376                 const cap_desc_t *cdp;
1377                 switch (mach) {
1378                 case EM_SPARC:
1379                 case EM_SPARC32PLUS:
1380                 case EM_SPARCV9:
1381                         cdp = cap_desc_sparc;
1382                         break;
1383                 case EM_386:
1384                 case EM_IA_64:
1385                 case EM_AMD64:
1386                         cdp = cap_desc_386;
1387                         break;
1388                 default:
1389                         cdp = NULL;
1390                         break;
1391                 }
1392                 if (file_printf(ms, ", uses") == -1)
1393                         return -1;
1394                 if (cdp) {
1395                         while (cdp->cd_name) {
1396                                 if (cap_hw1 & cdp->cd_mask) {
1397                                         if (file_printf(ms,
1398                                             " %s", cdp->cd_name) == -1)
1399                                                 return -1;
1400                                         cap_hw1 &= ~cdp->cd_mask;
1401                                 }
1402                                 ++cdp;
1403                         }
1404                         if (cap_hw1)
1405                                 if (file_printf(ms,
1406                                     " unknown hardware capability 0x%"
1407                                     INT64_T_FORMAT "x",
1408                                     (unsigned long long)cap_hw1) == -1)
1409                                         return -1;
1410                 } else {
1411                         if (file_printf(ms,
1412                             " hardware capability 0x%" INT64_T_FORMAT "x",
1413                             (unsigned long long)cap_hw1) == -1)
1414                                 return -1;
1415                 }
1416         }
1417         if (cap_sf1) {
1418                 if (cap_sf1 & SF1_SUNW_FPUSED) {
1419                         if (file_printf(ms,
1420                             (cap_sf1 & SF1_SUNW_FPKNWN)
1421                             ? ", uses frame pointer"
1422                             : ", not known to use frame pointer") == -1)
1423                                 return -1;
1424                 }
1425                 cap_sf1 &= ~SF1_SUNW_MASK;
1426                 if (cap_sf1)
1427                         if (file_printf(ms,
1428                             ", with unknown software capability 0x%"
1429                             INT64_T_FORMAT "x",
1430                             (unsigned long long)cap_sf1) == -1)
1431                                 return -1;
1432         }
1433         return 0;
1434 }
1435
1436 /*
1437  * Look through the program headers of an executable image, searching
1438  * for a PT_INTERP section; if one is found, it's dynamically linked,
1439  * otherwise it's statically linked.
1440  */
1441 private int
1442 dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
1443     int num, size_t size, off_t fsize, int sh_num, int *flags,
1444     uint16_t *notecount)
1445 {
1446         Elf32_Phdr ph32;
1447         Elf64_Phdr ph64;
1448         const char *linking_style = "statically";
1449         const char *interp = "";
1450         unsigned char nbuf[BUFSIZ];
1451         char ibuf[BUFSIZ];
1452         ssize_t bufsize;
1453         size_t offset, align, len;
1454         
1455         if (size != xph_sizeof) {
1456                 if (file_printf(ms, ", corrupted program header size") == -1)
1457                         return -1;
1458                 return 0;
1459         }
1460
1461         for ( ; num; num--) {
1462                 if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
1463                         file_badread(ms);
1464                         return -1;
1465                 }
1466
1467                 off += size;
1468                 bufsize = 0;
1469                 align = 4;
1470
1471                 /* Things we can determine before we seek */
1472                 switch (xph_type) {
1473                 case PT_DYNAMIC:
1474                         linking_style = "dynamically";
1475                         break;
1476                 case PT_NOTE:
1477                         if (sh_num)     /* Did this through section headers */
1478                                 continue;
1479                         if (((align = xph_align) & 0x80000000UL) != 0 ||
1480                             align < 4) {
1481                                 if (file_printf(ms, 
1482                                     ", invalid note alignment 0x%lx",
1483                                     (unsigned long)align) == -1)
1484                                         return -1;
1485                                 align = 4;
1486                         }
1487                         /*FALLTHROUGH*/
1488                 case PT_INTERP:
1489                         len = xph_filesz < sizeof(nbuf) ? xph_filesz
1490                             : sizeof(nbuf);
1491                         bufsize = pread(fd, nbuf, len, xph_offset);
1492                         if (bufsize == -1) {
1493                                 file_badread(ms);
1494                                 return -1;
1495                         }
1496                         break;
1497                 default:
1498                         if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
1499                                 /* Maybe warn here? */
1500                                 continue;
1501                         }
1502                         break;
1503                 }
1504
1505                 /* Things we can determine when we seek */
1506                 switch (xph_type) {
1507                 case PT_INTERP:
1508                         if (bufsize && nbuf[0]) {
1509                                 nbuf[bufsize - 1] = '\0';
1510                                 interp = (const char *)nbuf;
1511                         } else
1512                                 interp = "*empty*";
1513                         break;
1514                 case PT_NOTE:
1515                         /*
1516                          * This is a PT_NOTE section; loop through all the notes
1517                          * in the section.
1518                          */
1519                         offset = 0;
1520                         for (;;) {
1521                                 if (offset >= (size_t)bufsize)
1522                                         break;
1523                                 offset = donote(ms, nbuf, offset,
1524                                     (size_t)bufsize, clazz, swap, align,
1525                                     flags, notecount, fd, 0, 0, 0);
1526                                 if (offset == 0)
1527                                         break;
1528                         }
1529                         break;
1530                 default:
1531                         break;
1532                 }
1533         }
1534         if (file_printf(ms, ", %s linked", linking_style)
1535             == -1)
1536                 return -1;
1537         if (interp[0])
1538                 if (file_printf(ms, ", interpreter %s",
1539                     file_printable(ibuf, sizeof(ibuf), interp)) == -1)
1540                         return -1;
1541         return 0;
1542 }
1543
1544
1545 protected int
1546 file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
1547     size_t nbytes)
1548 {
1549         union {
1550                 int32_t l;
1551                 char c[sizeof (int32_t)];
1552         } u;
1553         int clazz;
1554         int swap;
1555         struct stat st;
1556         off_t fsize;
1557         int flags = 0;
1558         Elf32_Ehdr elf32hdr;
1559         Elf64_Ehdr elf64hdr;
1560         uint16_t type, phnum, shnum, notecount;
1561
1562         if (ms->flags & (MAGIC_MIME|MAGIC_APPLE|MAGIC_EXTENSION))
1563                 return 0;
1564         /*
1565          * ELF executables have multiple section headers in arbitrary
1566          * file locations and thus file(1) cannot determine it from easily.
1567          * Instead we traverse thru all section headers until a symbol table
1568          * one is found or else the binary is stripped.
1569          * Return immediately if it's not ELF (so we avoid pipe2file unless needed).
1570          */
1571         if (buf[EI_MAG0] != ELFMAG0
1572             || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
1573             || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
1574                 return 0;
1575
1576         /*
1577          * If we cannot seek, it must be a pipe, socket or fifo.
1578          */
1579         if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE))
1580                 fd = file_pipe2file(ms, fd, buf, nbytes);
1581
1582         if (fstat(fd, &st) == -1) {
1583                 file_badread(ms);
1584                 return -1;
1585         }
1586         if (S_ISREG(st.st_mode) || st.st_size != 0)
1587                 fsize = st.st_size;
1588         else
1589                 fsize = SIZE_UNKNOWN;
1590
1591         clazz = buf[EI_CLASS];
1592
1593         switch (clazz) {
1594         case ELFCLASS32:
1595 #undef elf_getu
1596 #define elf_getu(a, b)  elf_getu32(a, b)
1597 #undef elfhdr
1598 #define elfhdr elf32hdr
1599 #include "elfclass.h"
1600         case ELFCLASS64:
1601 #undef elf_getu
1602 #define elf_getu(a, b)  elf_getu64(a, b)
1603 #undef elfhdr
1604 #define elfhdr elf64hdr
1605 #include "elfclass.h"
1606         default:
1607             if (file_printf(ms, ", unknown class %d", clazz) == -1)
1608                     return -1;
1609             break;
1610         }
1611         return 0;
1612 }
1613 #endif