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