readelf.c revision 309847
1133359Sobrien/* 2133359Sobrien * Copyright (c) Christos Zoulas 2003. 3133359Sobrien * All Rights Reserved. 4133359Sobrien * 5133359Sobrien * Redistribution and use in source and binary forms, with or without 6133359Sobrien * modification, are permitted provided that the following conditions 7133359Sobrien * are met: 8133359Sobrien * 1. Redistributions of source code must retain the above copyright 9133359Sobrien * notice immediately at the beginning of the file, without modification, 10133359Sobrien * this list of conditions, and the following disclaimer. 11133359Sobrien * 2. Redistributions in binary form must reproduce the above copyright 12133359Sobrien * notice, this list of conditions and the following disclaimer in the 13133359Sobrien * documentation and/or other materials provided with the distribution. 14133359Sobrien * 15133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18133359Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19133359Sobrien * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20133359Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21133359Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25133359Sobrien * SUCH DAMAGE. 26133359Sobrien */ 2768349Sobrien#include "file.h" 2868349Sobrien 29191736Sobrien#ifndef lint 30309847SdelphijFILE_RCSID("@(#)$File: readelf.c,v 1.128 2016/10/04 21:43:10 christos Exp $") 31191736Sobrien#endif 32191736Sobrien 3368349Sobrien#ifdef BUILTIN_ELF 3468349Sobrien#include <string.h> 3568349Sobrien#include <ctype.h> 3668349Sobrien#include <stdlib.h> 3768349Sobrien#ifdef HAVE_UNISTD_H 3868349Sobrien#include <unistd.h> 3968349Sobrien#endif 4068349Sobrien 4168349Sobrien#include "readelf.h" 42186690Sobrien#include "magic.h" 4368349Sobrien 4468349Sobrien#ifdef ELFCORE 45169942Sobrienprivate int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t, 46276577Sdelphij off_t, int *, uint16_t *); 4768349Sobrien#endif 48169942Sobrienprivate int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t, 49276577Sdelphij off_t, int, int *, uint16_t *); 50226048Sobrienprivate int doshn(struct magic_set *, int, int, int, off_t, int, size_t, 51276577Sdelphij off_t, int, int, int *, uint16_t *); 52186690Sobrienprivate size_t donote(struct magic_set *, void *, size_t, size_t, int, 53298192Sdelphij int, size_t, int *, uint16_t *, int, off_t, int, off_t); 5468349Sobrien 55133359Sobrien#define ELF_ALIGN(a) ((((a) + align - 1) / align) * align) 5668349Sobrien 57159764Sobrien#define isquote(c) (strchr("'\"`", (c)) != NULL) 58159764Sobrien 59133359Sobrienprivate uint16_t getu16(int, uint16_t); 60133359Sobrienprivate uint32_t getu32(int, uint32_t); 61133359Sobrienprivate uint64_t getu64(int, uint64_t); 62133359Sobrien 63275698Sdelphij#define MAX_PHNUM 128 64275698Sdelphij#define MAX_SHNUM 32768 65275698Sdelphij#define SIZE_UNKNOWN ((off_t)-1) 66275666Sdelphij 67275666Sdelphijprivate int 68275666Sdelphijtoomany(struct magic_set *ms, const char *name, uint16_t num) 69275666Sdelphij{ 70276577Sdelphij if (file_printf(ms, ", too many %s (%u)", name, num 71275666Sdelphij ) == -1) 72275666Sdelphij return -1; 73275666Sdelphij return 0; 74275666Sdelphij} 75275666Sdelphij 76133359Sobrienprivate uint16_t 77103373Sobriengetu16(int swap, uint16_t value) 7868349Sobrien{ 7968349Sobrien union { 8068349Sobrien uint16_t ui; 8168349Sobrien char c[2]; 8268349Sobrien } retval, tmpval; 8368349Sobrien 8468349Sobrien if (swap) { 8568349Sobrien tmpval.ui = value; 8668349Sobrien 8768349Sobrien retval.c[0] = tmpval.c[1]; 8868349Sobrien retval.c[1] = tmpval.c[0]; 8968349Sobrien 9068349Sobrien return retval.ui; 9168349Sobrien } else 9268349Sobrien return value; 9368349Sobrien} 9468349Sobrien 95133359Sobrienprivate uint32_t 96103373Sobriengetu32(int swap, uint32_t value) 9768349Sobrien{ 9868349Sobrien union { 9968349Sobrien uint32_t ui; 10068349Sobrien char c[4]; 10168349Sobrien } retval, tmpval; 10268349Sobrien 10368349Sobrien if (swap) { 10468349Sobrien tmpval.ui = value; 10568349Sobrien 10668349Sobrien retval.c[0] = tmpval.c[3]; 10768349Sobrien retval.c[1] = tmpval.c[2]; 10868349Sobrien retval.c[2] = tmpval.c[1]; 10968349Sobrien retval.c[3] = tmpval.c[0]; 11068349Sobrien 11168349Sobrien return retval.ui; 11268349Sobrien } else 11368349Sobrien return value; 11468349Sobrien} 11568349Sobrien 116133359Sobrienprivate uint64_t 117103373Sobriengetu64(int swap, uint64_t value) 11868349Sobrien{ 11968349Sobrien union { 12068349Sobrien uint64_t ui; 12168349Sobrien char c[8]; 12268349Sobrien } retval, tmpval; 12368349Sobrien 12468349Sobrien if (swap) { 12568349Sobrien tmpval.ui = value; 12668349Sobrien 12768349Sobrien retval.c[0] = tmpval.c[7]; 12868349Sobrien retval.c[1] = tmpval.c[6]; 12968349Sobrien retval.c[2] = tmpval.c[5]; 13068349Sobrien retval.c[3] = tmpval.c[4]; 13168349Sobrien retval.c[4] = tmpval.c[3]; 13268349Sobrien retval.c[5] = tmpval.c[2]; 13368349Sobrien retval.c[6] = tmpval.c[1]; 13468349Sobrien retval.c[7] = tmpval.c[0]; 13568349Sobrien 13668349Sobrien return retval.ui; 13768349Sobrien } else 13868349Sobrien return value; 13968349Sobrien} 14068349Sobrien 141186690Sobrien#define elf_getu16(swap, value) getu16(swap, value) 142186690Sobrien#define elf_getu32(swap, value) getu32(swap, value) 143267843Sdelphij#define elf_getu64(swap, value) getu64(swap, value) 144159764Sobrien 145186690Sobrien#define xsh_addr (clazz == ELFCLASS32 \ 146267843Sdelphij ? (void *)&sh32 \ 147267843Sdelphij : (void *)&sh64) 148186690Sobrien#define xsh_sizeof (clazz == ELFCLASS32 \ 149267843Sdelphij ? sizeof(sh32) \ 150267843Sdelphij : sizeof(sh64)) 151267843Sdelphij#define xsh_size (size_t)(clazz == ELFCLASS32 \ 152186690Sobrien ? elf_getu32(swap, sh32.sh_size) \ 153186690Sobrien : elf_getu64(swap, sh64.sh_size)) 154226048Sobrien#define xsh_offset (off_t)(clazz == ELFCLASS32 \ 155186690Sobrien ? elf_getu32(swap, sh32.sh_offset) \ 156186690Sobrien : elf_getu64(swap, sh64.sh_offset)) 157186690Sobrien#define xsh_type (clazz == ELFCLASS32 \ 158186690Sobrien ? elf_getu32(swap, sh32.sh_type) \ 159186690Sobrien : elf_getu32(swap, sh64.sh_type)) 160267843Sdelphij#define xsh_name (clazz == ELFCLASS32 \ 161267843Sdelphij ? elf_getu32(swap, sh32.sh_name) \ 162267843Sdelphij : elf_getu32(swap, sh64.sh_name)) 163186690Sobrien#define xph_addr (clazz == ELFCLASS32 \ 164186690Sobrien ? (void *) &ph32 \ 16568349Sobrien : (void *) &ph64) 166186690Sobrien#define xph_sizeof (clazz == ELFCLASS32 \ 167267843Sdelphij ? sizeof(ph32) \ 168267843Sdelphij : sizeof(ph64)) 169186690Sobrien#define xph_type (clazz == ELFCLASS32 \ 170186690Sobrien ? elf_getu32(swap, ph32.p_type) \ 171186690Sobrien : elf_getu32(swap, ph64.p_type)) 172186690Sobrien#define xph_offset (off_t)(clazz == ELFCLASS32 \ 173186690Sobrien ? elf_getu32(swap, ph32.p_offset) \ 174186690Sobrien : elf_getu64(swap, ph64.p_offset)) 175186690Sobrien#define xph_align (size_t)((clazz == ELFCLASS32 \ 176186690Sobrien ? (off_t) (ph32.p_align ? \ 177186690Sobrien elf_getu32(swap, ph32.p_align) : 4) \ 178186690Sobrien : (off_t) (ph64.p_align ? \ 179186690Sobrien elf_getu64(swap, ph64.p_align) : 4))) 180298192Sdelphij#define xph_vaddr (size_t)((clazz == ELFCLASS32 \ 181298192Sdelphij ? (off_t) (ph32.p_vaddr ? \ 182298192Sdelphij elf_getu32(swap, ph32.p_vaddr) : 4) \ 183298192Sdelphij : (off_t) (ph64.p_vaddr ? \ 184298192Sdelphij elf_getu64(swap, ph64.p_vaddr) : 4))) 185186690Sobrien#define xph_filesz (size_t)((clazz == ELFCLASS32 \ 186186690Sobrien ? elf_getu32(swap, ph32.p_filesz) \ 187186690Sobrien : elf_getu64(swap, ph64.p_filesz))) 188186690Sobrien#define xnh_addr (clazz == ELFCLASS32 \ 189267843Sdelphij ? (void *)&nh32 \ 190267843Sdelphij : (void *)&nh64) 191186690Sobrien#define xph_memsz (size_t)((clazz == ELFCLASS32 \ 192186690Sobrien ? elf_getu32(swap, ph32.p_memsz) \ 193186690Sobrien : elf_getu64(swap, ph64.p_memsz))) 194186690Sobrien#define xnh_sizeof (clazz == ELFCLASS32 \ 195298192Sdelphij ? sizeof(nh32) \ 196298192Sdelphij : sizeof(nh64)) 197186690Sobrien#define xnh_type (clazz == ELFCLASS32 \ 198186690Sobrien ? elf_getu32(swap, nh32.n_type) \ 199186690Sobrien : elf_getu32(swap, nh64.n_type)) 200186690Sobrien#define xnh_namesz (clazz == ELFCLASS32 \ 201186690Sobrien ? elf_getu32(swap, nh32.n_namesz) \ 202186690Sobrien : elf_getu32(swap, nh64.n_namesz)) 203186690Sobrien#define xnh_descsz (clazz == ELFCLASS32 \ 204186690Sobrien ? elf_getu32(swap, nh32.n_descsz) \ 205186690Sobrien : elf_getu32(swap, nh64.n_descsz)) 206186690Sobrien#define prpsoffsets(i) (clazz == ELFCLASS32 \ 207186690Sobrien ? prpsoffsets32[i] \ 20868349Sobrien : prpsoffsets64[i]) 209186690Sobrien#define xcap_addr (clazz == ELFCLASS32 \ 210267843Sdelphij ? (void *)&cap32 \ 211267843Sdelphij : (void *)&cap64) 212186690Sobrien#define xcap_sizeof (clazz == ELFCLASS32 \ 213186690Sobrien ? sizeof cap32 \ 214186690Sobrien : sizeof cap64) 215186690Sobrien#define xcap_tag (clazz == ELFCLASS32 \ 216186690Sobrien ? elf_getu32(swap, cap32.c_tag) \ 217186690Sobrien : elf_getu64(swap, cap64.c_tag)) 218186690Sobrien#define xcap_val (clazz == ELFCLASS32 \ 219186690Sobrien ? elf_getu32(swap, cap32.c_un.c_val) \ 220186690Sobrien : elf_getu64(swap, cap64.c_un.c_val)) 221298192Sdelphij#define xauxv_addr (clazz == ELFCLASS32 \ 222298192Sdelphij ? (void *)&auxv32 \ 223298192Sdelphij : (void *)&auxv64) 224298192Sdelphij#define xauxv_sizeof (clazz == ELFCLASS32 \ 225298192Sdelphij ? sizeof(auxv32) \ 226298192Sdelphij : sizeof(auxv64)) 227298192Sdelphij#define xauxv_type (clazz == ELFCLASS32 \ 228298192Sdelphij ? elf_getu32(swap, auxv32.a_type) \ 229298192Sdelphij : elf_getu64(swap, auxv64.a_type)) 230298192Sdelphij#define xauxv_val (clazz == ELFCLASS32 \ 231298192Sdelphij ? elf_getu32(swap, auxv32.a_v) \ 232298192Sdelphij : elf_getu64(swap, auxv64.a_v)) 23368349Sobrien 23468349Sobrien#ifdef ELFCORE 235186690Sobrien/* 236186690Sobrien * Try larger offsets first to avoid false matches 237186690Sobrien * from earlier data that happen to look like strings. 238186690Sobrien */ 239186690Sobrienstatic const size_t prpsoffsets32[] = { 240186690Sobrien#ifdef USE_NT_PSINFO 241186690Sobrien 104, /* SunOS 5.x (command line) */ 242186690Sobrien 88, /* SunOS 5.x (short name) */ 243186690Sobrien#endif /* USE_NT_PSINFO */ 244186690Sobrien 245186690Sobrien 100, /* SunOS 5.x (command line) */ 246186690Sobrien 84, /* SunOS 5.x (short name) */ 247186690Sobrien 248186690Sobrien 44, /* Linux (command line) */ 249186690Sobrien 28, /* Linux 2.0.36 (short name) */ 250186690Sobrien 25168349Sobrien 8, /* FreeBSD */ 25268349Sobrien}; 25368349Sobrien 254186690Sobrienstatic const size_t prpsoffsets64[] = { 255186690Sobrien#ifdef USE_NT_PSINFO 256186690Sobrien 152, /* SunOS 5.x (command line) */ 257186690Sobrien 136, /* SunOS 5.x (short name) */ 258186690Sobrien#endif /* USE_NT_PSINFO */ 259186690Sobrien 260186690Sobrien 136, /* SunOS 5.x, 64-bit (command line) */ 261186690Sobrien 120, /* SunOS 5.x, 64-bit (short name) */ 262186690Sobrien 263186690Sobrien 56, /* Linux (command line) */ 264186690Sobrien 40, /* Linux (tested on core from 2.4.x, short name) */ 265186690Sobrien 266159764Sobrien 16, /* FreeBSD, 64-bit */ 26768349Sobrien}; 26868349Sobrien 26968349Sobrien#define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0]) 27068349Sobrien#define NOFFSETS64 (sizeof prpsoffsets64 / sizeof prpsoffsets64[0]) 27168349Sobrien 272186690Sobrien#define NOFFSETS (clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64) 27368349Sobrien 27468349Sobrien/* 27568349Sobrien * Look through the program headers of an executable image, searching 27668349Sobrien * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or 27768349Sobrien * "FreeBSD"; if one is found, try looking in various places in its 27868349Sobrien * contents for a 16-character string containing only printable 27968349Sobrien * characters - if found, that string should be the name of the program 28068349Sobrien * that dropped core. Note: right after that 16-character string is, 28168349Sobrien * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and 28268349Sobrien * Linux, a longer string (80 characters, in 5.x, probably other 28368349Sobrien * SVR4-flavored systems, and Linux) containing the start of the 28468349Sobrien * command line for that program. 28568349Sobrien * 286186690Sobrien * SunOS 5.x core files contain two PT_NOTE sections, with the types 287186690Sobrien * NT_PRPSINFO (old) and NT_PSINFO (new). These structs contain the 288186690Sobrien * same info about the command name and command line, so it probably 289186690Sobrien * isn't worthwhile to look for NT_PSINFO, but the offsets are provided 290186690Sobrien * above (see USE_NT_PSINFO), in case we ever decide to do so. The 291186690Sobrien * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent; 292186690Sobrien * the SunOS 5.x file command relies on this (and prefers the latter). 293186690Sobrien * 29468349Sobrien * The signal number probably appears in a section of type NT_PRSTATUS, 29568349Sobrien * but that's also rather OS-dependent, in ways that are harder to 29668349Sobrien * dissect with heuristics, so I'm not bothering with the signal number. 29768349Sobrien * (I suppose the signal number could be of interest in situations where 29868349Sobrien * you don't have the binary of the program that dropped core; if you 29968349Sobrien * *do* have that binary, the debugger will probably tell you what 30068349Sobrien * signal it was.) 30168349Sobrien */ 302103373Sobrien 303103373Sobrien#define OS_STYLE_SVR4 0 304103373Sobrien#define OS_STYLE_FREEBSD 1 305103373Sobrien#define OS_STYLE_NETBSD 2 306103373Sobrien 307186690Sobrienprivate const char os_style_names[][8] = { 308103373Sobrien "SVR4", 309103373Sobrien "FreeBSD", 310103373Sobrien "NetBSD", 311103373Sobrien}; 312103373Sobrien 313276577Sdelphij#define FLAGS_DID_CORE 0x001 314276577Sdelphij#define FLAGS_DID_OS_NOTE 0x002 315276577Sdelphij#define FLAGS_DID_BUILD_ID 0x004 316276577Sdelphij#define FLAGS_DID_CORE_STYLE 0x008 317276577Sdelphij#define FLAGS_DID_NETBSD_PAX 0x010 318276577Sdelphij#define FLAGS_DID_NETBSD_MARCH 0x020 319276577Sdelphij#define FLAGS_DID_NETBSD_CMODEL 0x040 320276577Sdelphij#define FLAGS_DID_NETBSD_UNKNOWN 0x080 321276577Sdelphij#define FLAGS_IS_CORE 0x100 322298192Sdelphij#define FLAGS_DID_AUXV 0x200 323159764Sobrien 324133359Sobrienprivate int 325186690Sobriendophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 326276577Sdelphij int num, size_t size, off_t fsize, int *flags, uint16_t *notecount) 32768349Sobrien{ 32868349Sobrien Elf32_Phdr ph32; 32968349Sobrien Elf64_Phdr ph64; 330267843Sdelphij size_t offset, len; 331133359Sobrien unsigned char nbuf[BUFSIZ]; 332133359Sobrien ssize_t bufsize; 333298192Sdelphij off_t ph_off = off; 334298192Sdelphij int ph_num = num; 33568349Sobrien 336159764Sobrien if (size != xph_sizeof) { 337133359Sobrien if (file_printf(ms, ", corrupted program header size") == -1) 338133359Sobrien return -1; 339133359Sobrien return 0; 340133359Sobrien } 341159764Sobrien 34268349Sobrien /* 34368349Sobrien * Loop through all the program headers. 34468349Sobrien */ 34568349Sobrien for ( ; num; num--) { 346276577Sdelphij if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) { 347133359Sobrien file_badread(ms); 348133359Sobrien return -1; 349133359Sobrien } 350226048Sobrien off += size; 351226048Sobrien 352275698Sdelphij if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 353226048Sobrien /* Perhaps warn here */ 354169942Sobrien continue; 355169942Sobrien } 356169942Sobrien 357159764Sobrien if (xph_type != PT_NOTE) 35868349Sobrien continue; 35968349Sobrien 36068349Sobrien /* 36168349Sobrien * This is a PT_NOTE section; loop through all the notes 36268349Sobrien * in the section. 36368349Sobrien */ 364267843Sdelphij len = xph_filesz < sizeof(nbuf) ? xph_filesz : sizeof(nbuf); 365267843Sdelphij if ((bufsize = pread(fd, nbuf, len, xph_offset)) == -1) { 366133359Sobrien file_badread(ms); 367133359Sobrien return -1; 368133359Sobrien } 36968349Sobrien offset = 0; 37068349Sobrien for (;;) { 371133359Sobrien if (offset >= (size_t)bufsize) 37268349Sobrien break; 373133359Sobrien offset = donote(ms, nbuf, offset, (size_t)bufsize, 374298192Sdelphij clazz, swap, 4, flags, notecount, fd, ph_off, 375298192Sdelphij ph_num, fsize); 376133359Sobrien if (offset == 0) 377133359Sobrien break; 37868349Sobrien 379133359Sobrien } 380133359Sobrien } 381133359Sobrien return 0; 382133359Sobrien} 383133359Sobrien#endif 384133359Sobrien 385267843Sdelphijstatic void 386267843Sdelphijdo_note_netbsd_version(struct magic_set *ms, int swap, void *v) 387267843Sdelphij{ 388267843Sdelphij uint32_t desc; 389267843Sdelphij (void)memcpy(&desc, v, sizeof(desc)); 390267843Sdelphij desc = elf_getu32(swap, desc); 391267843Sdelphij 392267843Sdelphij if (file_printf(ms, ", for NetBSD") == -1) 393267843Sdelphij return; 394267843Sdelphij /* 395267843Sdelphij * The version number used to be stuck as 199905, and was thus 396267843Sdelphij * basically content-free. Newer versions of NetBSD have fixed 397267843Sdelphij * this and now use the encoding of __NetBSD_Version__: 398267843Sdelphij * 399267843Sdelphij * MMmmrrpp00 400267843Sdelphij * 401267843Sdelphij * M = major version 402267843Sdelphij * m = minor version 403267843Sdelphij * r = release ["",A-Z,Z[A-Z] but numeric] 404267843Sdelphij * p = patchlevel 405267843Sdelphij */ 406267843Sdelphij if (desc > 100000000U) { 407267843Sdelphij uint32_t ver_patch = (desc / 100) % 100; 408267843Sdelphij uint32_t ver_rel = (desc / 10000) % 100; 409267843Sdelphij uint32_t ver_min = (desc / 1000000) % 100; 410267843Sdelphij uint32_t ver_maj = desc / 100000000; 411267843Sdelphij 412267843Sdelphij if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) 413267843Sdelphij return; 414267843Sdelphij if (ver_rel == 0 && ver_patch != 0) { 415267843Sdelphij if (file_printf(ms, ".%u", ver_patch) == -1) 416267843Sdelphij return; 417267843Sdelphij } else if (ver_rel != 0) { 418267843Sdelphij while (ver_rel > 26) { 419267843Sdelphij if (file_printf(ms, "Z") == -1) 420267843Sdelphij return; 421267843Sdelphij ver_rel -= 26; 422267843Sdelphij } 423267843Sdelphij if (file_printf(ms, "%c", 'A' + ver_rel - 1) 424267843Sdelphij == -1) 425267843Sdelphij return; 426267843Sdelphij } 427267843Sdelphij } 428267843Sdelphij} 429267843Sdelphij 430267843Sdelphijstatic void 431267843Sdelphijdo_note_freebsd_version(struct magic_set *ms, int swap, void *v) 432267843Sdelphij{ 433267843Sdelphij uint32_t desc; 434267843Sdelphij 435267843Sdelphij (void)memcpy(&desc, v, sizeof(desc)); 436267843Sdelphij desc = elf_getu32(swap, desc); 437267843Sdelphij if (file_printf(ms, ", for FreeBSD") == -1) 438267843Sdelphij return; 439267843Sdelphij 440267843Sdelphij /* 441267843Sdelphij * Contents is __FreeBSD_version, whose relation to OS 442267843Sdelphij * versions is defined by a huge table in the Porter's 443267843Sdelphij * Handbook. This is the general scheme: 444267843Sdelphij * 445267843Sdelphij * Releases: 446267843Sdelphij * Mmp000 (before 4.10) 447267843Sdelphij * Mmi0p0 (before 5.0) 448267843Sdelphij * Mmm0p0 449267843Sdelphij * 450267843Sdelphij * Development branches: 451267843Sdelphij * Mmpxxx (before 4.6) 452267843Sdelphij * Mmp1xx (before 4.10) 453267843Sdelphij * Mmi1xx (before 5.0) 454267843Sdelphij * M000xx (pre-M.0) 455267843Sdelphij * Mmm1xx 456267843Sdelphij * 457267843Sdelphij * M = major version 458267843Sdelphij * m = minor version 459267843Sdelphij * i = minor version increment (491000 -> 4.10) 460267843Sdelphij * p = patchlevel 461267843Sdelphij * x = revision 462267843Sdelphij * 463267843Sdelphij * The first release of FreeBSD to use ELF by default 464267843Sdelphij * was version 3.0. 465267843Sdelphij */ 466267843Sdelphij if (desc == 460002) { 467267843Sdelphij if (file_printf(ms, " 4.6.2") == -1) 468267843Sdelphij return; 469267843Sdelphij } else if (desc < 460100) { 470267843Sdelphij if (file_printf(ms, " %d.%d", desc / 100000, 471267843Sdelphij desc / 10000 % 10) == -1) 472267843Sdelphij return; 473267843Sdelphij if (desc / 1000 % 10 > 0) 474267843Sdelphij if (file_printf(ms, ".%d", desc / 1000 % 10) == -1) 475267843Sdelphij return; 476267843Sdelphij if ((desc % 1000 > 0) || (desc % 100000 == 0)) 477267843Sdelphij if (file_printf(ms, " (%d)", desc) == -1) 478267843Sdelphij return; 479267843Sdelphij } else if (desc < 500000) { 480267843Sdelphij if (file_printf(ms, " %d.%d", desc / 100000, 481267843Sdelphij desc / 10000 % 10 + desc / 1000 % 10) == -1) 482267843Sdelphij return; 483267843Sdelphij if (desc / 100 % 10 > 0) { 484267843Sdelphij if (file_printf(ms, " (%d)", desc) == -1) 485267843Sdelphij return; 486267843Sdelphij } else if (desc / 10 % 10 > 0) { 487267843Sdelphij if (file_printf(ms, ".%d", desc / 10 % 10) == -1) 488267843Sdelphij return; 489267843Sdelphij } 490267843Sdelphij } else { 491267843Sdelphij if (file_printf(ms, " %d.%d", desc / 100000, 492267843Sdelphij desc / 1000 % 100) == -1) 493267843Sdelphij return; 494267843Sdelphij if ((desc / 100 % 10 > 0) || 495267843Sdelphij (desc % 100000 / 100 == 0)) { 496267843Sdelphij if (file_printf(ms, " (%d)", desc) == -1) 497267843Sdelphij return; 498267843Sdelphij } else if (desc / 10 % 10 > 0) { 499267843Sdelphij if (file_printf(ms, ".%d", desc / 10 % 10) == -1) 500267843Sdelphij return; 501267843Sdelphij } 502267843Sdelphij } 503267843Sdelphij} 504267843Sdelphij 505276577Sdelphijprivate int 506284237Sdelphij/*ARGSUSED*/ 507276577Sdelphijdo_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 508276577Sdelphij int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz, 509276577Sdelphij size_t noff, size_t doff, int *flags) 510133359Sobrien{ 511276577Sdelphij if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 512309847Sdelphij type == NT_GNU_BUILD_ID && (descsz >= 4 || descsz <= 20)) { 513276577Sdelphij uint8_t desc[20]; 514309847Sdelphij const char *btype; 515276577Sdelphij uint32_t i; 516276577Sdelphij *flags |= FLAGS_DID_BUILD_ID; 517309847Sdelphij switch (descsz) { 518309847Sdelphij case 8: 519309847Sdelphij btype = "xxHash"; 520309847Sdelphij break; 521309847Sdelphij case 16: 522309847Sdelphij btype = "md5/uuid"; 523309847Sdelphij break; 524309847Sdelphij case 20: 525309847Sdelphij btype = "sha1"; 526309847Sdelphij break; 527309847Sdelphij default: 528309847Sdelphij btype = "unknown"; 529309847Sdelphij break; 530309847Sdelphij } 531309847Sdelphij if (file_printf(ms, ", BuildID[%s]=", btype) == -1) 532276577Sdelphij return 1; 533276577Sdelphij (void)memcpy(desc, &nbuf[doff], descsz); 534276577Sdelphij for (i = 0; i < descsz; i++) 535276577Sdelphij if (file_printf(ms, "%02x", desc[i]) == -1) 536276577Sdelphij return 1; 537276577Sdelphij return 1; 538275666Sdelphij } 539276577Sdelphij return 0; 540276577Sdelphij} 541275666Sdelphij 542276577Sdelphijprivate int 543276577Sdelphijdo_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 544276577Sdelphij int swap, uint32_t namesz, uint32_t descsz, 545276577Sdelphij size_t noff, size_t doff, int *flags) 546276577Sdelphij{ 547267843Sdelphij if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 && 548276577Sdelphij type == NT_GNU_VERSION && descsz == 2) { 549276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 550267843Sdelphij file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]); 551276577Sdelphij return 1; 552267843Sdelphij } 553276577Sdelphij 554133359Sobrien if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 555276577Sdelphij type == NT_GNU_VERSION && descsz == 16) { 556133359Sobrien uint32_t desc[4]; 557133359Sobrien (void)memcpy(desc, &nbuf[doff], sizeof(desc)); 558133359Sobrien 559276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 560133359Sobrien if (file_printf(ms, ", for GNU/") == -1) 561276577Sdelphij return 1; 562186690Sobrien switch (elf_getu32(swap, desc[0])) { 563133359Sobrien case GNU_OS_LINUX: 564133359Sobrien if (file_printf(ms, "Linux") == -1) 565276577Sdelphij return 1; 566133359Sobrien break; 567133359Sobrien case GNU_OS_HURD: 568133359Sobrien if (file_printf(ms, "Hurd") == -1) 569276577Sdelphij return 1; 570133359Sobrien break; 571133359Sobrien case GNU_OS_SOLARIS: 572133359Sobrien if (file_printf(ms, "Solaris") == -1) 573276577Sdelphij return 1; 574133359Sobrien break; 575186690Sobrien case GNU_OS_KFREEBSD: 576186690Sobrien if (file_printf(ms, "kFreeBSD") == -1) 577276577Sdelphij return 1; 578186690Sobrien break; 579186690Sobrien case GNU_OS_KNETBSD: 580186690Sobrien if (file_printf(ms, "kNetBSD") == -1) 581276577Sdelphij return 1; 582186690Sobrien break; 583133359Sobrien default: 584133359Sobrien if (file_printf(ms, "<unknown>") == -1) 585276577Sdelphij return 1; 586133359Sobrien } 587186690Sobrien if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]), 588186690Sobrien elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1) 589276577Sdelphij return 1; 590276577Sdelphij return 1; 591133359Sobrien } 592133359Sobrien 593276577Sdelphij if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { 594276577Sdelphij if (type == NT_NETBSD_VERSION && descsz == 4) { 595276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 596276577Sdelphij do_note_netbsd_version(ms, swap, &nbuf[doff]); 597276577Sdelphij return 1; 598276577Sdelphij } 599226048Sobrien } 600226048Sobrien 601276577Sdelphij if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) { 602276577Sdelphij if (type == NT_FREEBSD_VERSION && descsz == 4) { 603276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 604276577Sdelphij do_note_freebsd_version(ms, swap, &nbuf[doff]); 605276577Sdelphij return 1; 606276577Sdelphij } 607276577Sdelphij } 608276577Sdelphij 609276577Sdelphij if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && 610276577Sdelphij type == NT_OPENBSD_VERSION && descsz == 4) { 611276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 612276577Sdelphij if (file_printf(ms, ", for OpenBSD") == -1) 613276577Sdelphij return 1; 614276577Sdelphij /* Content of note is always 0 */ 615276577Sdelphij return 1; 616276577Sdelphij } 617276577Sdelphij 618276577Sdelphij if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 && 619276577Sdelphij type == NT_DRAGONFLY_VERSION && descsz == 4) { 620276577Sdelphij uint32_t desc; 621276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 622276577Sdelphij if (file_printf(ms, ", for DragonFly") == -1) 623276577Sdelphij return 1; 624276577Sdelphij (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 625276577Sdelphij desc = elf_getu32(swap, desc); 626276577Sdelphij if (file_printf(ms, " %d.%d.%d", desc / 100000, 627276577Sdelphij desc / 10000 % 10, desc % 10000) == -1) 628276577Sdelphij return 1; 629276577Sdelphij return 1; 630276577Sdelphij } 631276577Sdelphij return 0; 632276577Sdelphij} 633276577Sdelphij 634276577Sdelphijprivate int 635276577Sdelphijdo_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 636276577Sdelphij int swap, uint32_t namesz, uint32_t descsz, 637276577Sdelphij size_t noff, size_t doff, int *flags) 638276577Sdelphij{ 639267843Sdelphij if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 && 640276577Sdelphij type == NT_NETBSD_PAX && descsz == 4) { 641267843Sdelphij static const char *pax[] = { 642267843Sdelphij "+mprotect", 643267843Sdelphij "-mprotect", 644267843Sdelphij "+segvguard", 645267843Sdelphij "-segvguard", 646267843Sdelphij "+ASLR", 647267843Sdelphij "-ASLR", 648267843Sdelphij }; 649133359Sobrien uint32_t desc; 650267843Sdelphij size_t i; 651267843Sdelphij int did = 0; 652267843Sdelphij 653276577Sdelphij *flags |= FLAGS_DID_NETBSD_PAX; 654133359Sobrien (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 655186690Sobrien desc = elf_getu32(swap, desc); 656133359Sobrien 657267843Sdelphij if (desc && file_printf(ms, ", PaX: ") == -1) 658276577Sdelphij return 1; 659133359Sobrien 660267843Sdelphij for (i = 0; i < __arraycount(pax); i++) { 661284237Sdelphij if (((1 << (int)i) & desc) == 0) 662267843Sdelphij continue; 663267843Sdelphij if (file_printf(ms, "%s%s", did++ ? "," : "", 664267843Sdelphij pax[i]) == -1) 665276577Sdelphij return 1; 666133359Sobrien } 667276577Sdelphij return 1; 668133359Sobrien } 669276577Sdelphij return 0; 670276577Sdelphij} 67168349Sobrien 672276577Sdelphijprivate int 673276577Sdelphijdo_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 674276577Sdelphij int swap, uint32_t namesz, uint32_t descsz, 675276577Sdelphij size_t noff, size_t doff, int *flags, size_t size, int clazz) 676276577Sdelphij{ 677276577Sdelphij#ifdef ELFCORE 678276577Sdelphij int os_style = -1; 679133359Sobrien /* 680133359Sobrien * Sigh. The 2.0.36 kernel in Debian 2.1, at 681133359Sobrien * least, doesn't correctly implement name 682133359Sobrien * sections, in core dumps, as specified by 683133359Sobrien * the "Program Linking" section of "UNIX(R) System 684133359Sobrien * V Release 4 Programmer's Guide: ANSI C and 685133359Sobrien * Programming Support Tools", because my copy 686133359Sobrien * clearly says "The first 'namesz' bytes in 'name' 687133359Sobrien * contain a *null-terminated* [emphasis mine] 688133359Sobrien * character representation of the entry's owner 689133359Sobrien * or originator", but the 2.0.36 kernel code 690133359Sobrien * doesn't include the terminating null in the 691133359Sobrien * name.... 692133359Sobrien */ 693133359Sobrien if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) || 694133359Sobrien (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) { 695133359Sobrien os_style = OS_STYLE_SVR4; 696133359Sobrien } 697133359Sobrien 698133359Sobrien if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) { 699133359Sobrien os_style = OS_STYLE_FREEBSD; 700133359Sobrien } 701133359Sobrien 702133359Sobrien if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11) 703133359Sobrien == 0)) { 704133359Sobrien os_style = OS_STYLE_NETBSD; 705133359Sobrien } 706133359Sobrien 707175296Sobrien if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) { 708169942Sobrien if (file_printf(ms, ", %s-style", os_style_names[os_style]) 709169942Sobrien == -1) 710276577Sdelphij return 1; 711175296Sobrien *flags |= FLAGS_DID_CORE_STYLE; 712159764Sobrien } 713133359Sobrien 714159764Sobrien switch (os_style) { 715159764Sobrien case OS_STYLE_NETBSD: 716276577Sdelphij if (type == NT_NETBSD_CORE_PROCINFO) { 717276577Sdelphij char sbuf[512]; 718159764Sobrien uint32_t signo; 719159764Sobrien /* 720159764Sobrien * Extract the program name. It is at 721159764Sobrien * offset 0x7c, and is up to 32-bytes, 722159764Sobrien * including the terminating NUL. 723159764Sobrien */ 724159764Sobrien if (file_printf(ms, ", from '%.31s'", 725276577Sdelphij file_printable(sbuf, sizeof(sbuf), 726276577Sdelphij (const char *)&nbuf[doff + 0x7c])) == -1) 727276577Sdelphij return 1; 728159764Sobrien 729159764Sobrien /* 730159764Sobrien * Extract the signal number. It is at 731159764Sobrien * offset 0x08. 732159764Sobrien */ 733159764Sobrien (void)memcpy(&signo, &nbuf[doff + 0x08], 734159764Sobrien sizeof(signo)); 735159764Sobrien if (file_printf(ms, " (signal %u)", 736186690Sobrien elf_getu32(swap, signo)) == -1) 737276577Sdelphij return 1; 738175296Sobrien *flags |= FLAGS_DID_CORE; 739276577Sdelphij return 1; 740159764Sobrien } 741159764Sobrien break; 742133359Sobrien 743159764Sobrien default: 744276577Sdelphij if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) { 745159764Sobrien size_t i, j; 746159764Sobrien unsigned char c; 747159764Sobrien /* 748159764Sobrien * Extract the program name. We assume 749159764Sobrien * it to be 16 characters (that's what it 750159764Sobrien * is in SunOS 5.x and Linux). 751159764Sobrien * 752159764Sobrien * Unfortunately, it's at a different offset 753175296Sobrien * in various OSes, so try multiple offsets. 754159764Sobrien * If the characters aren't all printable, 755159764Sobrien * reject it. 756159764Sobrien */ 757159764Sobrien for (i = 0; i < NOFFSETS; i++) { 758175296Sobrien unsigned char *cname, *cp; 759159764Sobrien size_t reloffset = prpsoffsets(i); 760159764Sobrien size_t noffset = doff + reloffset; 761226048Sobrien size_t k; 762159764Sobrien for (j = 0; j < 16; j++, noffset++, 763159764Sobrien reloffset++) { 76468349Sobrien /* 765159764Sobrien * Make sure we're not past 766159764Sobrien * the end of the buffer; if 767159764Sobrien * we are, just give up. 76868349Sobrien */ 769159764Sobrien if (noffset >= size) 770133359Sobrien goto tryanother; 771159764Sobrien 772133359Sobrien /* 773159764Sobrien * Make sure we're not past 774159764Sobrien * the end of the contents; 775159764Sobrien * if we are, this obviously 776159764Sobrien * isn't the right offset. 777133359Sobrien */ 778159764Sobrien if (reloffset >= descsz) 779133359Sobrien goto tryanother; 780159764Sobrien 781159764Sobrien c = nbuf[noffset]; 782159764Sobrien if (c == '\0') { 783159764Sobrien /* 784159764Sobrien * A '\0' at the 785159764Sobrien * beginning is 786159764Sobrien * obviously wrong. 787159764Sobrien * Any other '\0' 788159764Sobrien * means we're done. 789159764Sobrien */ 790159764Sobrien if (j == 0) 791159764Sobrien goto tryanother; 792159764Sobrien else 793159764Sobrien break; 794159764Sobrien } else { 795159764Sobrien /* 796159764Sobrien * A nonprintable 797159764Sobrien * character is also 798159764Sobrien * wrong. 799159764Sobrien */ 800159764Sobrien if (!isprint(c) || isquote(c)) 801159764Sobrien goto tryanother; 802159764Sobrien } 80368349Sobrien } 804159764Sobrien /* 805159764Sobrien * Well, that worked. 806159764Sobrien */ 807226048Sobrien 808226048Sobrien /* 809226048Sobrien * Try next offsets, in case this match is 810226048Sobrien * in the middle of a string. 811226048Sobrien */ 812276577Sdelphij for (k = i + 1 ; k < NOFFSETS; k++) { 813226048Sobrien size_t no; 814226048Sobrien int adjust = 1; 815226048Sobrien if (prpsoffsets(k) >= prpsoffsets(i)) 816226048Sobrien continue; 817226048Sobrien for (no = doff + prpsoffsets(k); 818226048Sobrien no < doff + prpsoffsets(i); no++) 819226048Sobrien adjust = adjust 820226048Sobrien && isprint(nbuf[no]); 821226048Sobrien if (adjust) 822226048Sobrien i = k; 823226048Sobrien } 824226048Sobrien 825175296Sobrien cname = (unsigned char *) 826175296Sobrien &nbuf[doff + prpsoffsets(i)]; 827175296Sobrien for (cp = cname; *cp && isprint(*cp); cp++) 828175296Sobrien continue; 829186690Sobrien /* 830186690Sobrien * Linux apparently appends a space at the end 831186690Sobrien * of the command line: remove it. 832186690Sobrien */ 833186690Sobrien while (cp > cname && isspace(cp[-1])) 834175296Sobrien cp--; 835175296Sobrien if (file_printf(ms, ", from '%.*s'", 836175296Sobrien (int)(cp - cname), cname) == -1) 837276577Sdelphij return 1; 838175296Sobrien *flags |= FLAGS_DID_CORE; 839276577Sdelphij return 1; 840133359Sobrien 841159764Sobrien tryanother: 842159764Sobrien ; 843159764Sobrien } 84468349Sobrien } 845159764Sobrien break; 84668349Sobrien } 847133359Sobrien#endif 848276577Sdelphij return 0; 849276577Sdelphij} 850276577Sdelphij 851298192Sdelphijprivate off_t 852298192Sdelphijget_offset_from_virtaddr(struct magic_set *ms, int swap, int clazz, int fd, 853298192Sdelphij off_t off, int num, off_t fsize, uint64_t virtaddr) 854298192Sdelphij{ 855298192Sdelphij Elf32_Phdr ph32; 856298192Sdelphij Elf64_Phdr ph64; 857298192Sdelphij 858298192Sdelphij /* 859298192Sdelphij * Loop through all the program headers and find the header with 860298192Sdelphij * virtual address in which the "virtaddr" belongs to. 861298192Sdelphij */ 862298192Sdelphij for ( ; num; num--) { 863298192Sdelphij if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) { 864298192Sdelphij file_badread(ms); 865298192Sdelphij return -1; 866298192Sdelphij } 867298192Sdelphij off += xph_sizeof; 868298192Sdelphij 869298192Sdelphij if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 870298192Sdelphij /* Perhaps warn here */ 871298192Sdelphij continue; 872298192Sdelphij } 873298192Sdelphij 874298192Sdelphij if (virtaddr >= xph_vaddr && virtaddr < xph_vaddr + xph_filesz) 875298192Sdelphij return xph_offset + (virtaddr - xph_vaddr); 876298192Sdelphij } 877298192Sdelphij return 0; 878298192Sdelphij} 879298192Sdelphij 880276577Sdelphijprivate size_t 881298192Sdelphijget_string_on_virtaddr(struct magic_set *ms, 882298192Sdelphij int swap, int clazz, int fd, off_t ph_off, int ph_num, 883298192Sdelphij off_t fsize, uint64_t virtaddr, char *buf, ssize_t buflen) 884298192Sdelphij{ 885298192Sdelphij char *bptr; 886298192Sdelphij off_t offset; 887298192Sdelphij 888298192Sdelphij if (buflen == 0) 889298192Sdelphij return 0; 890298192Sdelphij 891298192Sdelphij offset = get_offset_from_virtaddr(ms, swap, clazz, fd, ph_off, ph_num, 892298192Sdelphij fsize, virtaddr); 893298192Sdelphij if ((buflen = pread(fd, buf, buflen, offset)) <= 0) { 894298192Sdelphij file_badread(ms); 895298192Sdelphij return 0; 896298192Sdelphij } 897298192Sdelphij 898298192Sdelphij buf[buflen - 1] = '\0'; 899298192Sdelphij 900298192Sdelphij /* We expect only printable characters, so return if buffer contains 901298192Sdelphij * non-printable character before the '\0' or just '\0'. */ 902298192Sdelphij for (bptr = buf; *bptr && isprint((unsigned char)*bptr); bptr++) 903298192Sdelphij continue; 904298192Sdelphij if (*bptr != '\0') 905298192Sdelphij return 0; 906298192Sdelphij 907298192Sdelphij return bptr - buf; 908298192Sdelphij} 909298192Sdelphij 910298192Sdelphij 911298192Sdelphijprivate int 912298192Sdelphijdo_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 913298192Sdelphij int swap, uint32_t namesz __attribute__((__unused__)), 914298192Sdelphij uint32_t descsz __attribute__((__unused__)), 915298192Sdelphij size_t noff __attribute__((__unused__)), size_t doff, 916298192Sdelphij int *flags, size_t size __attribute__((__unused__)), int clazz, 917298192Sdelphij int fd, off_t ph_off, int ph_num, off_t fsize) 918298192Sdelphij{ 919298192Sdelphij#ifdef ELFCORE 920298192Sdelphij Aux32Info auxv32; 921298192Sdelphij Aux64Info auxv64; 922298192Sdelphij size_t elsize = xauxv_sizeof; 923298192Sdelphij const char *tag; 924298192Sdelphij int is_string; 925298192Sdelphij size_t nval; 926298192Sdelphij 927298192Sdelphij if (type != NT_AUXV || (*flags & FLAGS_IS_CORE) == 0) 928298192Sdelphij return 0; 929298192Sdelphij 930298192Sdelphij *flags |= FLAGS_DID_AUXV; 931298192Sdelphij 932298192Sdelphij nval = 0; 933298192Sdelphij for (size_t off = 0; off + elsize <= descsz; off += elsize) { 934298192Sdelphij (void)memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof); 935298192Sdelphij /* Limit processing to 50 vector entries to prevent DoS */ 936298192Sdelphij if (nval++ >= 50) { 937298192Sdelphij file_error(ms, 0, "Too many ELF Auxv elements"); 938298192Sdelphij return 1; 939298192Sdelphij } 940298192Sdelphij 941298192Sdelphij switch(xauxv_type) { 942298192Sdelphij case AT_LINUX_EXECFN: 943298192Sdelphij is_string = 1; 944298192Sdelphij tag = "execfn"; 945298192Sdelphij break; 946298192Sdelphij case AT_LINUX_PLATFORM: 947298192Sdelphij is_string = 1; 948298192Sdelphij tag = "platform"; 949298192Sdelphij break; 950298192Sdelphij case AT_LINUX_UID: 951298192Sdelphij is_string = 0; 952298192Sdelphij tag = "real uid"; 953298192Sdelphij break; 954298192Sdelphij case AT_LINUX_GID: 955298192Sdelphij is_string = 0; 956298192Sdelphij tag = "real gid"; 957298192Sdelphij break; 958298192Sdelphij case AT_LINUX_EUID: 959298192Sdelphij is_string = 0; 960298192Sdelphij tag = "effective uid"; 961298192Sdelphij break; 962298192Sdelphij case AT_LINUX_EGID: 963298192Sdelphij is_string = 0; 964298192Sdelphij tag = "effective gid"; 965298192Sdelphij break; 966298192Sdelphij default: 967298192Sdelphij is_string = 0; 968298192Sdelphij tag = NULL; 969298192Sdelphij break; 970298192Sdelphij } 971298192Sdelphij 972298192Sdelphij if (tag == NULL) 973298192Sdelphij continue; 974298192Sdelphij 975298192Sdelphij if (is_string) { 976298192Sdelphij char buf[256]; 977298192Sdelphij ssize_t buflen; 978298192Sdelphij buflen = get_string_on_virtaddr(ms, swap, clazz, fd, 979298192Sdelphij ph_off, ph_num, fsize, xauxv_val, buf, sizeof(buf)); 980298192Sdelphij 981298192Sdelphij if (buflen == 0) 982298192Sdelphij continue; 983298192Sdelphij 984298192Sdelphij if (file_printf(ms, ", %s: '%s'", tag, buf) == -1) 985298192Sdelphij return 0; 986298192Sdelphij } else { 987298192Sdelphij if (file_printf(ms, ", %s: %d", tag, (int) xauxv_val) 988298192Sdelphij == -1) 989298192Sdelphij return 0; 990298192Sdelphij } 991298192Sdelphij } 992298192Sdelphij return 1; 993298192Sdelphij#else 994298192Sdelphij return 0; 995298192Sdelphij#endif 996298192Sdelphij} 997298192Sdelphij 998298192Sdelphijprivate size_t 999276577Sdelphijdonote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, 1000298192Sdelphij int clazz, int swap, size_t align, int *flags, uint16_t *notecount, 1001298192Sdelphij int fd, off_t ph_off, int ph_num, off_t fsize) 1002276577Sdelphij{ 1003276577Sdelphij Elf32_Nhdr nh32; 1004276577Sdelphij Elf64_Nhdr nh64; 1005276577Sdelphij size_t noff, doff; 1006276577Sdelphij uint32_t namesz, descsz; 1007276577Sdelphij unsigned char *nbuf = CAST(unsigned char *, vbuf); 1008276577Sdelphij 1009276577Sdelphij if (*notecount == 0) 1010276577Sdelphij return 0; 1011276577Sdelphij --*notecount; 1012276577Sdelphij 1013276577Sdelphij if (xnh_sizeof + offset > size) { 1014276577Sdelphij /* 1015276577Sdelphij * We're out of note headers. 1016276577Sdelphij */ 1017276577Sdelphij return xnh_sizeof + offset; 1018276577Sdelphij } 1019276577Sdelphij 1020276577Sdelphij (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); 1021276577Sdelphij offset += xnh_sizeof; 1022276577Sdelphij 1023276577Sdelphij namesz = xnh_namesz; 1024276577Sdelphij descsz = xnh_descsz; 1025298192Sdelphij 1026276577Sdelphij if ((namesz == 0) && (descsz == 0)) { 1027276577Sdelphij /* 1028276577Sdelphij * We're out of note headers. 1029276577Sdelphij */ 1030276577Sdelphij return (offset >= size) ? offset : size; 1031276577Sdelphij } 1032276577Sdelphij 1033276577Sdelphij if (namesz & 0x80000000) { 1034276577Sdelphij (void)file_printf(ms, ", bad note name size 0x%lx", 1035276577Sdelphij (unsigned long)namesz); 1036276577Sdelphij return 0; 1037276577Sdelphij } 1038276577Sdelphij 1039276577Sdelphij if (descsz & 0x80000000) { 1040276577Sdelphij (void)file_printf(ms, ", bad note description size 0x%lx", 1041276577Sdelphij (unsigned long)descsz); 1042276577Sdelphij return 0; 1043276577Sdelphij } 1044276577Sdelphij 1045276577Sdelphij noff = offset; 1046276577Sdelphij doff = ELF_ALIGN(offset + namesz); 1047276577Sdelphij 1048276577Sdelphij if (offset + namesz > size) { 1049276577Sdelphij /* 1050276577Sdelphij * We're past the end of the buffer. 1051276577Sdelphij */ 1052276577Sdelphij return doff; 1053276577Sdelphij } 1054276577Sdelphij 1055276577Sdelphij offset = ELF_ALIGN(doff + descsz); 1056276577Sdelphij if (doff + descsz > size) { 1057276577Sdelphij /* 1058276577Sdelphij * We're past the end of the buffer. 1059276577Sdelphij */ 1060276577Sdelphij return (offset >= size) ? offset : size; 1061276577Sdelphij } 1062276577Sdelphij 1063298192Sdelphij 1064276577Sdelphij if ((*flags & FLAGS_DID_OS_NOTE) == 0) { 1065276577Sdelphij if (do_os_note(ms, nbuf, xnh_type, swap, 1066276577Sdelphij namesz, descsz, noff, doff, flags)) 1067298192Sdelphij return offset; 1068276577Sdelphij } 1069276577Sdelphij 1070276577Sdelphij if ((*flags & FLAGS_DID_BUILD_ID) == 0) { 1071276577Sdelphij if (do_bid_note(ms, nbuf, xnh_type, swap, 1072276577Sdelphij namesz, descsz, noff, doff, flags)) 1073298192Sdelphij return offset; 1074276577Sdelphij } 1075276577Sdelphij 1076276577Sdelphij if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) { 1077276577Sdelphij if (do_pax_note(ms, nbuf, xnh_type, swap, 1078276577Sdelphij namesz, descsz, noff, doff, flags)) 1079298192Sdelphij return offset; 1080276577Sdelphij } 1081276577Sdelphij 1082276577Sdelphij if ((*flags & FLAGS_DID_CORE) == 0) { 1083276577Sdelphij if (do_core_note(ms, nbuf, xnh_type, swap, 1084276577Sdelphij namesz, descsz, noff, doff, flags, size, clazz)) 1085298192Sdelphij return offset; 1086276577Sdelphij } 1087276577Sdelphij 1088298192Sdelphij if ((*flags & FLAGS_DID_AUXV) == 0) { 1089298192Sdelphij if (do_auxv_note(ms, nbuf, xnh_type, swap, 1090298192Sdelphij namesz, descsz, noff, doff, flags, size, clazz, 1091298192Sdelphij fd, ph_off, ph_num, fsize)) 1092298192Sdelphij return offset; 1093298192Sdelphij } 1094298192Sdelphij 1095276577Sdelphij if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { 1096276577Sdelphij if (descsz > 100) 1097276577Sdelphij descsz = 100; 1098276577Sdelphij switch (xnh_type) { 1099276577Sdelphij case NT_NETBSD_VERSION: 1100298192Sdelphij return offset; 1101276577Sdelphij case NT_NETBSD_MARCH: 1102276577Sdelphij if (*flags & FLAGS_DID_NETBSD_MARCH) 1103298192Sdelphij return offset; 1104276577Sdelphij *flags |= FLAGS_DID_NETBSD_MARCH; 1105276577Sdelphij if (file_printf(ms, ", compiled for: %.*s", 1106276577Sdelphij (int)descsz, (const char *)&nbuf[doff]) == -1) 1107298192Sdelphij return offset; 1108276577Sdelphij break; 1109276577Sdelphij case NT_NETBSD_CMODEL: 1110276577Sdelphij if (*flags & FLAGS_DID_NETBSD_CMODEL) 1111298192Sdelphij return offset; 1112276577Sdelphij *flags |= FLAGS_DID_NETBSD_CMODEL; 1113276577Sdelphij if (file_printf(ms, ", compiler model: %.*s", 1114276577Sdelphij (int)descsz, (const char *)&nbuf[doff]) == -1) 1115298192Sdelphij return offset; 1116276577Sdelphij break; 1117276577Sdelphij default: 1118276577Sdelphij if (*flags & FLAGS_DID_NETBSD_UNKNOWN) 1119298192Sdelphij return offset; 1120276577Sdelphij *flags |= FLAGS_DID_NETBSD_UNKNOWN; 1121276577Sdelphij if (file_printf(ms, ", note=%u", xnh_type) == -1) 1122298192Sdelphij return offset; 1123276577Sdelphij break; 1124276577Sdelphij } 1125298192Sdelphij return offset; 1126276577Sdelphij } 1127276577Sdelphij 1128133359Sobrien return offset; 112968349Sobrien} 113068349Sobrien 1131186690Sobrien/* SunOS 5.x hardware capability descriptions */ 1132186690Sobrientypedef struct cap_desc { 1133186690Sobrien uint64_t cd_mask; 1134186690Sobrien const char *cd_name; 1135186690Sobrien} cap_desc_t; 1136186690Sobrien 1137186690Sobrienstatic const cap_desc_t cap_desc_sparc[] = { 1138186690Sobrien { AV_SPARC_MUL32, "MUL32" }, 1139186690Sobrien { AV_SPARC_DIV32, "DIV32" }, 1140186690Sobrien { AV_SPARC_FSMULD, "FSMULD" }, 1141186690Sobrien { AV_SPARC_V8PLUS, "V8PLUS" }, 1142186690Sobrien { AV_SPARC_POPC, "POPC" }, 1143186690Sobrien { AV_SPARC_VIS, "VIS" }, 1144186690Sobrien { AV_SPARC_VIS2, "VIS2" }, 1145186690Sobrien { AV_SPARC_ASI_BLK_INIT, "ASI_BLK_INIT" }, 1146186690Sobrien { AV_SPARC_FMAF, "FMAF" }, 1147186690Sobrien { AV_SPARC_FJFMAU, "FJFMAU" }, 1148186690Sobrien { AV_SPARC_IMA, "IMA" }, 1149186690Sobrien { 0, NULL } 1150186690Sobrien}; 1151186690Sobrien 1152186690Sobrienstatic const cap_desc_t cap_desc_386[] = { 1153186690Sobrien { AV_386_FPU, "FPU" }, 1154186690Sobrien { AV_386_TSC, "TSC" }, 1155186690Sobrien { AV_386_CX8, "CX8" }, 1156186690Sobrien { AV_386_SEP, "SEP" }, 1157186690Sobrien { AV_386_AMD_SYSC, "AMD_SYSC" }, 1158186690Sobrien { AV_386_CMOV, "CMOV" }, 1159186690Sobrien { AV_386_MMX, "MMX" }, 1160186690Sobrien { AV_386_AMD_MMX, "AMD_MMX" }, 1161186690Sobrien { AV_386_AMD_3DNow, "AMD_3DNow" }, 1162186690Sobrien { AV_386_AMD_3DNowx, "AMD_3DNowx" }, 1163186690Sobrien { AV_386_FXSR, "FXSR" }, 1164186690Sobrien { AV_386_SSE, "SSE" }, 1165186690Sobrien { AV_386_SSE2, "SSE2" }, 1166186690Sobrien { AV_386_PAUSE, "PAUSE" }, 1167186690Sobrien { AV_386_SSE3, "SSE3" }, 1168186690Sobrien { AV_386_MON, "MON" }, 1169186690Sobrien { AV_386_CX16, "CX16" }, 1170186690Sobrien { AV_386_AHF, "AHF" }, 1171186690Sobrien { AV_386_TSCP, "TSCP" }, 1172186690Sobrien { AV_386_AMD_SSE4A, "AMD_SSE4A" }, 1173186690Sobrien { AV_386_POPCNT, "POPCNT" }, 1174186690Sobrien { AV_386_AMD_LZCNT, "AMD_LZCNT" }, 1175186690Sobrien { AV_386_SSSE3, "SSSE3" }, 1176186690Sobrien { AV_386_SSE4_1, "SSE4.1" }, 1177186690Sobrien { AV_386_SSE4_2, "SSE4.2" }, 1178186690Sobrien { 0, NULL } 1179186690Sobrien}; 1180186690Sobrien 1181133359Sobrienprivate int 1182186690Sobriendoshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, 1183276577Sdelphij size_t size, off_t fsize, int mach, int strtab, int *flags, 1184276577Sdelphij uint16_t *notecount) 118568349Sobrien{ 1186133359Sobrien Elf32_Shdr sh32; 1187133359Sobrien Elf64_Shdr sh64; 1188159764Sobrien int stripped = 1; 1189275666Sdelphij size_t nbadcap = 0; 1190159764Sobrien void *nbuf; 1191267843Sdelphij off_t noff, coff, name_off; 1192186690Sobrien uint64_t cap_hw1 = 0; /* SunOS 5.x hardware capabilites */ 1193186690Sobrien uint64_t cap_sf1 = 0; /* SunOS 5.x software capabilites */ 1194267843Sdelphij char name[50]; 1195276577Sdelphij ssize_t namesize; 1196133359Sobrien 1197159764Sobrien if (size != xsh_sizeof) { 1198133359Sobrien if (file_printf(ms, ", corrupted section header size") == -1) 1199133359Sobrien return -1; 1200133359Sobrien return 0; 1201133359Sobrien } 1202133359Sobrien 1203267843Sdelphij /* Read offset of name section to be able to read section names later */ 1204284237Sdelphij if (pread(fd, xsh_addr, xsh_sizeof, CAST(off_t, (off + size * strtab))) 1205284237Sdelphij < (ssize_t)xsh_sizeof) { 1206267843Sdelphij file_badread(ms); 1207267843Sdelphij return -1; 1208267843Sdelphij } 1209267843Sdelphij name_off = xsh_offset; 1210267843Sdelphij 1211133359Sobrien for ( ; num; num--) { 1212267843Sdelphij /* Read the name of this section. */ 1213276577Sdelphij if ((namesize = pread(fd, name, sizeof(name) - 1, name_off + xsh_name)) == -1) { 1214267843Sdelphij file_badread(ms); 1215226048Sobrien return -1; 1216226048Sobrien } 1217276577Sdelphij name[namesize] = '\0'; 1218267843Sdelphij if (strcmp(name, ".debug_info") == 0) 1219267843Sdelphij stripped = 0; 1220267843Sdelphij 1221276577Sdelphij if (pread(fd, xsh_addr, xsh_sizeof, off) < (ssize_t)xsh_sizeof) { 1222133359Sobrien file_badread(ms); 1223133359Sobrien return -1; 1224133359Sobrien } 1225226048Sobrien off += size; 1226226048Sobrien 1227226048Sobrien /* Things we can determine before we seek */ 1228159764Sobrien switch (xsh_type) { 1229159764Sobrien case SHT_SYMTAB: 1230159764Sobrien#if 0 1231159764Sobrien case SHT_DYNSYM: 1232159764Sobrien#endif 1233159764Sobrien stripped = 0; 1234159764Sobrien break; 1235226048Sobrien default: 1236275698Sdelphij if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) { 1237226048Sobrien /* Perhaps warn here */ 1238226048Sobrien continue; 1239226048Sobrien } 1240226048Sobrien break; 1241226048Sobrien } 1242226048Sobrien 1243287453Sdelphij 1244226048Sobrien /* Things we can determine when we seek */ 1245226048Sobrien switch (xsh_type) { 1246159764Sobrien case SHT_NOTE: 1247288143Sdelphij if ((uintmax_t)(xsh_size + xsh_offset) > 1248288143Sdelphij (uintmax_t)fsize) { 1249287453Sdelphij if (file_printf(ms, 1250288143Sdelphij ", note offset/size 0x%" INTMAX_T_FORMAT 1251288143Sdelphij "x+0x%" INTMAX_T_FORMAT "x exceeds" 1252288143Sdelphij " file size 0x%" INTMAX_T_FORMAT "x", 1253288143Sdelphij (uintmax_t)xsh_offset, (uintmax_t)xsh_size, 1254288143Sdelphij (uintmax_t)fsize) == -1) 1255287453Sdelphij return -1; 1256287453Sdelphij return 0; 1257287453Sdelphij } 1258267843Sdelphij if ((nbuf = malloc(xsh_size)) == NULL) { 1259159764Sobrien file_error(ms, errno, "Cannot allocate memory" 1260159764Sobrien " for note"); 1261159764Sobrien return -1; 1262159764Sobrien } 1263288143Sdelphij if (pread(fd, nbuf, xsh_size, xsh_offset) < 1264288143Sdelphij (ssize_t)xsh_size) { 1265159764Sobrien file_badread(ms); 1266159764Sobrien free(nbuf); 1267159764Sobrien return -1; 1268159764Sobrien } 1269159764Sobrien 1270159764Sobrien noff = 0; 1271159764Sobrien for (;;) { 1272191736Sobrien if (noff >= (off_t)xsh_size) 1273159764Sobrien break; 1274159764Sobrien noff = donote(ms, nbuf, (size_t)noff, 1275298192Sdelphij xsh_size, clazz, swap, 4, flags, notecount, 1276298192Sdelphij fd, 0, 0, 0); 1277159764Sobrien if (noff == 0) 1278159764Sobrien break; 1279159764Sobrien } 1280159764Sobrien free(nbuf); 1281159764Sobrien break; 1282186690Sobrien case SHT_SUNW_cap: 1283267843Sdelphij switch (mach) { 1284267843Sdelphij case EM_SPARC: 1285267843Sdelphij case EM_SPARCV9: 1286267843Sdelphij case EM_IA_64: 1287267843Sdelphij case EM_386: 1288267843Sdelphij case EM_AMD64: 1289267843Sdelphij break; 1290267843Sdelphij default: 1291267843Sdelphij goto skip; 1292267843Sdelphij } 1293267843Sdelphij 1294275666Sdelphij if (nbadcap > 5) 1295275666Sdelphij break; 1296267843Sdelphij if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) { 1297226048Sobrien file_badseek(ms); 1298186690Sobrien return -1; 1299186690Sobrien } 1300186690Sobrien coff = 0; 1301186690Sobrien for (;;) { 1302186690Sobrien Elf32_Cap cap32; 1303186690Sobrien Elf64_Cap cap64; 1304191736Sobrien char cbuf[/*CONSTCOND*/ 1305191736Sobrien MAX(sizeof cap32, sizeof cap64)]; 1306226048Sobrien if ((coff += xcap_sizeof) > (off_t)xsh_size) 1307186690Sobrien break; 1308186690Sobrien if (read(fd, cbuf, (size_t)xcap_sizeof) != 1309186690Sobrien (ssize_t)xcap_sizeof) { 1310186690Sobrien file_badread(ms); 1311186690Sobrien return -1; 1312186690Sobrien } 1313267843Sdelphij if (cbuf[0] == 'A') { 1314267843Sdelphij#ifdef notyet 1315267843Sdelphij char *p = cbuf + 1; 1316267843Sdelphij uint32_t len, tag; 1317267843Sdelphij memcpy(&len, p, sizeof(len)); 1318267843Sdelphij p += 4; 1319267843Sdelphij len = getu32(swap, len); 1320267843Sdelphij if (memcmp("gnu", p, 3) != 0) { 1321267843Sdelphij if (file_printf(ms, 1322267843Sdelphij ", unknown capability %.3s", p) 1323267843Sdelphij == -1) 1324267843Sdelphij return -1; 1325267843Sdelphij break; 1326267843Sdelphij } 1327267843Sdelphij p += strlen(p) + 1; 1328267843Sdelphij tag = *p++; 1329267843Sdelphij memcpy(&len, p, sizeof(len)); 1330267843Sdelphij p += 4; 1331267843Sdelphij len = getu32(swap, len); 1332267843Sdelphij if (tag != 1) { 1333267843Sdelphij if (file_printf(ms, ", unknown gnu" 1334267843Sdelphij " capability tag %d", tag) 1335267843Sdelphij == -1) 1336267843Sdelphij return -1; 1337267843Sdelphij break; 1338267843Sdelphij } 1339267843Sdelphij // gnu attributes 1340267843Sdelphij#endif 1341267843Sdelphij break; 1342267843Sdelphij } 1343186690Sobrien (void)memcpy(xcap_addr, cbuf, xcap_sizeof); 1344186690Sobrien switch (xcap_tag) { 1345186690Sobrien case CA_SUNW_NULL: 1346186690Sobrien break; 1347186690Sobrien case CA_SUNW_HW_1: 1348186690Sobrien cap_hw1 |= xcap_val; 1349186690Sobrien break; 1350186690Sobrien case CA_SUNW_SF_1: 1351186690Sobrien cap_sf1 |= xcap_val; 1352186690Sobrien break; 1353186690Sobrien default: 1354186690Sobrien if (file_printf(ms, 1355186690Sobrien ", with unknown capability " 1356226048Sobrien "0x%" INT64_T_FORMAT "x = 0x%" 1357226048Sobrien INT64_T_FORMAT "x", 1358191736Sobrien (unsigned long long)xcap_tag, 1359191736Sobrien (unsigned long long)xcap_val) == -1) 1360186690Sobrien return -1; 1361275666Sdelphij if (nbadcap++ > 2) 1362275666Sdelphij coff = xsh_size; 1363186690Sobrien break; 1364186690Sobrien } 1365186690Sobrien } 1366267843Sdelphij /*FALLTHROUGH*/ 1367267843Sdelphij skip: 1368226048Sobrien default: 1369226048Sobrien break; 1370133359Sobrien } 1371133359Sobrien } 1372267843Sdelphij 1373159764Sobrien if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1) 1374133359Sobrien return -1; 1375186690Sobrien if (cap_hw1) { 1376186690Sobrien const cap_desc_t *cdp; 1377186690Sobrien switch (mach) { 1378186690Sobrien case EM_SPARC: 1379186690Sobrien case EM_SPARC32PLUS: 1380186690Sobrien case EM_SPARCV9: 1381186690Sobrien cdp = cap_desc_sparc; 1382186690Sobrien break; 1383186690Sobrien case EM_386: 1384186690Sobrien case EM_IA_64: 1385186690Sobrien case EM_AMD64: 1386186690Sobrien cdp = cap_desc_386; 1387186690Sobrien break; 1388186690Sobrien default: 1389186690Sobrien cdp = NULL; 1390186690Sobrien break; 1391186690Sobrien } 1392186690Sobrien if (file_printf(ms, ", uses") == -1) 1393186690Sobrien return -1; 1394186690Sobrien if (cdp) { 1395186690Sobrien while (cdp->cd_name) { 1396186690Sobrien if (cap_hw1 & cdp->cd_mask) { 1397186690Sobrien if (file_printf(ms, 1398186690Sobrien " %s", cdp->cd_name) == -1) 1399186690Sobrien return -1; 1400186690Sobrien cap_hw1 &= ~cdp->cd_mask; 1401186690Sobrien } 1402186690Sobrien ++cdp; 1403186690Sobrien } 1404186690Sobrien if (cap_hw1) 1405186690Sobrien if (file_printf(ms, 1406226048Sobrien " unknown hardware capability 0x%" 1407226048Sobrien INT64_T_FORMAT "x", 1408191736Sobrien (unsigned long long)cap_hw1) == -1) 1409186690Sobrien return -1; 1410186690Sobrien } else { 1411186690Sobrien if (file_printf(ms, 1412226048Sobrien " hardware capability 0x%" INT64_T_FORMAT "x", 1413191736Sobrien (unsigned long long)cap_hw1) == -1) 1414186690Sobrien return -1; 1415186690Sobrien } 1416186690Sobrien } 1417186690Sobrien if (cap_sf1) { 1418186690Sobrien if (cap_sf1 & SF1_SUNW_FPUSED) { 1419186690Sobrien if (file_printf(ms, 1420186690Sobrien (cap_sf1 & SF1_SUNW_FPKNWN) 1421186690Sobrien ? ", uses frame pointer" 1422186690Sobrien : ", not known to use frame pointer") == -1) 1423186690Sobrien return -1; 1424186690Sobrien } 1425186690Sobrien cap_sf1 &= ~SF1_SUNW_MASK; 1426186690Sobrien if (cap_sf1) 1427186690Sobrien if (file_printf(ms, 1428226048Sobrien ", with unknown software capability 0x%" 1429226048Sobrien INT64_T_FORMAT "x", 1430191736Sobrien (unsigned long long)cap_sf1) == -1) 1431186690Sobrien return -1; 1432186690Sobrien } 1433133359Sobrien return 0; 1434133359Sobrien} 1435133359Sobrien 1436133359Sobrien/* 1437133359Sobrien * Look through the program headers of an executable image, searching 1438133359Sobrien * for a PT_INTERP section; if one is found, it's dynamically linked, 1439133359Sobrien * otherwise it's statically linked. 1440133359Sobrien */ 1441133359Sobrienprivate int 1442186690Sobriendophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 1443276577Sdelphij int num, size_t size, off_t fsize, int sh_num, int *flags, 1444276577Sdelphij uint16_t *notecount) 1445133359Sobrien{ 1446133359Sobrien Elf32_Phdr ph32; 1447133359Sobrien Elf64_Phdr ph64; 1448133359Sobrien const char *linking_style = "statically"; 1449276577Sdelphij const char *interp = ""; 1450133359Sobrien unsigned char nbuf[BUFSIZ]; 1451276577Sdelphij char ibuf[BUFSIZ]; 1452226048Sobrien ssize_t bufsize; 1453267843Sdelphij size_t offset, align, len; 1454169942Sobrien 1455159764Sobrien if (size != xph_sizeof) { 1456133359Sobrien if (file_printf(ms, ", corrupted program header size") == -1) 1457186690Sobrien return -1; 1458133359Sobrien return 0; 1459133359Sobrien } 1460169942Sobrien 1461133359Sobrien for ( ; num; num--) { 1462276577Sdelphij if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) { 1463267843Sdelphij file_badread(ms); 1464133359Sobrien return -1; 1465133359Sobrien } 1466169942Sobrien 1467226048Sobrien off += size; 1468276577Sdelphij bufsize = 0; 1469276577Sdelphij align = 4; 1470169942Sobrien 1471226048Sobrien /* Things we can determine before we seek */ 1472159764Sobrien switch (xph_type) { 1473133359Sobrien case PT_DYNAMIC: 1474133359Sobrien linking_style = "dynamically"; 1475133359Sobrien break; 1476276577Sdelphij case PT_NOTE: 1477276577Sdelphij if (sh_num) /* Did this through section headers */ 1478276577Sdelphij continue; 1479276577Sdelphij if (((align = xph_align) & 0x80000000UL) != 0 || 1480276577Sdelphij align < 4) { 1481276577Sdelphij if (file_printf(ms, 1482276577Sdelphij ", invalid note alignment 0x%lx", 1483276577Sdelphij (unsigned long)align) == -1) 1484276577Sdelphij return -1; 1485276577Sdelphij align = 4; 1486276577Sdelphij } 1487276577Sdelphij /*FALLTHROUGH*/ 1488133359Sobrien case PT_INTERP: 1489276577Sdelphij len = xph_filesz < sizeof(nbuf) ? xph_filesz 1490276577Sdelphij : sizeof(nbuf); 1491276577Sdelphij bufsize = pread(fd, nbuf, len, xph_offset); 1492276577Sdelphij if (bufsize == -1) { 1493276577Sdelphij file_badread(ms); 1494276577Sdelphij return -1; 1495276577Sdelphij } 1496133359Sobrien break; 1497226048Sobrien default: 1498275698Sdelphij if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 1499226048Sobrien /* Maybe warn here? */ 1500226048Sobrien continue; 1501226048Sobrien } 1502226048Sobrien break; 1503226048Sobrien } 1504226048Sobrien 1505226048Sobrien /* Things we can determine when we seek */ 1506226048Sobrien switch (xph_type) { 1507276577Sdelphij case PT_INTERP: 1508276577Sdelphij if (bufsize && nbuf[0]) { 1509276577Sdelphij nbuf[bufsize - 1] = '\0'; 1510276577Sdelphij interp = (const char *)nbuf; 1511276577Sdelphij } else 1512276577Sdelphij interp = "*empty*"; 1513276577Sdelphij break; 1514133359Sobrien case PT_NOTE: 1515133359Sobrien /* 1516133359Sobrien * This is a PT_NOTE section; loop through all the notes 1517133359Sobrien * in the section. 1518133359Sobrien */ 1519133359Sobrien offset = 0; 1520133359Sobrien for (;;) { 1521133359Sobrien if (offset >= (size_t)bufsize) 1522133359Sobrien break; 1523133359Sobrien offset = donote(ms, nbuf, offset, 1524186690Sobrien (size_t)bufsize, clazz, swap, align, 1525298192Sdelphij flags, notecount, fd, 0, 0, 0); 1526133359Sobrien if (offset == 0) 1527133359Sobrien break; 1528133359Sobrien } 1529133359Sobrien break; 1530175296Sobrien default: 1531175296Sobrien break; 1532133359Sobrien } 1533133359Sobrien } 1534276577Sdelphij if (file_printf(ms, ", %s linked", linking_style) 1535133359Sobrien == -1) 1536276577Sdelphij return -1; 1537276577Sdelphij if (interp[0]) 1538276577Sdelphij if (file_printf(ms, ", interpreter %s", 1539276577Sdelphij file_printable(ibuf, sizeof(ibuf), interp)) == -1) 1540276577Sdelphij return -1; 1541133359Sobrien return 0; 1542133359Sobrien} 1543133359Sobrien 1544133359Sobrien 1545133359Sobrienprotected int 1546133359Sobrienfile_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, 1547133359Sobrien size_t nbytes) 1548133359Sobrien{ 154968349Sobrien union { 1550103373Sobrien int32_t l; 1551103373Sobrien char c[sizeof (int32_t)]; 155268349Sobrien } u; 1553186690Sobrien int clazz; 155468349Sobrien int swap; 1555169942Sobrien struct stat st; 1556169942Sobrien off_t fsize; 1557169942Sobrien int flags = 0; 1558186690Sobrien Elf32_Ehdr elf32hdr; 1559186690Sobrien Elf64_Ehdr elf64hdr; 1560276577Sdelphij uint16_t type, phnum, shnum, notecount; 156168349Sobrien 1562284237Sdelphij if (ms->flags & (MAGIC_MIME|MAGIC_APPLE|MAGIC_EXTENSION)) 1563186690Sobrien return 0; 156468349Sobrien /* 156568349Sobrien * ELF executables have multiple section headers in arbitrary 156668349Sobrien * file locations and thus file(1) cannot determine it from easily. 156768349Sobrien * Instead we traverse thru all section headers until a symbol table 156868349Sobrien * one is found or else the binary is stripped. 1569186690Sobrien * Return immediately if it's not ELF (so we avoid pipe2file unless needed). 157068349Sobrien */ 157168349Sobrien if (buf[EI_MAG0] != ELFMAG0 157268349Sobrien || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) 157368349Sobrien || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) 1574186690Sobrien return 0; 157568349Sobrien 1576186690Sobrien /* 1577186690Sobrien * If we cannot seek, it must be a pipe, socket or fifo. 1578186690Sobrien */ 1579186690Sobrien if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) 1580186690Sobrien fd = file_pipe2file(ms, fd, buf, nbytes); 158168349Sobrien 1582186690Sobrien if (fstat(fd, &st) == -1) { 1583186690Sobrien file_badread(ms); 1584186690Sobrien return -1; 158568349Sobrien } 1586275698Sdelphij if (S_ISREG(st.st_mode) || st.st_size != 0) 1587275698Sdelphij fsize = st.st_size; 1588275698Sdelphij else 1589275698Sdelphij fsize = SIZE_UNKNOWN; 159068349Sobrien 1591186690Sobrien clazz = buf[EI_CLASS]; 159268349Sobrien 1593186690Sobrien switch (clazz) { 1594186690Sobrien case ELFCLASS32: 1595186690Sobrien#undef elf_getu 1596186690Sobrien#define elf_getu(a, b) elf_getu32(a, b) 1597186690Sobrien#undef elfhdr 1598186690Sobrien#define elfhdr elf32hdr 1599186690Sobrien#include "elfclass.h" 1600186690Sobrien case ELFCLASS64: 1601186690Sobrien#undef elf_getu 1602186690Sobrien#define elf_getu(a, b) elf_getu64(a, b) 1603186690Sobrien#undef elfhdr 1604186690Sobrien#define elfhdr elf64hdr 1605186690Sobrien#include "elfclass.h" 1606186690Sobrien default: 1607186690Sobrien if (file_printf(ms, ", unknown class %d", clazz) == -1) 1608186690Sobrien return -1; 1609186690Sobrien break; 161068349Sobrien } 1611133359Sobrien return 0; 161268349Sobrien} 161368349Sobrien#endif 1614