Coverage Report

Created: 2026-02-14 06:25

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