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 30298192SdelphijFILE_RCSID("@(#)$File: readelf.c,v 1.127 2015/11/18 12:29:29 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 && 512276577Sdelphij type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) { 513276577Sdelphij uint8_t desc[20]; 514276577Sdelphij uint32_t i; 515276577Sdelphij *flags |= FLAGS_DID_BUILD_ID; 516276577Sdelphij if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" : 517276577Sdelphij "sha1") == -1) 518276577Sdelphij return 1; 519276577Sdelphij (void)memcpy(desc, &nbuf[doff], descsz); 520276577Sdelphij for (i = 0; i < descsz; i++) 521276577Sdelphij if (file_printf(ms, "%02x", desc[i]) == -1) 522276577Sdelphij return 1; 523276577Sdelphij return 1; 524275666Sdelphij } 525276577Sdelphij return 0; 526276577Sdelphij} 527275666Sdelphij 528276577Sdelphijprivate int 529276577Sdelphijdo_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 530276577Sdelphij int swap, uint32_t namesz, uint32_t descsz, 531276577Sdelphij size_t noff, size_t doff, int *flags) 532276577Sdelphij{ 533267843Sdelphij if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 && 534276577Sdelphij type == NT_GNU_VERSION && descsz == 2) { 535276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 536267843Sdelphij file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]); 537276577Sdelphij return 1; 538267843Sdelphij } 539276577Sdelphij 540133359Sobrien if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 541276577Sdelphij type == NT_GNU_VERSION && descsz == 16) { 542133359Sobrien uint32_t desc[4]; 543133359Sobrien (void)memcpy(desc, &nbuf[doff], sizeof(desc)); 544133359Sobrien 545276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 546133359Sobrien if (file_printf(ms, ", for GNU/") == -1) 547276577Sdelphij return 1; 548186690Sobrien switch (elf_getu32(swap, desc[0])) { 549133359Sobrien case GNU_OS_LINUX: 550133359Sobrien if (file_printf(ms, "Linux") == -1) 551276577Sdelphij return 1; 552133359Sobrien break; 553133359Sobrien case GNU_OS_HURD: 554133359Sobrien if (file_printf(ms, "Hurd") == -1) 555276577Sdelphij return 1; 556133359Sobrien break; 557133359Sobrien case GNU_OS_SOLARIS: 558133359Sobrien if (file_printf(ms, "Solaris") == -1) 559276577Sdelphij return 1; 560133359Sobrien break; 561186690Sobrien case GNU_OS_KFREEBSD: 562186690Sobrien if (file_printf(ms, "kFreeBSD") == -1) 563276577Sdelphij return 1; 564186690Sobrien break; 565186690Sobrien case GNU_OS_KNETBSD: 566186690Sobrien if (file_printf(ms, "kNetBSD") == -1) 567276577Sdelphij return 1; 568186690Sobrien break; 569133359Sobrien default: 570133359Sobrien if (file_printf(ms, "<unknown>") == -1) 571276577Sdelphij return 1; 572133359Sobrien } 573186690Sobrien if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]), 574186690Sobrien elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1) 575276577Sdelphij return 1; 576276577Sdelphij return 1; 577133359Sobrien } 578133359Sobrien 579276577Sdelphij if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { 580276577Sdelphij if (type == NT_NETBSD_VERSION && descsz == 4) { 581276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 582276577Sdelphij do_note_netbsd_version(ms, swap, &nbuf[doff]); 583276577Sdelphij return 1; 584276577Sdelphij } 585226048Sobrien } 586226048Sobrien 587276577Sdelphij if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) { 588276577Sdelphij if (type == NT_FREEBSD_VERSION && descsz == 4) { 589276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 590276577Sdelphij do_note_freebsd_version(ms, swap, &nbuf[doff]); 591276577Sdelphij return 1; 592276577Sdelphij } 593276577Sdelphij } 594276577Sdelphij 595276577Sdelphij if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && 596276577Sdelphij type == NT_OPENBSD_VERSION && descsz == 4) { 597276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 598276577Sdelphij if (file_printf(ms, ", for OpenBSD") == -1) 599276577Sdelphij return 1; 600276577Sdelphij /* Content of note is always 0 */ 601276577Sdelphij return 1; 602276577Sdelphij } 603276577Sdelphij 604276577Sdelphij if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 && 605276577Sdelphij type == NT_DRAGONFLY_VERSION && descsz == 4) { 606276577Sdelphij uint32_t desc; 607276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 608276577Sdelphij if (file_printf(ms, ", for DragonFly") == -1) 609276577Sdelphij return 1; 610276577Sdelphij (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 611276577Sdelphij desc = elf_getu32(swap, desc); 612276577Sdelphij if (file_printf(ms, " %d.%d.%d", desc / 100000, 613276577Sdelphij desc / 10000 % 10, desc % 10000) == -1) 614276577Sdelphij return 1; 615276577Sdelphij return 1; 616276577Sdelphij } 617276577Sdelphij return 0; 618276577Sdelphij} 619276577Sdelphij 620276577Sdelphijprivate int 621276577Sdelphijdo_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 622276577Sdelphij int swap, uint32_t namesz, uint32_t descsz, 623276577Sdelphij size_t noff, size_t doff, int *flags) 624276577Sdelphij{ 625267843Sdelphij if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 && 626276577Sdelphij type == NT_NETBSD_PAX && descsz == 4) { 627267843Sdelphij static const char *pax[] = { 628267843Sdelphij "+mprotect", 629267843Sdelphij "-mprotect", 630267843Sdelphij "+segvguard", 631267843Sdelphij "-segvguard", 632267843Sdelphij "+ASLR", 633267843Sdelphij "-ASLR", 634267843Sdelphij }; 635133359Sobrien uint32_t desc; 636267843Sdelphij size_t i; 637267843Sdelphij int did = 0; 638267843Sdelphij 639276577Sdelphij *flags |= FLAGS_DID_NETBSD_PAX; 640133359Sobrien (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 641186690Sobrien desc = elf_getu32(swap, desc); 642133359Sobrien 643267843Sdelphij if (desc && file_printf(ms, ", PaX: ") == -1) 644276577Sdelphij return 1; 645133359Sobrien 646267843Sdelphij for (i = 0; i < __arraycount(pax); i++) { 647284237Sdelphij if (((1 << (int)i) & desc) == 0) 648267843Sdelphij continue; 649267843Sdelphij if (file_printf(ms, "%s%s", did++ ? "," : "", 650267843Sdelphij pax[i]) == -1) 651276577Sdelphij return 1; 652133359Sobrien } 653276577Sdelphij return 1; 654133359Sobrien } 655276577Sdelphij return 0; 656276577Sdelphij} 65768349Sobrien 658276577Sdelphijprivate int 659276577Sdelphijdo_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 660276577Sdelphij int swap, uint32_t namesz, uint32_t descsz, 661276577Sdelphij size_t noff, size_t doff, int *flags, size_t size, int clazz) 662276577Sdelphij{ 663276577Sdelphij#ifdef ELFCORE 664276577Sdelphij int os_style = -1; 665133359Sobrien /* 666133359Sobrien * Sigh. The 2.0.36 kernel in Debian 2.1, at 667133359Sobrien * least, doesn't correctly implement name 668133359Sobrien * sections, in core dumps, as specified by 669133359Sobrien * the "Program Linking" section of "UNIX(R) System 670133359Sobrien * V Release 4 Programmer's Guide: ANSI C and 671133359Sobrien * Programming Support Tools", because my copy 672133359Sobrien * clearly says "The first 'namesz' bytes in 'name' 673133359Sobrien * contain a *null-terminated* [emphasis mine] 674133359Sobrien * character representation of the entry's owner 675133359Sobrien * or originator", but the 2.0.36 kernel code 676133359Sobrien * doesn't include the terminating null in the 677133359Sobrien * name.... 678133359Sobrien */ 679133359Sobrien if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) || 680133359Sobrien (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) { 681133359Sobrien os_style = OS_STYLE_SVR4; 682133359Sobrien } 683133359Sobrien 684133359Sobrien if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) { 685133359Sobrien os_style = OS_STYLE_FREEBSD; 686133359Sobrien } 687133359Sobrien 688133359Sobrien if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11) 689133359Sobrien == 0)) { 690133359Sobrien os_style = OS_STYLE_NETBSD; 691133359Sobrien } 692133359Sobrien 693175296Sobrien if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) { 694169942Sobrien if (file_printf(ms, ", %s-style", os_style_names[os_style]) 695169942Sobrien == -1) 696276577Sdelphij return 1; 697175296Sobrien *flags |= FLAGS_DID_CORE_STYLE; 698159764Sobrien } 699133359Sobrien 700159764Sobrien switch (os_style) { 701159764Sobrien case OS_STYLE_NETBSD: 702276577Sdelphij if (type == NT_NETBSD_CORE_PROCINFO) { 703276577Sdelphij char sbuf[512]; 704159764Sobrien uint32_t signo; 705159764Sobrien /* 706159764Sobrien * Extract the program name. It is at 707159764Sobrien * offset 0x7c, and is up to 32-bytes, 708159764Sobrien * including the terminating NUL. 709159764Sobrien */ 710159764Sobrien if (file_printf(ms, ", from '%.31s'", 711276577Sdelphij file_printable(sbuf, sizeof(sbuf), 712276577Sdelphij (const char *)&nbuf[doff + 0x7c])) == -1) 713276577Sdelphij return 1; 714159764Sobrien 715159764Sobrien /* 716159764Sobrien * Extract the signal number. It is at 717159764Sobrien * offset 0x08. 718159764Sobrien */ 719159764Sobrien (void)memcpy(&signo, &nbuf[doff + 0x08], 720159764Sobrien sizeof(signo)); 721159764Sobrien if (file_printf(ms, " (signal %u)", 722186690Sobrien elf_getu32(swap, signo)) == -1) 723276577Sdelphij return 1; 724175296Sobrien *flags |= FLAGS_DID_CORE; 725276577Sdelphij return 1; 726159764Sobrien } 727159764Sobrien break; 728133359Sobrien 729159764Sobrien default: 730276577Sdelphij if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) { 731159764Sobrien size_t i, j; 732159764Sobrien unsigned char c; 733159764Sobrien /* 734159764Sobrien * Extract the program name. We assume 735159764Sobrien * it to be 16 characters (that's what it 736159764Sobrien * is in SunOS 5.x and Linux). 737159764Sobrien * 738159764Sobrien * Unfortunately, it's at a different offset 739175296Sobrien * in various OSes, so try multiple offsets. 740159764Sobrien * If the characters aren't all printable, 741159764Sobrien * reject it. 742159764Sobrien */ 743159764Sobrien for (i = 0; i < NOFFSETS; i++) { 744175296Sobrien unsigned char *cname, *cp; 745159764Sobrien size_t reloffset = prpsoffsets(i); 746159764Sobrien size_t noffset = doff + reloffset; 747226048Sobrien size_t k; 748159764Sobrien for (j = 0; j < 16; j++, noffset++, 749159764Sobrien reloffset++) { 75068349Sobrien /* 751159764Sobrien * Make sure we're not past 752159764Sobrien * the end of the buffer; if 753159764Sobrien * we are, just give up. 75468349Sobrien */ 755159764Sobrien if (noffset >= size) 756133359Sobrien goto tryanother; 757159764Sobrien 758133359Sobrien /* 759159764Sobrien * Make sure we're not past 760159764Sobrien * the end of the contents; 761159764Sobrien * if we are, this obviously 762159764Sobrien * isn't the right offset. 763133359Sobrien */ 764159764Sobrien if (reloffset >= descsz) 765133359Sobrien goto tryanother; 766159764Sobrien 767159764Sobrien c = nbuf[noffset]; 768159764Sobrien if (c == '\0') { 769159764Sobrien /* 770159764Sobrien * A '\0' at the 771159764Sobrien * beginning is 772159764Sobrien * obviously wrong. 773159764Sobrien * Any other '\0' 774159764Sobrien * means we're done. 775159764Sobrien */ 776159764Sobrien if (j == 0) 777159764Sobrien goto tryanother; 778159764Sobrien else 779159764Sobrien break; 780159764Sobrien } else { 781159764Sobrien /* 782159764Sobrien * A nonprintable 783159764Sobrien * character is also 784159764Sobrien * wrong. 785159764Sobrien */ 786159764Sobrien if (!isprint(c) || isquote(c)) 787159764Sobrien goto tryanother; 788159764Sobrien } 78968349Sobrien } 790159764Sobrien /* 791159764Sobrien * Well, that worked. 792159764Sobrien */ 793226048Sobrien 794226048Sobrien /* 795226048Sobrien * Try next offsets, in case this match is 796226048Sobrien * in the middle of a string. 797226048Sobrien */ 798276577Sdelphij for (k = i + 1 ; k < NOFFSETS; k++) { 799226048Sobrien size_t no; 800226048Sobrien int adjust = 1; 801226048Sobrien if (prpsoffsets(k) >= prpsoffsets(i)) 802226048Sobrien continue; 803226048Sobrien for (no = doff + prpsoffsets(k); 804226048Sobrien no < doff + prpsoffsets(i); no++) 805226048Sobrien adjust = adjust 806226048Sobrien && isprint(nbuf[no]); 807226048Sobrien if (adjust) 808226048Sobrien i = k; 809226048Sobrien } 810226048Sobrien 811175296Sobrien cname = (unsigned char *) 812175296Sobrien &nbuf[doff + prpsoffsets(i)]; 813175296Sobrien for (cp = cname; *cp && isprint(*cp); cp++) 814175296Sobrien continue; 815186690Sobrien /* 816186690Sobrien * Linux apparently appends a space at the end 817186690Sobrien * of the command line: remove it. 818186690Sobrien */ 819186690Sobrien while (cp > cname && isspace(cp[-1])) 820175296Sobrien cp--; 821175296Sobrien if (file_printf(ms, ", from '%.*s'", 822175296Sobrien (int)(cp - cname), cname) == -1) 823276577Sdelphij return 1; 824175296Sobrien *flags |= FLAGS_DID_CORE; 825276577Sdelphij return 1; 826133359Sobrien 827159764Sobrien tryanother: 828159764Sobrien ; 829159764Sobrien } 83068349Sobrien } 831159764Sobrien break; 83268349Sobrien } 833133359Sobrien#endif 834276577Sdelphij return 0; 835276577Sdelphij} 836276577Sdelphij 837298192Sdelphijprivate off_t 838298192Sdelphijget_offset_from_virtaddr(struct magic_set *ms, int swap, int clazz, int fd, 839298192Sdelphij off_t off, int num, off_t fsize, uint64_t virtaddr) 840298192Sdelphij{ 841298192Sdelphij Elf32_Phdr ph32; 842298192Sdelphij Elf64_Phdr ph64; 843298192Sdelphij 844298192Sdelphij /* 845298192Sdelphij * Loop through all the program headers and find the header with 846298192Sdelphij * virtual address in which the "virtaddr" belongs to. 847298192Sdelphij */ 848298192Sdelphij for ( ; num; num--) { 849298192Sdelphij if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) { 850298192Sdelphij file_badread(ms); 851298192Sdelphij return -1; 852298192Sdelphij } 853298192Sdelphij off += xph_sizeof; 854298192Sdelphij 855298192Sdelphij if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 856298192Sdelphij /* Perhaps warn here */ 857298192Sdelphij continue; 858298192Sdelphij } 859298192Sdelphij 860298192Sdelphij if (virtaddr >= xph_vaddr && virtaddr < xph_vaddr + xph_filesz) 861298192Sdelphij return xph_offset + (virtaddr - xph_vaddr); 862298192Sdelphij } 863298192Sdelphij return 0; 864298192Sdelphij} 865298192Sdelphij 866276577Sdelphijprivate size_t 867298192Sdelphijget_string_on_virtaddr(struct magic_set *ms, 868298192Sdelphij int swap, int clazz, int fd, off_t ph_off, int ph_num, 869298192Sdelphij off_t fsize, uint64_t virtaddr, char *buf, ssize_t buflen) 870298192Sdelphij{ 871298192Sdelphij char *bptr; 872298192Sdelphij off_t offset; 873298192Sdelphij 874298192Sdelphij if (buflen == 0) 875298192Sdelphij return 0; 876298192Sdelphij 877298192Sdelphij offset = get_offset_from_virtaddr(ms, swap, clazz, fd, ph_off, ph_num, 878298192Sdelphij fsize, virtaddr); 879298192Sdelphij if ((buflen = pread(fd, buf, buflen, offset)) <= 0) { 880298192Sdelphij file_badread(ms); 881298192Sdelphij return 0; 882298192Sdelphij } 883298192Sdelphij 884298192Sdelphij buf[buflen - 1] = '\0'; 885298192Sdelphij 886298192Sdelphij /* We expect only printable characters, so return if buffer contains 887298192Sdelphij * non-printable character before the '\0' or just '\0'. */ 888298192Sdelphij for (bptr = buf; *bptr && isprint((unsigned char)*bptr); bptr++) 889298192Sdelphij continue; 890298192Sdelphij if (*bptr != '\0') 891298192Sdelphij return 0; 892298192Sdelphij 893298192Sdelphij return bptr - buf; 894298192Sdelphij} 895298192Sdelphij 896298192Sdelphij 897298192Sdelphijprivate int 898298192Sdelphijdo_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 899298192Sdelphij int swap, uint32_t namesz __attribute__((__unused__)), 900298192Sdelphij uint32_t descsz __attribute__((__unused__)), 901298192Sdelphij size_t noff __attribute__((__unused__)), size_t doff, 902298192Sdelphij int *flags, size_t size __attribute__((__unused__)), int clazz, 903298192Sdelphij int fd, off_t ph_off, int ph_num, off_t fsize) 904298192Sdelphij{ 905298192Sdelphij#ifdef ELFCORE 906298192Sdelphij Aux32Info auxv32; 907298192Sdelphij Aux64Info auxv64; 908298192Sdelphij size_t elsize = xauxv_sizeof; 909298192Sdelphij const char *tag; 910298192Sdelphij int is_string; 911298192Sdelphij size_t nval; 912298192Sdelphij 913298192Sdelphij if (type != NT_AUXV || (*flags & FLAGS_IS_CORE) == 0) 914298192Sdelphij return 0; 915298192Sdelphij 916298192Sdelphij *flags |= FLAGS_DID_AUXV; 917298192Sdelphij 918298192Sdelphij nval = 0; 919298192Sdelphij for (size_t off = 0; off + elsize <= descsz; off += elsize) { 920298192Sdelphij (void)memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof); 921298192Sdelphij /* Limit processing to 50 vector entries to prevent DoS */ 922298192Sdelphij if (nval++ >= 50) { 923298192Sdelphij file_error(ms, 0, "Too many ELF Auxv elements"); 924298192Sdelphij return 1; 925298192Sdelphij } 926298192Sdelphij 927298192Sdelphij switch(xauxv_type) { 928298192Sdelphij case AT_LINUX_EXECFN: 929298192Sdelphij is_string = 1; 930298192Sdelphij tag = "execfn"; 931298192Sdelphij break; 932298192Sdelphij case AT_LINUX_PLATFORM: 933298192Sdelphij is_string = 1; 934298192Sdelphij tag = "platform"; 935298192Sdelphij break; 936298192Sdelphij case AT_LINUX_UID: 937298192Sdelphij is_string = 0; 938298192Sdelphij tag = "real uid"; 939298192Sdelphij break; 940298192Sdelphij case AT_LINUX_GID: 941298192Sdelphij is_string = 0; 942298192Sdelphij tag = "real gid"; 943298192Sdelphij break; 944298192Sdelphij case AT_LINUX_EUID: 945298192Sdelphij is_string = 0; 946298192Sdelphij tag = "effective uid"; 947298192Sdelphij break; 948298192Sdelphij case AT_LINUX_EGID: 949298192Sdelphij is_string = 0; 950298192Sdelphij tag = "effective gid"; 951298192Sdelphij break; 952298192Sdelphij default: 953298192Sdelphij is_string = 0; 954298192Sdelphij tag = NULL; 955298192Sdelphij break; 956298192Sdelphij } 957298192Sdelphij 958298192Sdelphij if (tag == NULL) 959298192Sdelphij continue; 960298192Sdelphij 961298192Sdelphij if (is_string) { 962298192Sdelphij char buf[256]; 963298192Sdelphij ssize_t buflen; 964298192Sdelphij buflen = get_string_on_virtaddr(ms, swap, clazz, fd, 965298192Sdelphij ph_off, ph_num, fsize, xauxv_val, buf, sizeof(buf)); 966298192Sdelphij 967298192Sdelphij if (buflen == 0) 968298192Sdelphij continue; 969298192Sdelphij 970298192Sdelphij if (file_printf(ms, ", %s: '%s'", tag, buf) == -1) 971298192Sdelphij return 0; 972298192Sdelphij } else { 973298192Sdelphij if (file_printf(ms, ", %s: %d", tag, (int) xauxv_val) 974298192Sdelphij == -1) 975298192Sdelphij return 0; 976298192Sdelphij } 977298192Sdelphij } 978298192Sdelphij return 1; 979298192Sdelphij#else 980298192Sdelphij return 0; 981298192Sdelphij#endif 982298192Sdelphij} 983298192Sdelphij 984298192Sdelphijprivate size_t 985276577Sdelphijdonote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, 986298192Sdelphij int clazz, int swap, size_t align, int *flags, uint16_t *notecount, 987298192Sdelphij int fd, off_t ph_off, int ph_num, off_t fsize) 988276577Sdelphij{ 989276577Sdelphij Elf32_Nhdr nh32; 990276577Sdelphij Elf64_Nhdr nh64; 991276577Sdelphij size_t noff, doff; 992276577Sdelphij uint32_t namesz, descsz; 993276577Sdelphij unsigned char *nbuf = CAST(unsigned char *, vbuf); 994276577Sdelphij 995276577Sdelphij if (*notecount == 0) 996276577Sdelphij return 0; 997276577Sdelphij --*notecount; 998276577Sdelphij 999276577Sdelphij if (xnh_sizeof + offset > size) { 1000276577Sdelphij /* 1001276577Sdelphij * We're out of note headers. 1002276577Sdelphij */ 1003276577Sdelphij return xnh_sizeof + offset; 1004276577Sdelphij } 1005276577Sdelphij 1006276577Sdelphij (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); 1007276577Sdelphij offset += xnh_sizeof; 1008276577Sdelphij 1009276577Sdelphij namesz = xnh_namesz; 1010276577Sdelphij descsz = xnh_descsz; 1011298192Sdelphij 1012276577Sdelphij if ((namesz == 0) && (descsz == 0)) { 1013276577Sdelphij /* 1014276577Sdelphij * We're out of note headers. 1015276577Sdelphij */ 1016276577Sdelphij return (offset >= size) ? offset : size; 1017276577Sdelphij } 1018276577Sdelphij 1019276577Sdelphij if (namesz & 0x80000000) { 1020276577Sdelphij (void)file_printf(ms, ", bad note name size 0x%lx", 1021276577Sdelphij (unsigned long)namesz); 1022276577Sdelphij return 0; 1023276577Sdelphij } 1024276577Sdelphij 1025276577Sdelphij if (descsz & 0x80000000) { 1026276577Sdelphij (void)file_printf(ms, ", bad note description size 0x%lx", 1027276577Sdelphij (unsigned long)descsz); 1028276577Sdelphij return 0; 1029276577Sdelphij } 1030276577Sdelphij 1031276577Sdelphij noff = offset; 1032276577Sdelphij doff = ELF_ALIGN(offset + namesz); 1033276577Sdelphij 1034276577Sdelphij if (offset + namesz > size) { 1035276577Sdelphij /* 1036276577Sdelphij * We're past the end of the buffer. 1037276577Sdelphij */ 1038276577Sdelphij return doff; 1039276577Sdelphij } 1040276577Sdelphij 1041276577Sdelphij offset = ELF_ALIGN(doff + descsz); 1042276577Sdelphij if (doff + descsz > size) { 1043276577Sdelphij /* 1044276577Sdelphij * We're past the end of the buffer. 1045276577Sdelphij */ 1046276577Sdelphij return (offset >= size) ? offset : size; 1047276577Sdelphij } 1048276577Sdelphij 1049298192Sdelphij 1050276577Sdelphij if ((*flags & FLAGS_DID_OS_NOTE) == 0) { 1051276577Sdelphij if (do_os_note(ms, nbuf, xnh_type, swap, 1052276577Sdelphij namesz, descsz, noff, doff, flags)) 1053298192Sdelphij return offset; 1054276577Sdelphij } 1055276577Sdelphij 1056276577Sdelphij if ((*flags & FLAGS_DID_BUILD_ID) == 0) { 1057276577Sdelphij if (do_bid_note(ms, nbuf, xnh_type, swap, 1058276577Sdelphij namesz, descsz, noff, doff, flags)) 1059298192Sdelphij return offset; 1060276577Sdelphij } 1061276577Sdelphij 1062276577Sdelphij if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) { 1063276577Sdelphij if (do_pax_note(ms, nbuf, xnh_type, swap, 1064276577Sdelphij namesz, descsz, noff, doff, flags)) 1065298192Sdelphij return offset; 1066276577Sdelphij } 1067276577Sdelphij 1068276577Sdelphij if ((*flags & FLAGS_DID_CORE) == 0) { 1069276577Sdelphij if (do_core_note(ms, nbuf, xnh_type, swap, 1070276577Sdelphij namesz, descsz, noff, doff, flags, size, clazz)) 1071298192Sdelphij return offset; 1072276577Sdelphij } 1073276577Sdelphij 1074298192Sdelphij if ((*flags & FLAGS_DID_AUXV) == 0) { 1075298192Sdelphij if (do_auxv_note(ms, nbuf, xnh_type, swap, 1076298192Sdelphij namesz, descsz, noff, doff, flags, size, clazz, 1077298192Sdelphij fd, ph_off, ph_num, fsize)) 1078298192Sdelphij return offset; 1079298192Sdelphij } 1080298192Sdelphij 1081276577Sdelphij if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { 1082276577Sdelphij if (descsz > 100) 1083276577Sdelphij descsz = 100; 1084276577Sdelphij switch (xnh_type) { 1085276577Sdelphij case NT_NETBSD_VERSION: 1086298192Sdelphij return offset; 1087276577Sdelphij case NT_NETBSD_MARCH: 1088276577Sdelphij if (*flags & FLAGS_DID_NETBSD_MARCH) 1089298192Sdelphij return offset; 1090276577Sdelphij *flags |= FLAGS_DID_NETBSD_MARCH; 1091276577Sdelphij if (file_printf(ms, ", compiled for: %.*s", 1092276577Sdelphij (int)descsz, (const char *)&nbuf[doff]) == -1) 1093298192Sdelphij return offset; 1094276577Sdelphij break; 1095276577Sdelphij case NT_NETBSD_CMODEL: 1096276577Sdelphij if (*flags & FLAGS_DID_NETBSD_CMODEL) 1097298192Sdelphij return offset; 1098276577Sdelphij *flags |= FLAGS_DID_NETBSD_CMODEL; 1099276577Sdelphij if (file_printf(ms, ", compiler model: %.*s", 1100276577Sdelphij (int)descsz, (const char *)&nbuf[doff]) == -1) 1101298192Sdelphij return offset; 1102276577Sdelphij break; 1103276577Sdelphij default: 1104276577Sdelphij if (*flags & FLAGS_DID_NETBSD_UNKNOWN) 1105298192Sdelphij return offset; 1106276577Sdelphij *flags |= FLAGS_DID_NETBSD_UNKNOWN; 1107276577Sdelphij if (file_printf(ms, ", note=%u", xnh_type) == -1) 1108298192Sdelphij return offset; 1109276577Sdelphij break; 1110276577Sdelphij } 1111298192Sdelphij return offset; 1112276577Sdelphij } 1113276577Sdelphij 1114133359Sobrien return offset; 111568349Sobrien} 111668349Sobrien 1117186690Sobrien/* SunOS 5.x hardware capability descriptions */ 1118186690Sobrientypedef struct cap_desc { 1119186690Sobrien uint64_t cd_mask; 1120186690Sobrien const char *cd_name; 1121186690Sobrien} cap_desc_t; 1122186690Sobrien 1123186690Sobrienstatic const cap_desc_t cap_desc_sparc[] = { 1124186690Sobrien { AV_SPARC_MUL32, "MUL32" }, 1125186690Sobrien { AV_SPARC_DIV32, "DIV32" }, 1126186690Sobrien { AV_SPARC_FSMULD, "FSMULD" }, 1127186690Sobrien { AV_SPARC_V8PLUS, "V8PLUS" }, 1128186690Sobrien { AV_SPARC_POPC, "POPC" }, 1129186690Sobrien { AV_SPARC_VIS, "VIS" }, 1130186690Sobrien { AV_SPARC_VIS2, "VIS2" }, 1131186690Sobrien { AV_SPARC_ASI_BLK_INIT, "ASI_BLK_INIT" }, 1132186690Sobrien { AV_SPARC_FMAF, "FMAF" }, 1133186690Sobrien { AV_SPARC_FJFMAU, "FJFMAU" }, 1134186690Sobrien { AV_SPARC_IMA, "IMA" }, 1135186690Sobrien { 0, NULL } 1136186690Sobrien}; 1137186690Sobrien 1138186690Sobrienstatic const cap_desc_t cap_desc_386[] = { 1139186690Sobrien { AV_386_FPU, "FPU" }, 1140186690Sobrien { AV_386_TSC, "TSC" }, 1141186690Sobrien { AV_386_CX8, "CX8" }, 1142186690Sobrien { AV_386_SEP, "SEP" }, 1143186690Sobrien { AV_386_AMD_SYSC, "AMD_SYSC" }, 1144186690Sobrien { AV_386_CMOV, "CMOV" }, 1145186690Sobrien { AV_386_MMX, "MMX" }, 1146186690Sobrien { AV_386_AMD_MMX, "AMD_MMX" }, 1147186690Sobrien { AV_386_AMD_3DNow, "AMD_3DNow" }, 1148186690Sobrien { AV_386_AMD_3DNowx, "AMD_3DNowx" }, 1149186690Sobrien { AV_386_FXSR, "FXSR" }, 1150186690Sobrien { AV_386_SSE, "SSE" }, 1151186690Sobrien { AV_386_SSE2, "SSE2" }, 1152186690Sobrien { AV_386_PAUSE, "PAUSE" }, 1153186690Sobrien { AV_386_SSE3, "SSE3" }, 1154186690Sobrien { AV_386_MON, "MON" }, 1155186690Sobrien { AV_386_CX16, "CX16" }, 1156186690Sobrien { AV_386_AHF, "AHF" }, 1157186690Sobrien { AV_386_TSCP, "TSCP" }, 1158186690Sobrien { AV_386_AMD_SSE4A, "AMD_SSE4A" }, 1159186690Sobrien { AV_386_POPCNT, "POPCNT" }, 1160186690Sobrien { AV_386_AMD_LZCNT, "AMD_LZCNT" }, 1161186690Sobrien { AV_386_SSSE3, "SSSE3" }, 1162186690Sobrien { AV_386_SSE4_1, "SSE4.1" }, 1163186690Sobrien { AV_386_SSE4_2, "SSE4.2" }, 1164186690Sobrien { 0, NULL } 1165186690Sobrien}; 1166186690Sobrien 1167133359Sobrienprivate int 1168186690Sobriendoshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, 1169276577Sdelphij size_t size, off_t fsize, int mach, int strtab, int *flags, 1170276577Sdelphij uint16_t *notecount) 117168349Sobrien{ 1172133359Sobrien Elf32_Shdr sh32; 1173133359Sobrien Elf64_Shdr sh64; 1174159764Sobrien int stripped = 1; 1175275666Sdelphij size_t nbadcap = 0; 1176159764Sobrien void *nbuf; 1177267843Sdelphij off_t noff, coff, name_off; 1178186690Sobrien uint64_t cap_hw1 = 0; /* SunOS 5.x hardware capabilites */ 1179186690Sobrien uint64_t cap_sf1 = 0; /* SunOS 5.x software capabilites */ 1180267843Sdelphij char name[50]; 1181276577Sdelphij ssize_t namesize; 1182133359Sobrien 1183159764Sobrien if (size != xsh_sizeof) { 1184133359Sobrien if (file_printf(ms, ", corrupted section header size") == -1) 1185133359Sobrien return -1; 1186133359Sobrien return 0; 1187133359Sobrien } 1188133359Sobrien 1189267843Sdelphij /* Read offset of name section to be able to read section names later */ 1190284237Sdelphij if (pread(fd, xsh_addr, xsh_sizeof, CAST(off_t, (off + size * strtab))) 1191284237Sdelphij < (ssize_t)xsh_sizeof) { 1192267843Sdelphij file_badread(ms); 1193267843Sdelphij return -1; 1194267843Sdelphij } 1195267843Sdelphij name_off = xsh_offset; 1196267843Sdelphij 1197133359Sobrien for ( ; num; num--) { 1198267843Sdelphij /* Read the name of this section. */ 1199276577Sdelphij if ((namesize = pread(fd, name, sizeof(name) - 1, name_off + xsh_name)) == -1) { 1200267843Sdelphij file_badread(ms); 1201226048Sobrien return -1; 1202226048Sobrien } 1203276577Sdelphij name[namesize] = '\0'; 1204267843Sdelphij if (strcmp(name, ".debug_info") == 0) 1205267843Sdelphij stripped = 0; 1206267843Sdelphij 1207276577Sdelphij if (pread(fd, xsh_addr, xsh_sizeof, off) < (ssize_t)xsh_sizeof) { 1208133359Sobrien file_badread(ms); 1209133359Sobrien return -1; 1210133359Sobrien } 1211226048Sobrien off += size; 1212226048Sobrien 1213226048Sobrien /* Things we can determine before we seek */ 1214159764Sobrien switch (xsh_type) { 1215159764Sobrien case SHT_SYMTAB: 1216159764Sobrien#if 0 1217159764Sobrien case SHT_DYNSYM: 1218159764Sobrien#endif 1219159764Sobrien stripped = 0; 1220159764Sobrien break; 1221226048Sobrien default: 1222275698Sdelphij if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) { 1223226048Sobrien /* Perhaps warn here */ 1224226048Sobrien continue; 1225226048Sobrien } 1226226048Sobrien break; 1227226048Sobrien } 1228226048Sobrien 1229287453Sdelphij 1230226048Sobrien /* Things we can determine when we seek */ 1231226048Sobrien switch (xsh_type) { 1232159764Sobrien case SHT_NOTE: 1233288143Sdelphij if ((uintmax_t)(xsh_size + xsh_offset) > 1234288143Sdelphij (uintmax_t)fsize) { 1235287453Sdelphij if (file_printf(ms, 1236288143Sdelphij ", note offset/size 0x%" INTMAX_T_FORMAT 1237288143Sdelphij "x+0x%" INTMAX_T_FORMAT "x exceeds" 1238288143Sdelphij " file size 0x%" INTMAX_T_FORMAT "x", 1239288143Sdelphij (uintmax_t)xsh_offset, (uintmax_t)xsh_size, 1240288143Sdelphij (uintmax_t)fsize) == -1) 1241287453Sdelphij return -1; 1242287453Sdelphij return 0; 1243287453Sdelphij } 1244267843Sdelphij if ((nbuf = malloc(xsh_size)) == NULL) { 1245159764Sobrien file_error(ms, errno, "Cannot allocate memory" 1246159764Sobrien " for note"); 1247159764Sobrien return -1; 1248159764Sobrien } 1249288143Sdelphij if (pread(fd, nbuf, xsh_size, xsh_offset) < 1250288143Sdelphij (ssize_t)xsh_size) { 1251159764Sobrien file_badread(ms); 1252159764Sobrien free(nbuf); 1253159764Sobrien return -1; 1254159764Sobrien } 1255159764Sobrien 1256159764Sobrien noff = 0; 1257159764Sobrien for (;;) { 1258191736Sobrien if (noff >= (off_t)xsh_size) 1259159764Sobrien break; 1260159764Sobrien noff = donote(ms, nbuf, (size_t)noff, 1261298192Sdelphij xsh_size, clazz, swap, 4, flags, notecount, 1262298192Sdelphij fd, 0, 0, 0); 1263159764Sobrien if (noff == 0) 1264159764Sobrien break; 1265159764Sobrien } 1266159764Sobrien free(nbuf); 1267159764Sobrien break; 1268186690Sobrien case SHT_SUNW_cap: 1269267843Sdelphij switch (mach) { 1270267843Sdelphij case EM_SPARC: 1271267843Sdelphij case EM_SPARCV9: 1272267843Sdelphij case EM_IA_64: 1273267843Sdelphij case EM_386: 1274267843Sdelphij case EM_AMD64: 1275267843Sdelphij break; 1276267843Sdelphij default: 1277267843Sdelphij goto skip; 1278267843Sdelphij } 1279267843Sdelphij 1280275666Sdelphij if (nbadcap > 5) 1281275666Sdelphij break; 1282267843Sdelphij if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) { 1283226048Sobrien file_badseek(ms); 1284186690Sobrien return -1; 1285186690Sobrien } 1286186690Sobrien coff = 0; 1287186690Sobrien for (;;) { 1288186690Sobrien Elf32_Cap cap32; 1289186690Sobrien Elf64_Cap cap64; 1290191736Sobrien char cbuf[/*CONSTCOND*/ 1291191736Sobrien MAX(sizeof cap32, sizeof cap64)]; 1292226048Sobrien if ((coff += xcap_sizeof) > (off_t)xsh_size) 1293186690Sobrien break; 1294186690Sobrien if (read(fd, cbuf, (size_t)xcap_sizeof) != 1295186690Sobrien (ssize_t)xcap_sizeof) { 1296186690Sobrien file_badread(ms); 1297186690Sobrien return -1; 1298186690Sobrien } 1299267843Sdelphij if (cbuf[0] == 'A') { 1300267843Sdelphij#ifdef notyet 1301267843Sdelphij char *p = cbuf + 1; 1302267843Sdelphij uint32_t len, tag; 1303267843Sdelphij memcpy(&len, p, sizeof(len)); 1304267843Sdelphij p += 4; 1305267843Sdelphij len = getu32(swap, len); 1306267843Sdelphij if (memcmp("gnu", p, 3) != 0) { 1307267843Sdelphij if (file_printf(ms, 1308267843Sdelphij ", unknown capability %.3s", p) 1309267843Sdelphij == -1) 1310267843Sdelphij return -1; 1311267843Sdelphij break; 1312267843Sdelphij } 1313267843Sdelphij p += strlen(p) + 1; 1314267843Sdelphij tag = *p++; 1315267843Sdelphij memcpy(&len, p, sizeof(len)); 1316267843Sdelphij p += 4; 1317267843Sdelphij len = getu32(swap, len); 1318267843Sdelphij if (tag != 1) { 1319267843Sdelphij if (file_printf(ms, ", unknown gnu" 1320267843Sdelphij " capability tag %d", tag) 1321267843Sdelphij == -1) 1322267843Sdelphij return -1; 1323267843Sdelphij break; 1324267843Sdelphij } 1325267843Sdelphij // gnu attributes 1326267843Sdelphij#endif 1327267843Sdelphij break; 1328267843Sdelphij } 1329186690Sobrien (void)memcpy(xcap_addr, cbuf, xcap_sizeof); 1330186690Sobrien switch (xcap_tag) { 1331186690Sobrien case CA_SUNW_NULL: 1332186690Sobrien break; 1333186690Sobrien case CA_SUNW_HW_1: 1334186690Sobrien cap_hw1 |= xcap_val; 1335186690Sobrien break; 1336186690Sobrien case CA_SUNW_SF_1: 1337186690Sobrien cap_sf1 |= xcap_val; 1338186690Sobrien break; 1339186690Sobrien default: 1340186690Sobrien if (file_printf(ms, 1341186690Sobrien ", with unknown capability " 1342226048Sobrien "0x%" INT64_T_FORMAT "x = 0x%" 1343226048Sobrien INT64_T_FORMAT "x", 1344191736Sobrien (unsigned long long)xcap_tag, 1345191736Sobrien (unsigned long long)xcap_val) == -1) 1346186690Sobrien return -1; 1347275666Sdelphij if (nbadcap++ > 2) 1348275666Sdelphij coff = xsh_size; 1349186690Sobrien break; 1350186690Sobrien } 1351186690Sobrien } 1352267843Sdelphij /*FALLTHROUGH*/ 1353267843Sdelphij skip: 1354226048Sobrien default: 1355226048Sobrien break; 1356133359Sobrien } 1357133359Sobrien } 1358267843Sdelphij 1359159764Sobrien if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1) 1360133359Sobrien return -1; 1361186690Sobrien if (cap_hw1) { 1362186690Sobrien const cap_desc_t *cdp; 1363186690Sobrien switch (mach) { 1364186690Sobrien case EM_SPARC: 1365186690Sobrien case EM_SPARC32PLUS: 1366186690Sobrien case EM_SPARCV9: 1367186690Sobrien cdp = cap_desc_sparc; 1368186690Sobrien break; 1369186690Sobrien case EM_386: 1370186690Sobrien case EM_IA_64: 1371186690Sobrien case EM_AMD64: 1372186690Sobrien cdp = cap_desc_386; 1373186690Sobrien break; 1374186690Sobrien default: 1375186690Sobrien cdp = NULL; 1376186690Sobrien break; 1377186690Sobrien } 1378186690Sobrien if (file_printf(ms, ", uses") == -1) 1379186690Sobrien return -1; 1380186690Sobrien if (cdp) { 1381186690Sobrien while (cdp->cd_name) { 1382186690Sobrien if (cap_hw1 & cdp->cd_mask) { 1383186690Sobrien if (file_printf(ms, 1384186690Sobrien " %s", cdp->cd_name) == -1) 1385186690Sobrien return -1; 1386186690Sobrien cap_hw1 &= ~cdp->cd_mask; 1387186690Sobrien } 1388186690Sobrien ++cdp; 1389186690Sobrien } 1390186690Sobrien if (cap_hw1) 1391186690Sobrien if (file_printf(ms, 1392226048Sobrien " unknown hardware capability 0x%" 1393226048Sobrien INT64_T_FORMAT "x", 1394191736Sobrien (unsigned long long)cap_hw1) == -1) 1395186690Sobrien return -1; 1396186690Sobrien } else { 1397186690Sobrien if (file_printf(ms, 1398226048Sobrien " hardware capability 0x%" INT64_T_FORMAT "x", 1399191736Sobrien (unsigned long long)cap_hw1) == -1) 1400186690Sobrien return -1; 1401186690Sobrien } 1402186690Sobrien } 1403186690Sobrien if (cap_sf1) { 1404186690Sobrien if (cap_sf1 & SF1_SUNW_FPUSED) { 1405186690Sobrien if (file_printf(ms, 1406186690Sobrien (cap_sf1 & SF1_SUNW_FPKNWN) 1407186690Sobrien ? ", uses frame pointer" 1408186690Sobrien : ", not known to use frame pointer") == -1) 1409186690Sobrien return -1; 1410186690Sobrien } 1411186690Sobrien cap_sf1 &= ~SF1_SUNW_MASK; 1412186690Sobrien if (cap_sf1) 1413186690Sobrien if (file_printf(ms, 1414226048Sobrien ", with unknown software capability 0x%" 1415226048Sobrien INT64_T_FORMAT "x", 1416191736Sobrien (unsigned long long)cap_sf1) == -1) 1417186690Sobrien return -1; 1418186690Sobrien } 1419133359Sobrien return 0; 1420133359Sobrien} 1421133359Sobrien 1422133359Sobrien/* 1423133359Sobrien * Look through the program headers of an executable image, searching 1424133359Sobrien * for a PT_INTERP section; if one is found, it's dynamically linked, 1425133359Sobrien * otherwise it's statically linked. 1426133359Sobrien */ 1427133359Sobrienprivate int 1428186690Sobriendophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 1429276577Sdelphij int num, size_t size, off_t fsize, int sh_num, int *flags, 1430276577Sdelphij uint16_t *notecount) 1431133359Sobrien{ 1432133359Sobrien Elf32_Phdr ph32; 1433133359Sobrien Elf64_Phdr ph64; 1434133359Sobrien const char *linking_style = "statically"; 1435276577Sdelphij const char *interp = ""; 1436133359Sobrien unsigned char nbuf[BUFSIZ]; 1437276577Sdelphij char ibuf[BUFSIZ]; 1438226048Sobrien ssize_t bufsize; 1439267843Sdelphij size_t offset, align, len; 1440169942Sobrien 1441159764Sobrien if (size != xph_sizeof) { 1442133359Sobrien if (file_printf(ms, ", corrupted program header size") == -1) 1443186690Sobrien return -1; 1444133359Sobrien return 0; 1445133359Sobrien } 1446169942Sobrien 1447133359Sobrien for ( ; num; num--) { 1448276577Sdelphij if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) { 1449267843Sdelphij file_badread(ms); 1450133359Sobrien return -1; 1451133359Sobrien } 1452169942Sobrien 1453226048Sobrien off += size; 1454276577Sdelphij bufsize = 0; 1455276577Sdelphij align = 4; 1456169942Sobrien 1457226048Sobrien /* Things we can determine before we seek */ 1458159764Sobrien switch (xph_type) { 1459133359Sobrien case PT_DYNAMIC: 1460133359Sobrien linking_style = "dynamically"; 1461133359Sobrien break; 1462276577Sdelphij case PT_NOTE: 1463276577Sdelphij if (sh_num) /* Did this through section headers */ 1464276577Sdelphij continue; 1465276577Sdelphij if (((align = xph_align) & 0x80000000UL) != 0 || 1466276577Sdelphij align < 4) { 1467276577Sdelphij if (file_printf(ms, 1468276577Sdelphij ", invalid note alignment 0x%lx", 1469276577Sdelphij (unsigned long)align) == -1) 1470276577Sdelphij return -1; 1471276577Sdelphij align = 4; 1472276577Sdelphij } 1473276577Sdelphij /*FALLTHROUGH*/ 1474133359Sobrien case PT_INTERP: 1475276577Sdelphij len = xph_filesz < sizeof(nbuf) ? xph_filesz 1476276577Sdelphij : sizeof(nbuf); 1477276577Sdelphij bufsize = pread(fd, nbuf, len, xph_offset); 1478276577Sdelphij if (bufsize == -1) { 1479276577Sdelphij file_badread(ms); 1480276577Sdelphij return -1; 1481276577Sdelphij } 1482133359Sobrien break; 1483226048Sobrien default: 1484275698Sdelphij if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 1485226048Sobrien /* Maybe warn here? */ 1486226048Sobrien continue; 1487226048Sobrien } 1488226048Sobrien break; 1489226048Sobrien } 1490226048Sobrien 1491226048Sobrien /* Things we can determine when we seek */ 1492226048Sobrien switch (xph_type) { 1493276577Sdelphij case PT_INTERP: 1494276577Sdelphij if (bufsize && nbuf[0]) { 1495276577Sdelphij nbuf[bufsize - 1] = '\0'; 1496276577Sdelphij interp = (const char *)nbuf; 1497276577Sdelphij } else 1498276577Sdelphij interp = "*empty*"; 1499276577Sdelphij break; 1500133359Sobrien case PT_NOTE: 1501133359Sobrien /* 1502133359Sobrien * This is a PT_NOTE section; loop through all the notes 1503133359Sobrien * in the section. 1504133359Sobrien */ 1505133359Sobrien offset = 0; 1506133359Sobrien for (;;) { 1507133359Sobrien if (offset >= (size_t)bufsize) 1508133359Sobrien break; 1509133359Sobrien offset = donote(ms, nbuf, offset, 1510186690Sobrien (size_t)bufsize, clazz, swap, align, 1511298192Sdelphij flags, notecount, fd, 0, 0, 0); 1512133359Sobrien if (offset == 0) 1513133359Sobrien break; 1514133359Sobrien } 1515133359Sobrien break; 1516175296Sobrien default: 1517175296Sobrien break; 1518133359Sobrien } 1519133359Sobrien } 1520276577Sdelphij if (file_printf(ms, ", %s linked", linking_style) 1521133359Sobrien == -1) 1522276577Sdelphij return -1; 1523276577Sdelphij if (interp[0]) 1524276577Sdelphij if (file_printf(ms, ", interpreter %s", 1525276577Sdelphij file_printable(ibuf, sizeof(ibuf), interp)) == -1) 1526276577Sdelphij return -1; 1527133359Sobrien return 0; 1528133359Sobrien} 1529133359Sobrien 1530133359Sobrien 1531133359Sobrienprotected int 1532133359Sobrienfile_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, 1533133359Sobrien size_t nbytes) 1534133359Sobrien{ 153568349Sobrien union { 1536103373Sobrien int32_t l; 1537103373Sobrien char c[sizeof (int32_t)]; 153868349Sobrien } u; 1539186690Sobrien int clazz; 154068349Sobrien int swap; 1541169942Sobrien struct stat st; 1542169942Sobrien off_t fsize; 1543169942Sobrien int flags = 0; 1544186690Sobrien Elf32_Ehdr elf32hdr; 1545186690Sobrien Elf64_Ehdr elf64hdr; 1546276577Sdelphij uint16_t type, phnum, shnum, notecount; 154768349Sobrien 1548284237Sdelphij if (ms->flags & (MAGIC_MIME|MAGIC_APPLE|MAGIC_EXTENSION)) 1549186690Sobrien return 0; 155068349Sobrien /* 155168349Sobrien * ELF executables have multiple section headers in arbitrary 155268349Sobrien * file locations and thus file(1) cannot determine it from easily. 155368349Sobrien * Instead we traverse thru all section headers until a symbol table 155468349Sobrien * one is found or else the binary is stripped. 1555186690Sobrien * Return immediately if it's not ELF (so we avoid pipe2file unless needed). 155668349Sobrien */ 155768349Sobrien if (buf[EI_MAG0] != ELFMAG0 155868349Sobrien || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) 155968349Sobrien || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) 1560186690Sobrien return 0; 156168349Sobrien 1562186690Sobrien /* 1563186690Sobrien * If we cannot seek, it must be a pipe, socket or fifo. 1564186690Sobrien */ 1565186690Sobrien if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) 1566186690Sobrien fd = file_pipe2file(ms, fd, buf, nbytes); 156768349Sobrien 1568186690Sobrien if (fstat(fd, &st) == -1) { 1569186690Sobrien file_badread(ms); 1570186690Sobrien return -1; 157168349Sobrien } 1572275698Sdelphij if (S_ISREG(st.st_mode) || st.st_size != 0) 1573275698Sdelphij fsize = st.st_size; 1574275698Sdelphij else 1575275698Sdelphij fsize = SIZE_UNKNOWN; 157668349Sobrien 1577186690Sobrien clazz = buf[EI_CLASS]; 157868349Sobrien 1579186690Sobrien switch (clazz) { 1580186690Sobrien case ELFCLASS32: 1581186690Sobrien#undef elf_getu 1582186690Sobrien#define elf_getu(a, b) elf_getu32(a, b) 1583186690Sobrien#undef elfhdr 1584186690Sobrien#define elfhdr elf32hdr 1585186690Sobrien#include "elfclass.h" 1586186690Sobrien case ELFCLASS64: 1587186690Sobrien#undef elf_getu 1588186690Sobrien#define elf_getu(a, b) elf_getu64(a, b) 1589186690Sobrien#undef elfhdr 1590186690Sobrien#define elfhdr elf64hdr 1591186690Sobrien#include "elfclass.h" 1592186690Sobrien default: 1593186690Sobrien if (file_printf(ms, ", unknown class %d", clazz) == -1) 1594186690Sobrien return -1; 1595186690Sobrien break; 159668349Sobrien } 1597133359Sobrien return 0; 159868349Sobrien} 159968349Sobrien#endif 1600