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 30328875SeadlerFILE_RCSID("@(#)$File: readelf.c,v 1.138 2017/08/27 07:55:02 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, 46277592Sdelphij off_t, int *, uint16_t *); 4768349Sobrien#endif 48169942Sobrienprivate int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t, 49277592Sdelphij off_t, int, int *, uint16_t *); 50226048Sobrienprivate int doshn(struct magic_set *, int, int, int, off_t, int, size_t, 51277592Sdelphij off_t, int, int, int *, uint16_t *); 52186690Sobrienprivate size_t donote(struct magic_set *, void *, size_t, size_t, int, 53300899Sdelphij 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 63276415Sdelphij#define MAX_PHNUM 128 64276415Sdelphij#define MAX_SHNUM 32768 65276415Sdelphij#define SIZE_UNKNOWN ((off_t)-1) 66275668Sdelphij 67275668Sdelphijprivate int 68275668Sdelphijtoomany(struct magic_set *ms, const char *name, uint16_t num) 69275668Sdelphij{ 70277592Sdelphij if (file_printf(ms, ", too many %s (%u)", name, num 71275668Sdelphij ) == -1) 72275668Sdelphij return -1; 73275668Sdelphij return 0; 74275668Sdelphij} 75275668Sdelphij 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))) 180300899Sdelphij#define xph_vaddr (size_t)((clazz == ELFCLASS32 \ 181300899Sdelphij ? (off_t) (ph32.p_vaddr ? \ 182300899Sdelphij elf_getu32(swap, ph32.p_vaddr) : 4) \ 183300899Sdelphij : (off_t) (ph64.p_vaddr ? \ 184300899Sdelphij 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 \ 195300899Sdelphij ? sizeof(nh32) \ 196300899Sdelphij : 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)) 221300899Sdelphij#define xauxv_addr (clazz == ELFCLASS32 \ 222300899Sdelphij ? (void *)&auxv32 \ 223300899Sdelphij : (void *)&auxv64) 224300899Sdelphij#define xauxv_sizeof (clazz == ELFCLASS32 \ 225300899Sdelphij ? sizeof(auxv32) \ 226300899Sdelphij : sizeof(auxv64)) 227300899Sdelphij#define xauxv_type (clazz == ELFCLASS32 \ 228300899Sdelphij ? elf_getu32(swap, auxv32.a_type) \ 229300899Sdelphij : elf_getu64(swap, auxv64.a_type)) 230300899Sdelphij#define xauxv_val (clazz == ELFCLASS32 \ 231300899Sdelphij ? elf_getu32(swap, auxv32.a_v) \ 232300899Sdelphij : 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 313328875Seadler#define FLAGS_CORE_STYLE 0x003 314159764Sobrien 315328875Seadler#define FLAGS_DID_CORE 0x004 316328875Seadler#define FLAGS_DID_OS_NOTE 0x008 317328875Seadler#define FLAGS_DID_BUILD_ID 0x010 318328875Seadler#define FLAGS_DID_CORE_STYLE 0x020 319328875Seadler#define FLAGS_DID_NETBSD_PAX 0x040 320328875Seadler#define FLAGS_DID_NETBSD_MARCH 0x080 321328875Seadler#define FLAGS_DID_NETBSD_CMODEL 0x100 322328875Seadler#define FLAGS_DID_NETBSD_UNKNOWN 0x200 323328875Seadler#define FLAGS_IS_CORE 0x400 324328875Seadler#define FLAGS_DID_AUXV 0x800 325328875Seadler 326133359Sobrienprivate int 327186690Sobriendophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 328277592Sdelphij int num, size_t size, off_t fsize, int *flags, uint16_t *notecount) 32968349Sobrien{ 33068349Sobrien Elf32_Phdr ph32; 33168349Sobrien Elf64_Phdr ph64; 332267843Sdelphij size_t offset, len; 333133359Sobrien unsigned char nbuf[BUFSIZ]; 334133359Sobrien ssize_t bufsize; 335300899Sdelphij off_t ph_off = off; 336300899Sdelphij int ph_num = num; 33768349Sobrien 338159764Sobrien if (size != xph_sizeof) { 339133359Sobrien if (file_printf(ms, ", corrupted program header size") == -1) 340133359Sobrien return -1; 341133359Sobrien return 0; 342133359Sobrien } 343159764Sobrien 34468349Sobrien /* 34568349Sobrien * Loop through all the program headers. 34668349Sobrien */ 34768349Sobrien for ( ; num; num--) { 348277592Sdelphij if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) { 349133359Sobrien file_badread(ms); 350133359Sobrien return -1; 351133359Sobrien } 352226048Sobrien off += size; 353226048Sobrien 354276415Sdelphij if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 355226048Sobrien /* Perhaps warn here */ 356169942Sobrien continue; 357169942Sobrien } 358169942Sobrien 359159764Sobrien if (xph_type != PT_NOTE) 36068349Sobrien continue; 36168349Sobrien 36268349Sobrien /* 36368349Sobrien * This is a PT_NOTE section; loop through all the notes 36468349Sobrien * in the section. 36568349Sobrien */ 366267843Sdelphij len = xph_filesz < sizeof(nbuf) ? xph_filesz : sizeof(nbuf); 367267843Sdelphij if ((bufsize = pread(fd, nbuf, len, xph_offset)) == -1) { 368133359Sobrien file_badread(ms); 369133359Sobrien return -1; 370133359Sobrien } 37168349Sobrien offset = 0; 37268349Sobrien for (;;) { 373133359Sobrien if (offset >= (size_t)bufsize) 37468349Sobrien break; 375133359Sobrien offset = donote(ms, nbuf, offset, (size_t)bufsize, 376300899Sdelphij clazz, swap, 4, flags, notecount, fd, ph_off, 377300899Sdelphij ph_num, fsize); 378133359Sobrien if (offset == 0) 379133359Sobrien break; 38068349Sobrien 381133359Sobrien } 382133359Sobrien } 383133359Sobrien return 0; 384133359Sobrien} 385133359Sobrien#endif 386133359Sobrien 387267843Sdelphijstatic void 388267843Sdelphijdo_note_netbsd_version(struct magic_set *ms, int swap, void *v) 389267843Sdelphij{ 390267843Sdelphij uint32_t desc; 391267843Sdelphij (void)memcpy(&desc, v, sizeof(desc)); 392267843Sdelphij desc = elf_getu32(swap, desc); 393267843Sdelphij 394267843Sdelphij if (file_printf(ms, ", for NetBSD") == -1) 395267843Sdelphij return; 396267843Sdelphij /* 397267843Sdelphij * The version number used to be stuck as 199905, and was thus 398267843Sdelphij * basically content-free. Newer versions of NetBSD have fixed 399267843Sdelphij * this and now use the encoding of __NetBSD_Version__: 400267843Sdelphij * 401267843Sdelphij * MMmmrrpp00 402267843Sdelphij * 403267843Sdelphij * M = major version 404267843Sdelphij * m = minor version 405267843Sdelphij * r = release ["",A-Z,Z[A-Z] but numeric] 406267843Sdelphij * p = patchlevel 407267843Sdelphij */ 408267843Sdelphij if (desc > 100000000U) { 409267843Sdelphij uint32_t ver_patch = (desc / 100) % 100; 410267843Sdelphij uint32_t ver_rel = (desc / 10000) % 100; 411267843Sdelphij uint32_t ver_min = (desc / 1000000) % 100; 412267843Sdelphij uint32_t ver_maj = desc / 100000000; 413267843Sdelphij 414267843Sdelphij if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) 415267843Sdelphij return; 416267843Sdelphij if (ver_rel == 0 && ver_patch != 0) { 417267843Sdelphij if (file_printf(ms, ".%u", ver_patch) == -1) 418267843Sdelphij return; 419267843Sdelphij } else if (ver_rel != 0) { 420267843Sdelphij while (ver_rel > 26) { 421267843Sdelphij if (file_printf(ms, "Z") == -1) 422267843Sdelphij return; 423267843Sdelphij ver_rel -= 26; 424267843Sdelphij } 425267843Sdelphij if (file_printf(ms, "%c", 'A' + ver_rel - 1) 426267843Sdelphij == -1) 427267843Sdelphij return; 428267843Sdelphij } 429267843Sdelphij } 430267843Sdelphij} 431267843Sdelphij 432267843Sdelphijstatic void 433267843Sdelphijdo_note_freebsd_version(struct magic_set *ms, int swap, void *v) 434267843Sdelphij{ 435267843Sdelphij uint32_t desc; 436267843Sdelphij 437267843Sdelphij (void)memcpy(&desc, v, sizeof(desc)); 438267843Sdelphij desc = elf_getu32(swap, desc); 439267843Sdelphij if (file_printf(ms, ", for FreeBSD") == -1) 440267843Sdelphij return; 441267843Sdelphij 442267843Sdelphij /* 443267843Sdelphij * Contents is __FreeBSD_version, whose relation to OS 444267843Sdelphij * versions is defined by a huge table in the Porter's 445267843Sdelphij * Handbook. This is the general scheme: 446267843Sdelphij * 447267843Sdelphij * Releases: 448267843Sdelphij * Mmp000 (before 4.10) 449267843Sdelphij * Mmi0p0 (before 5.0) 450267843Sdelphij * Mmm0p0 451267843Sdelphij * 452267843Sdelphij * Development branches: 453267843Sdelphij * Mmpxxx (before 4.6) 454267843Sdelphij * Mmp1xx (before 4.10) 455267843Sdelphij * Mmi1xx (before 5.0) 456267843Sdelphij * M000xx (pre-M.0) 457267843Sdelphij * Mmm1xx 458267843Sdelphij * 459267843Sdelphij * M = major version 460267843Sdelphij * m = minor version 461267843Sdelphij * i = minor version increment (491000 -> 4.10) 462267843Sdelphij * p = patchlevel 463267843Sdelphij * x = revision 464267843Sdelphij * 465267843Sdelphij * The first release of FreeBSD to use ELF by default 466267843Sdelphij * was version 3.0. 467267843Sdelphij */ 468267843Sdelphij if (desc == 460002) { 469267843Sdelphij if (file_printf(ms, " 4.6.2") == -1) 470267843Sdelphij return; 471267843Sdelphij } else if (desc < 460100) { 472267843Sdelphij if (file_printf(ms, " %d.%d", desc / 100000, 473267843Sdelphij desc / 10000 % 10) == -1) 474267843Sdelphij return; 475267843Sdelphij if (desc / 1000 % 10 > 0) 476267843Sdelphij if (file_printf(ms, ".%d", desc / 1000 % 10) == -1) 477267843Sdelphij return; 478267843Sdelphij if ((desc % 1000 > 0) || (desc % 100000 == 0)) 479267843Sdelphij if (file_printf(ms, " (%d)", desc) == -1) 480267843Sdelphij return; 481267843Sdelphij } else if (desc < 500000) { 482267843Sdelphij if (file_printf(ms, " %d.%d", desc / 100000, 483267843Sdelphij desc / 10000 % 10 + desc / 1000 % 10) == -1) 484267843Sdelphij return; 485267843Sdelphij if (desc / 100 % 10 > 0) { 486267843Sdelphij if (file_printf(ms, " (%d)", desc) == -1) 487267843Sdelphij return; 488267843Sdelphij } else if (desc / 10 % 10 > 0) { 489267843Sdelphij if (file_printf(ms, ".%d", desc / 10 % 10) == -1) 490267843Sdelphij return; 491267843Sdelphij } 492267843Sdelphij } else { 493267843Sdelphij if (file_printf(ms, " %d.%d", desc / 100000, 494267843Sdelphij desc / 1000 % 100) == -1) 495267843Sdelphij return; 496267843Sdelphij if ((desc / 100 % 10 > 0) || 497267843Sdelphij (desc % 100000 / 100 == 0)) { 498267843Sdelphij if (file_printf(ms, " (%d)", desc) == -1) 499267843Sdelphij return; 500267843Sdelphij } else if (desc / 10 % 10 > 0) { 501267843Sdelphij if (file_printf(ms, ".%d", desc / 10 % 10) == -1) 502267843Sdelphij return; 503267843Sdelphij } 504267843Sdelphij } 505267843Sdelphij} 506267843Sdelphij 507277592Sdelphijprivate int 508284778Sdelphij/*ARGSUSED*/ 509277592Sdelphijdo_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 510277592Sdelphij int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz, 511277592Sdelphij size_t noff, size_t doff, int *flags) 512133359Sobrien{ 513277592Sdelphij if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 514323281Sgordon type == NT_GNU_BUILD_ID && (descsz >= 4 && descsz <= 20)) { 515277592Sdelphij uint8_t desc[20]; 516309848Sdelphij const char *btype; 517277592Sdelphij uint32_t i; 518277592Sdelphij *flags |= FLAGS_DID_BUILD_ID; 519309848Sdelphij switch (descsz) { 520309848Sdelphij case 8: 521309848Sdelphij btype = "xxHash"; 522309848Sdelphij break; 523309848Sdelphij case 16: 524309848Sdelphij btype = "md5/uuid"; 525309848Sdelphij break; 526309848Sdelphij case 20: 527309848Sdelphij btype = "sha1"; 528309848Sdelphij break; 529309848Sdelphij default: 530309848Sdelphij btype = "unknown"; 531309848Sdelphij break; 532309848Sdelphij } 533309848Sdelphij if (file_printf(ms, ", BuildID[%s]=", btype) == -1) 534277592Sdelphij return 1; 535277592Sdelphij (void)memcpy(desc, &nbuf[doff], descsz); 536277592Sdelphij for (i = 0; i < descsz; i++) 537277592Sdelphij if (file_printf(ms, "%02x", desc[i]) == -1) 538277592Sdelphij return 1; 539277592Sdelphij return 1; 540275668Sdelphij } 541277592Sdelphij return 0; 542277592Sdelphij} 543275668Sdelphij 544277592Sdelphijprivate int 545277592Sdelphijdo_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 546277592Sdelphij int swap, uint32_t namesz, uint32_t descsz, 547277592Sdelphij size_t noff, size_t doff, int *flags) 548277592Sdelphij{ 549267843Sdelphij if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 && 550277592Sdelphij type == NT_GNU_VERSION && descsz == 2) { 551277592Sdelphij *flags |= FLAGS_DID_OS_NOTE; 552267843Sdelphij file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]); 553277592Sdelphij return 1; 554267843Sdelphij } 555277592Sdelphij 556133359Sobrien if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 557277592Sdelphij type == NT_GNU_VERSION && descsz == 16) { 558133359Sobrien uint32_t desc[4]; 559133359Sobrien (void)memcpy(desc, &nbuf[doff], sizeof(desc)); 560133359Sobrien 561277592Sdelphij *flags |= FLAGS_DID_OS_NOTE; 562133359Sobrien if (file_printf(ms, ", for GNU/") == -1) 563277592Sdelphij return 1; 564186690Sobrien switch (elf_getu32(swap, desc[0])) { 565133359Sobrien case GNU_OS_LINUX: 566133359Sobrien if (file_printf(ms, "Linux") == -1) 567277592Sdelphij return 1; 568133359Sobrien break; 569133359Sobrien case GNU_OS_HURD: 570133359Sobrien if (file_printf(ms, "Hurd") == -1) 571277592Sdelphij return 1; 572133359Sobrien break; 573133359Sobrien case GNU_OS_SOLARIS: 574133359Sobrien if (file_printf(ms, "Solaris") == -1) 575277592Sdelphij return 1; 576133359Sobrien break; 577186690Sobrien case GNU_OS_KFREEBSD: 578186690Sobrien if (file_printf(ms, "kFreeBSD") == -1) 579277592Sdelphij return 1; 580186690Sobrien break; 581186690Sobrien case GNU_OS_KNETBSD: 582186690Sobrien if (file_printf(ms, "kNetBSD") == -1) 583277592Sdelphij return 1; 584186690Sobrien break; 585133359Sobrien default: 586133359Sobrien if (file_printf(ms, "<unknown>") == -1) 587277592Sdelphij return 1; 588133359Sobrien } 589186690Sobrien if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]), 590186690Sobrien elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1) 591277592Sdelphij return 1; 592277592Sdelphij return 1; 593133359Sobrien } 594133359Sobrien 595277592Sdelphij if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { 596277592Sdelphij if (type == NT_NETBSD_VERSION && descsz == 4) { 597277592Sdelphij *flags |= FLAGS_DID_OS_NOTE; 598277592Sdelphij do_note_netbsd_version(ms, swap, &nbuf[doff]); 599277592Sdelphij return 1; 600277592Sdelphij } 601226048Sobrien } 602226048Sobrien 603277592Sdelphij if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) { 604277592Sdelphij if (type == NT_FREEBSD_VERSION && descsz == 4) { 605277592Sdelphij *flags |= FLAGS_DID_OS_NOTE; 606277592Sdelphij do_note_freebsd_version(ms, swap, &nbuf[doff]); 607277592Sdelphij return 1; 608277592Sdelphij } 609277592Sdelphij } 610277592Sdelphij 611277592Sdelphij if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && 612277592Sdelphij type == NT_OPENBSD_VERSION && descsz == 4) { 613277592Sdelphij *flags |= FLAGS_DID_OS_NOTE; 614277592Sdelphij if (file_printf(ms, ", for OpenBSD") == -1) 615277592Sdelphij return 1; 616277592Sdelphij /* Content of note is always 0 */ 617277592Sdelphij return 1; 618277592Sdelphij } 619277592Sdelphij 620277592Sdelphij if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 && 621277592Sdelphij type == NT_DRAGONFLY_VERSION && descsz == 4) { 622277592Sdelphij uint32_t desc; 623277592Sdelphij *flags |= FLAGS_DID_OS_NOTE; 624277592Sdelphij if (file_printf(ms, ", for DragonFly") == -1) 625277592Sdelphij return 1; 626277592Sdelphij (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 627277592Sdelphij desc = elf_getu32(swap, desc); 628277592Sdelphij if (file_printf(ms, " %d.%d.%d", desc / 100000, 629277592Sdelphij desc / 10000 % 10, desc % 10000) == -1) 630277592Sdelphij return 1; 631277592Sdelphij return 1; 632277592Sdelphij } 633277592Sdelphij return 0; 634277592Sdelphij} 635277592Sdelphij 636277592Sdelphijprivate int 637277592Sdelphijdo_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 638277592Sdelphij int swap, uint32_t namesz, uint32_t descsz, 639277592Sdelphij size_t noff, size_t doff, int *flags) 640277592Sdelphij{ 641267843Sdelphij if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 && 642277592Sdelphij type == NT_NETBSD_PAX && descsz == 4) { 643267843Sdelphij static const char *pax[] = { 644267843Sdelphij "+mprotect", 645267843Sdelphij "-mprotect", 646267843Sdelphij "+segvguard", 647267843Sdelphij "-segvguard", 648267843Sdelphij "+ASLR", 649267843Sdelphij "-ASLR", 650267843Sdelphij }; 651133359Sobrien uint32_t desc; 652267843Sdelphij size_t i; 653267843Sdelphij int did = 0; 654267843Sdelphij 655277592Sdelphij *flags |= FLAGS_DID_NETBSD_PAX; 656133359Sobrien (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 657186690Sobrien desc = elf_getu32(swap, desc); 658133359Sobrien 659267843Sdelphij if (desc && file_printf(ms, ", PaX: ") == -1) 660277592Sdelphij return 1; 661133359Sobrien 662267843Sdelphij for (i = 0; i < __arraycount(pax); i++) { 663284778Sdelphij if (((1 << (int)i) & desc) == 0) 664267843Sdelphij continue; 665267843Sdelphij if (file_printf(ms, "%s%s", did++ ? "," : "", 666267843Sdelphij pax[i]) == -1) 667277592Sdelphij return 1; 668133359Sobrien } 669277592Sdelphij return 1; 670133359Sobrien } 671277592Sdelphij return 0; 672277592Sdelphij} 67368349Sobrien 674277592Sdelphijprivate int 675277592Sdelphijdo_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 676277592Sdelphij int swap, uint32_t namesz, uint32_t descsz, 677277592Sdelphij size_t noff, size_t doff, int *flags, size_t size, int clazz) 678277592Sdelphij{ 679277592Sdelphij#ifdef ELFCORE 680277592Sdelphij int os_style = -1; 681133359Sobrien /* 682133359Sobrien * Sigh. The 2.0.36 kernel in Debian 2.1, at 683133359Sobrien * least, doesn't correctly implement name 684133359Sobrien * sections, in core dumps, as specified by 685133359Sobrien * the "Program Linking" section of "UNIX(R) System 686133359Sobrien * V Release 4 Programmer's Guide: ANSI C and 687133359Sobrien * Programming Support Tools", because my copy 688133359Sobrien * clearly says "The first 'namesz' bytes in 'name' 689133359Sobrien * contain a *null-terminated* [emphasis mine] 690133359Sobrien * character representation of the entry's owner 691133359Sobrien * or originator", but the 2.0.36 kernel code 692133359Sobrien * doesn't include the terminating null in the 693133359Sobrien * name.... 694133359Sobrien */ 695133359Sobrien if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) || 696133359Sobrien (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) { 697133359Sobrien os_style = OS_STYLE_SVR4; 698133359Sobrien } 699133359Sobrien 700133359Sobrien if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) { 701133359Sobrien os_style = OS_STYLE_FREEBSD; 702133359Sobrien } 703133359Sobrien 704133359Sobrien if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11) 705133359Sobrien == 0)) { 706133359Sobrien os_style = OS_STYLE_NETBSD; 707133359Sobrien } 708133359Sobrien 709175296Sobrien if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) { 710169942Sobrien if (file_printf(ms, ", %s-style", os_style_names[os_style]) 711169942Sobrien == -1) 712277592Sdelphij return 1; 713175296Sobrien *flags |= FLAGS_DID_CORE_STYLE; 714328875Seadler *flags |= os_style; 715159764Sobrien } 716133359Sobrien 717159764Sobrien switch (os_style) { 718159764Sobrien case OS_STYLE_NETBSD: 719277592Sdelphij if (type == NT_NETBSD_CORE_PROCINFO) { 720277592Sdelphij char sbuf[512]; 721328875Seadler struct NetBSD_elfcore_procinfo pi; 722328875Seadler memset(&pi, 0, sizeof(pi)); 723328875Seadler memcpy(&pi, nbuf + doff, descsz); 724328875Seadler 725328875Seadler if (file_printf(ms, ", from '%.31s', pid=%u, uid=%u, " 726328875Seadler "gid=%u, nlwps=%u, lwp=%u (signal %u/code %u)", 727277592Sdelphij file_printable(sbuf, sizeof(sbuf), 728328875Seadler CAST(char *, pi.cpi_name)), 729328875Seadler elf_getu32(swap, pi.cpi_pid), 730328875Seadler elf_getu32(swap, pi.cpi_euid), 731328875Seadler elf_getu32(swap, pi.cpi_egid), 732328875Seadler elf_getu32(swap, pi.cpi_nlwps), 733328875Seadler elf_getu32(swap, pi.cpi_siglwp), 734328875Seadler elf_getu32(swap, pi.cpi_signo), 735328875Seadler elf_getu32(swap, pi.cpi_sigcode)) == -1) 736277592Sdelphij return 1; 737328875Seadler 738175296Sobrien *flags |= FLAGS_DID_CORE; 739277592Sdelphij return 1; 740159764Sobrien } 741159764Sobrien break; 742133359Sobrien 743159764Sobrien default: 744277592Sdelphij 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 */ 812277592Sdelphij 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) 837277592Sdelphij return 1; 838175296Sobrien *flags |= FLAGS_DID_CORE; 839277592Sdelphij return 1; 840133359Sobrien 841159764Sobrien tryanother: 842159764Sobrien ; 843159764Sobrien } 84468349Sobrien } 845159764Sobrien break; 84668349Sobrien } 847133359Sobrien#endif 848277592Sdelphij return 0; 849277592Sdelphij} 850277592Sdelphij 851300899Sdelphijprivate off_t 852300899Sdelphijget_offset_from_virtaddr(struct magic_set *ms, int swap, int clazz, int fd, 853300899Sdelphij off_t off, int num, off_t fsize, uint64_t virtaddr) 854300899Sdelphij{ 855300899Sdelphij Elf32_Phdr ph32; 856300899Sdelphij Elf64_Phdr ph64; 857300899Sdelphij 858300899Sdelphij /* 859300899Sdelphij * Loop through all the program headers and find the header with 860300899Sdelphij * virtual address in which the "virtaddr" belongs to. 861300899Sdelphij */ 862300899Sdelphij for ( ; num; num--) { 863300899Sdelphij if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) { 864300899Sdelphij file_badread(ms); 865300899Sdelphij return -1; 866300899Sdelphij } 867300899Sdelphij off += xph_sizeof; 868300899Sdelphij 869300899Sdelphij if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 870300899Sdelphij /* Perhaps warn here */ 871300899Sdelphij continue; 872300899Sdelphij } 873300899Sdelphij 874300899Sdelphij if (virtaddr >= xph_vaddr && virtaddr < xph_vaddr + xph_filesz) 875300899Sdelphij return xph_offset + (virtaddr - xph_vaddr); 876300899Sdelphij } 877300899Sdelphij return 0; 878300899Sdelphij} 879300899Sdelphij 880277592Sdelphijprivate size_t 881300899Sdelphijget_string_on_virtaddr(struct magic_set *ms, 882300899Sdelphij int swap, int clazz, int fd, off_t ph_off, int ph_num, 883300899Sdelphij off_t fsize, uint64_t virtaddr, char *buf, ssize_t buflen) 884300899Sdelphij{ 885300899Sdelphij char *bptr; 886300899Sdelphij off_t offset; 887300899Sdelphij 888300899Sdelphij if (buflen == 0) 889300899Sdelphij return 0; 890300899Sdelphij 891300899Sdelphij offset = get_offset_from_virtaddr(ms, swap, clazz, fd, ph_off, ph_num, 892300899Sdelphij fsize, virtaddr); 893328875Seadler if ((buflen = pread(fd, buf, CAST(size_t, buflen), offset)) <= 0) { 894300899Sdelphij file_badread(ms); 895300899Sdelphij return 0; 896300899Sdelphij } 897300899Sdelphij 898300899Sdelphij buf[buflen - 1] = '\0'; 899300899Sdelphij 900300899Sdelphij /* We expect only printable characters, so return if buffer contains 901300899Sdelphij * non-printable character before the '\0' or just '\0'. */ 902300899Sdelphij for (bptr = buf; *bptr && isprint((unsigned char)*bptr); bptr++) 903300899Sdelphij continue; 904300899Sdelphij if (*bptr != '\0') 905300899Sdelphij return 0; 906300899Sdelphij 907300899Sdelphij return bptr - buf; 908300899Sdelphij} 909300899Sdelphij 910300899Sdelphij 911300899Sdelphijprivate int 912300899Sdelphijdo_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 913300899Sdelphij int swap, uint32_t namesz __attribute__((__unused__)), 914300899Sdelphij uint32_t descsz __attribute__((__unused__)), 915300899Sdelphij size_t noff __attribute__((__unused__)), size_t doff, 916300899Sdelphij int *flags, size_t size __attribute__((__unused__)), int clazz, 917300899Sdelphij int fd, off_t ph_off, int ph_num, off_t fsize) 918300899Sdelphij{ 919300899Sdelphij#ifdef ELFCORE 920300899Sdelphij Aux32Info auxv32; 921300899Sdelphij Aux64Info auxv64; 922300899Sdelphij size_t elsize = xauxv_sizeof; 923300899Sdelphij const char *tag; 924300899Sdelphij int is_string; 925300899Sdelphij size_t nval; 926300899Sdelphij 927328875Seadler if ((*flags & (FLAGS_IS_CORE|FLAGS_DID_CORE_STYLE)) != 928328875Seadler (FLAGS_IS_CORE|FLAGS_DID_CORE_STYLE)) 929300899Sdelphij return 0; 930300899Sdelphij 931328875Seadler switch (*flags & FLAGS_CORE_STYLE) { 932328875Seadler case OS_STYLE_SVR4: 933328875Seadler if (type != NT_AUXV) 934328875Seadler return 0; 935328875Seadler break; 936328875Seadler#ifdef notyet 937328875Seadler case OS_STYLE_NETBSD: 938328875Seadler if (type != NT_NETBSD_CORE_AUXV) 939328875Seadler return 0; 940328875Seadler break; 941328875Seadler case OS_STYLE_FREEBSD: 942328875Seadler if (type != NT_FREEBSD_PROCSTAT_AUXV) 943328875Seadler return 0; 944328875Seadler break; 945328875Seadler#endif 946328875Seadler default: 947328875Seadler return 0; 948328875Seadler } 949328875Seadler 950300899Sdelphij *flags |= FLAGS_DID_AUXV; 951300899Sdelphij 952300899Sdelphij nval = 0; 953300899Sdelphij for (size_t off = 0; off + elsize <= descsz; off += elsize) { 954300899Sdelphij (void)memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof); 955300899Sdelphij /* Limit processing to 50 vector entries to prevent DoS */ 956300899Sdelphij if (nval++ >= 50) { 957300899Sdelphij file_error(ms, 0, "Too many ELF Auxv elements"); 958300899Sdelphij return 1; 959300899Sdelphij } 960300899Sdelphij 961300899Sdelphij switch(xauxv_type) { 962300899Sdelphij case AT_LINUX_EXECFN: 963300899Sdelphij is_string = 1; 964300899Sdelphij tag = "execfn"; 965300899Sdelphij break; 966300899Sdelphij case AT_LINUX_PLATFORM: 967300899Sdelphij is_string = 1; 968300899Sdelphij tag = "platform"; 969300899Sdelphij break; 970300899Sdelphij case AT_LINUX_UID: 971300899Sdelphij is_string = 0; 972300899Sdelphij tag = "real uid"; 973300899Sdelphij break; 974300899Sdelphij case AT_LINUX_GID: 975300899Sdelphij is_string = 0; 976300899Sdelphij tag = "real gid"; 977300899Sdelphij break; 978300899Sdelphij case AT_LINUX_EUID: 979300899Sdelphij is_string = 0; 980300899Sdelphij tag = "effective uid"; 981300899Sdelphij break; 982300899Sdelphij case AT_LINUX_EGID: 983300899Sdelphij is_string = 0; 984300899Sdelphij tag = "effective gid"; 985300899Sdelphij break; 986300899Sdelphij default: 987300899Sdelphij is_string = 0; 988300899Sdelphij tag = NULL; 989300899Sdelphij break; 990300899Sdelphij } 991300899Sdelphij 992300899Sdelphij if (tag == NULL) 993300899Sdelphij continue; 994300899Sdelphij 995300899Sdelphij if (is_string) { 996300899Sdelphij char buf[256]; 997300899Sdelphij ssize_t buflen; 998300899Sdelphij buflen = get_string_on_virtaddr(ms, swap, clazz, fd, 999300899Sdelphij ph_off, ph_num, fsize, xauxv_val, buf, sizeof(buf)); 1000300899Sdelphij 1001300899Sdelphij if (buflen == 0) 1002300899Sdelphij continue; 1003300899Sdelphij 1004300899Sdelphij if (file_printf(ms, ", %s: '%s'", tag, buf) == -1) 1005300899Sdelphij return 0; 1006300899Sdelphij } else { 1007300899Sdelphij if (file_printf(ms, ", %s: %d", tag, (int) xauxv_val) 1008300899Sdelphij == -1) 1009300899Sdelphij return 0; 1010300899Sdelphij } 1011300899Sdelphij } 1012300899Sdelphij return 1; 1013300899Sdelphij#else 1014300899Sdelphij return 0; 1015300899Sdelphij#endif 1016300899Sdelphij} 1017300899Sdelphij 1018300899Sdelphijprivate size_t 1019277592Sdelphijdonote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, 1020300899Sdelphij int clazz, int swap, size_t align, int *flags, uint16_t *notecount, 1021300899Sdelphij int fd, off_t ph_off, int ph_num, off_t fsize) 1022277592Sdelphij{ 1023277592Sdelphij Elf32_Nhdr nh32; 1024277592Sdelphij Elf64_Nhdr nh64; 1025277592Sdelphij size_t noff, doff; 1026277592Sdelphij uint32_t namesz, descsz; 1027277592Sdelphij unsigned char *nbuf = CAST(unsigned char *, vbuf); 1028277592Sdelphij 1029277592Sdelphij if (*notecount == 0) 1030277592Sdelphij return 0; 1031277592Sdelphij --*notecount; 1032277592Sdelphij 1033277592Sdelphij if (xnh_sizeof + offset > size) { 1034277592Sdelphij /* 1035277592Sdelphij * We're out of note headers. 1036277592Sdelphij */ 1037277592Sdelphij return xnh_sizeof + offset; 1038277592Sdelphij } 1039277592Sdelphij 1040277592Sdelphij (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); 1041277592Sdelphij offset += xnh_sizeof; 1042277592Sdelphij 1043277592Sdelphij namesz = xnh_namesz; 1044277592Sdelphij descsz = xnh_descsz; 1045300899Sdelphij 1046277592Sdelphij if ((namesz == 0) && (descsz == 0)) { 1047277592Sdelphij /* 1048277592Sdelphij * We're out of note headers. 1049277592Sdelphij */ 1050277592Sdelphij return (offset >= size) ? offset : size; 1051277592Sdelphij } 1052277592Sdelphij 1053277592Sdelphij if (namesz & 0x80000000) { 1054328875Seadler (void)file_printf(ms, ", bad note name size %#lx", 1055277592Sdelphij (unsigned long)namesz); 1056277592Sdelphij return 0; 1057277592Sdelphij } 1058277592Sdelphij 1059277592Sdelphij if (descsz & 0x80000000) { 1060328875Seadler (void)file_printf(ms, ", bad note description size %#lx", 1061277592Sdelphij (unsigned long)descsz); 1062277592Sdelphij return 0; 1063277592Sdelphij } 1064277592Sdelphij 1065277592Sdelphij noff = offset; 1066277592Sdelphij doff = ELF_ALIGN(offset + namesz); 1067277592Sdelphij 1068277592Sdelphij if (offset + namesz > size) { 1069277592Sdelphij /* 1070277592Sdelphij * We're past the end of the buffer. 1071277592Sdelphij */ 1072277592Sdelphij return doff; 1073277592Sdelphij } 1074277592Sdelphij 1075277592Sdelphij offset = ELF_ALIGN(doff + descsz); 1076277592Sdelphij if (doff + descsz > size) { 1077277592Sdelphij /* 1078277592Sdelphij * We're past the end of the buffer. 1079277592Sdelphij */ 1080277592Sdelphij return (offset >= size) ? offset : size; 1081277592Sdelphij } 1082277592Sdelphij 1083300899Sdelphij 1084277592Sdelphij if ((*flags & FLAGS_DID_OS_NOTE) == 0) { 1085277592Sdelphij if (do_os_note(ms, nbuf, xnh_type, swap, 1086277592Sdelphij namesz, descsz, noff, doff, flags)) 1087300899Sdelphij return offset; 1088277592Sdelphij } 1089277592Sdelphij 1090277592Sdelphij if ((*flags & FLAGS_DID_BUILD_ID) == 0) { 1091277592Sdelphij if (do_bid_note(ms, nbuf, xnh_type, swap, 1092277592Sdelphij namesz, descsz, noff, doff, flags)) 1093300899Sdelphij return offset; 1094277592Sdelphij } 1095277592Sdelphij 1096277592Sdelphij if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) { 1097277592Sdelphij if (do_pax_note(ms, nbuf, xnh_type, swap, 1098277592Sdelphij namesz, descsz, noff, doff, flags)) 1099300899Sdelphij return offset; 1100277592Sdelphij } 1101277592Sdelphij 1102277592Sdelphij if ((*flags & FLAGS_DID_CORE) == 0) { 1103277592Sdelphij if (do_core_note(ms, nbuf, xnh_type, swap, 1104277592Sdelphij namesz, descsz, noff, doff, flags, size, clazz)) 1105300899Sdelphij return offset; 1106277592Sdelphij } 1107277592Sdelphij 1108300899Sdelphij if ((*flags & FLAGS_DID_AUXV) == 0) { 1109300899Sdelphij if (do_auxv_note(ms, nbuf, xnh_type, swap, 1110300899Sdelphij namesz, descsz, noff, doff, flags, size, clazz, 1111300899Sdelphij fd, ph_off, ph_num, fsize)) 1112300899Sdelphij return offset; 1113300899Sdelphij } 1114300899Sdelphij 1115277592Sdelphij if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { 1116277592Sdelphij if (descsz > 100) 1117277592Sdelphij descsz = 100; 1118277592Sdelphij switch (xnh_type) { 1119277592Sdelphij case NT_NETBSD_VERSION: 1120300899Sdelphij return offset; 1121277592Sdelphij case NT_NETBSD_MARCH: 1122277592Sdelphij if (*flags & FLAGS_DID_NETBSD_MARCH) 1123300899Sdelphij return offset; 1124277592Sdelphij *flags |= FLAGS_DID_NETBSD_MARCH; 1125277592Sdelphij if (file_printf(ms, ", compiled for: %.*s", 1126277592Sdelphij (int)descsz, (const char *)&nbuf[doff]) == -1) 1127300899Sdelphij return offset; 1128277592Sdelphij break; 1129277592Sdelphij case NT_NETBSD_CMODEL: 1130277592Sdelphij if (*flags & FLAGS_DID_NETBSD_CMODEL) 1131300899Sdelphij return offset; 1132277592Sdelphij *flags |= FLAGS_DID_NETBSD_CMODEL; 1133277592Sdelphij if (file_printf(ms, ", compiler model: %.*s", 1134277592Sdelphij (int)descsz, (const char *)&nbuf[doff]) == -1) 1135300899Sdelphij return offset; 1136277592Sdelphij break; 1137277592Sdelphij default: 1138277592Sdelphij if (*flags & FLAGS_DID_NETBSD_UNKNOWN) 1139300899Sdelphij return offset; 1140277592Sdelphij *flags |= FLAGS_DID_NETBSD_UNKNOWN; 1141277592Sdelphij if (file_printf(ms, ", note=%u", xnh_type) == -1) 1142300899Sdelphij return offset; 1143277592Sdelphij break; 1144277592Sdelphij } 1145300899Sdelphij return offset; 1146277592Sdelphij } 1147277592Sdelphij 1148133359Sobrien return offset; 114968349Sobrien} 115068349Sobrien 1151186690Sobrien/* SunOS 5.x hardware capability descriptions */ 1152186690Sobrientypedef struct cap_desc { 1153186690Sobrien uint64_t cd_mask; 1154186690Sobrien const char *cd_name; 1155186690Sobrien} cap_desc_t; 1156186690Sobrien 1157186690Sobrienstatic const cap_desc_t cap_desc_sparc[] = { 1158186690Sobrien { AV_SPARC_MUL32, "MUL32" }, 1159186690Sobrien { AV_SPARC_DIV32, "DIV32" }, 1160186690Sobrien { AV_SPARC_FSMULD, "FSMULD" }, 1161186690Sobrien { AV_SPARC_V8PLUS, "V8PLUS" }, 1162186690Sobrien { AV_SPARC_POPC, "POPC" }, 1163186690Sobrien { AV_SPARC_VIS, "VIS" }, 1164186690Sobrien { AV_SPARC_VIS2, "VIS2" }, 1165186690Sobrien { AV_SPARC_ASI_BLK_INIT, "ASI_BLK_INIT" }, 1166186690Sobrien { AV_SPARC_FMAF, "FMAF" }, 1167186690Sobrien { AV_SPARC_FJFMAU, "FJFMAU" }, 1168186690Sobrien { AV_SPARC_IMA, "IMA" }, 1169186690Sobrien { 0, NULL } 1170186690Sobrien}; 1171186690Sobrien 1172186690Sobrienstatic const cap_desc_t cap_desc_386[] = { 1173186690Sobrien { AV_386_FPU, "FPU" }, 1174186690Sobrien { AV_386_TSC, "TSC" }, 1175186690Sobrien { AV_386_CX8, "CX8" }, 1176186690Sobrien { AV_386_SEP, "SEP" }, 1177186690Sobrien { AV_386_AMD_SYSC, "AMD_SYSC" }, 1178186690Sobrien { AV_386_CMOV, "CMOV" }, 1179186690Sobrien { AV_386_MMX, "MMX" }, 1180186690Sobrien { AV_386_AMD_MMX, "AMD_MMX" }, 1181186690Sobrien { AV_386_AMD_3DNow, "AMD_3DNow" }, 1182186690Sobrien { AV_386_AMD_3DNowx, "AMD_3DNowx" }, 1183186690Sobrien { AV_386_FXSR, "FXSR" }, 1184186690Sobrien { AV_386_SSE, "SSE" }, 1185186690Sobrien { AV_386_SSE2, "SSE2" }, 1186186690Sobrien { AV_386_PAUSE, "PAUSE" }, 1187186690Sobrien { AV_386_SSE3, "SSE3" }, 1188186690Sobrien { AV_386_MON, "MON" }, 1189186690Sobrien { AV_386_CX16, "CX16" }, 1190186690Sobrien { AV_386_AHF, "AHF" }, 1191186690Sobrien { AV_386_TSCP, "TSCP" }, 1192186690Sobrien { AV_386_AMD_SSE4A, "AMD_SSE4A" }, 1193186690Sobrien { AV_386_POPCNT, "POPCNT" }, 1194186690Sobrien { AV_386_AMD_LZCNT, "AMD_LZCNT" }, 1195186690Sobrien { AV_386_SSSE3, "SSSE3" }, 1196186690Sobrien { AV_386_SSE4_1, "SSE4.1" }, 1197186690Sobrien { AV_386_SSE4_2, "SSE4.2" }, 1198186690Sobrien { 0, NULL } 1199186690Sobrien}; 1200186690Sobrien 1201133359Sobrienprivate int 1202186690Sobriendoshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, 1203277592Sdelphij size_t size, off_t fsize, int mach, int strtab, int *flags, 1204277592Sdelphij uint16_t *notecount) 120568349Sobrien{ 1206133359Sobrien Elf32_Shdr sh32; 1207133359Sobrien Elf64_Shdr sh64; 1208328875Seadler int stripped = 1, has_debug_info = 0; 1209275668Sdelphij size_t nbadcap = 0; 1210159764Sobrien void *nbuf; 1211267843Sdelphij off_t noff, coff, name_off; 1212328875Seadler uint64_t cap_hw1 = 0; /* SunOS 5.x hardware capabilities */ 1213328875Seadler uint64_t cap_sf1 = 0; /* SunOS 5.x software capabilities */ 1214267843Sdelphij char name[50]; 1215277592Sdelphij ssize_t namesize; 1216133359Sobrien 1217159764Sobrien if (size != xsh_sizeof) { 1218133359Sobrien if (file_printf(ms, ", corrupted section header size") == -1) 1219133359Sobrien return -1; 1220133359Sobrien return 0; 1221133359Sobrien } 1222133359Sobrien 1223267843Sdelphij /* Read offset of name section to be able to read section names later */ 1224284778Sdelphij if (pread(fd, xsh_addr, xsh_sizeof, CAST(off_t, (off + size * strtab))) 1225284778Sdelphij < (ssize_t)xsh_sizeof) { 1226328875Seadler if (file_printf(ms, ", missing section headers") == -1) 1227328875Seadler return -1; 1228328875Seadler return 0; 1229267843Sdelphij } 1230267843Sdelphij name_off = xsh_offset; 1231267843Sdelphij 1232133359Sobrien for ( ; num; num--) { 1233267843Sdelphij /* Read the name of this section. */ 1234277592Sdelphij if ((namesize = pread(fd, name, sizeof(name) - 1, name_off + xsh_name)) == -1) { 1235267843Sdelphij file_badread(ms); 1236226048Sobrien return -1; 1237226048Sobrien } 1238277592Sdelphij name[namesize] = '\0'; 1239328875Seadler if (strcmp(name, ".debug_info") == 0) { 1240328875Seadler has_debug_info = 1; 1241267843Sdelphij stripped = 0; 1242328875Seadler } 1243267843Sdelphij 1244277592Sdelphij if (pread(fd, xsh_addr, xsh_sizeof, off) < (ssize_t)xsh_sizeof) { 1245133359Sobrien file_badread(ms); 1246133359Sobrien return -1; 1247133359Sobrien } 1248226048Sobrien off += size; 1249226048Sobrien 1250226048Sobrien /* Things we can determine before we seek */ 1251159764Sobrien switch (xsh_type) { 1252159764Sobrien case SHT_SYMTAB: 1253159764Sobrien#if 0 1254159764Sobrien case SHT_DYNSYM: 1255159764Sobrien#endif 1256159764Sobrien stripped = 0; 1257159764Sobrien break; 1258226048Sobrien default: 1259276415Sdelphij if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) { 1260226048Sobrien /* Perhaps warn here */ 1261226048Sobrien continue; 1262226048Sobrien } 1263226048Sobrien break; 1264226048Sobrien } 1265226048Sobrien 1266290152Sdelphij 1267226048Sobrien /* Things we can determine when we seek */ 1268226048Sobrien switch (xsh_type) { 1269159764Sobrien case SHT_NOTE: 1270290152Sdelphij if ((uintmax_t)(xsh_size + xsh_offset) > 1271290152Sdelphij (uintmax_t)fsize) { 1272290152Sdelphij if (file_printf(ms, 1273328875Seadler ", note offset/size %#" INTMAX_T_FORMAT 1274328875Seadler "x+%#" INTMAX_T_FORMAT "x exceeds" 1275328875Seadler " file size %#" INTMAX_T_FORMAT "x", 1276290152Sdelphij (uintmax_t)xsh_offset, (uintmax_t)xsh_size, 1277290152Sdelphij (uintmax_t)fsize) == -1) 1278290152Sdelphij return -1; 1279290152Sdelphij return 0; 1280290152Sdelphij } 1281267843Sdelphij if ((nbuf = malloc(xsh_size)) == NULL) { 1282159764Sobrien file_error(ms, errno, "Cannot allocate memory" 1283159764Sobrien " for note"); 1284159764Sobrien return -1; 1285159764Sobrien } 1286290152Sdelphij if (pread(fd, nbuf, xsh_size, xsh_offset) < 1287290152Sdelphij (ssize_t)xsh_size) { 1288159764Sobrien file_badread(ms); 1289159764Sobrien free(nbuf); 1290159764Sobrien return -1; 1291159764Sobrien } 1292159764Sobrien 1293159764Sobrien noff = 0; 1294159764Sobrien for (;;) { 1295191736Sobrien if (noff >= (off_t)xsh_size) 1296159764Sobrien break; 1297159764Sobrien noff = donote(ms, nbuf, (size_t)noff, 1298300899Sdelphij xsh_size, clazz, swap, 4, flags, notecount, 1299300899Sdelphij fd, 0, 0, 0); 1300159764Sobrien if (noff == 0) 1301159764Sobrien break; 1302159764Sobrien } 1303159764Sobrien free(nbuf); 1304159764Sobrien break; 1305186690Sobrien case SHT_SUNW_cap: 1306267843Sdelphij switch (mach) { 1307267843Sdelphij case EM_SPARC: 1308267843Sdelphij case EM_SPARCV9: 1309267843Sdelphij case EM_IA_64: 1310267843Sdelphij case EM_386: 1311267843Sdelphij case EM_AMD64: 1312267843Sdelphij break; 1313267843Sdelphij default: 1314267843Sdelphij goto skip; 1315267843Sdelphij } 1316267843Sdelphij 1317275668Sdelphij if (nbadcap > 5) 1318275668Sdelphij break; 1319267843Sdelphij if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) { 1320226048Sobrien file_badseek(ms); 1321186690Sobrien return -1; 1322186690Sobrien } 1323186690Sobrien coff = 0; 1324186690Sobrien for (;;) { 1325186690Sobrien Elf32_Cap cap32; 1326186690Sobrien Elf64_Cap cap64; 1327191736Sobrien char cbuf[/*CONSTCOND*/ 1328191736Sobrien MAX(sizeof cap32, sizeof cap64)]; 1329226048Sobrien if ((coff += xcap_sizeof) > (off_t)xsh_size) 1330186690Sobrien break; 1331186690Sobrien if (read(fd, cbuf, (size_t)xcap_sizeof) != 1332186690Sobrien (ssize_t)xcap_sizeof) { 1333186690Sobrien file_badread(ms); 1334186690Sobrien return -1; 1335186690Sobrien } 1336267843Sdelphij if (cbuf[0] == 'A') { 1337267843Sdelphij#ifdef notyet 1338267843Sdelphij char *p = cbuf + 1; 1339267843Sdelphij uint32_t len, tag; 1340267843Sdelphij memcpy(&len, p, sizeof(len)); 1341267843Sdelphij p += 4; 1342267843Sdelphij len = getu32(swap, len); 1343267843Sdelphij if (memcmp("gnu", p, 3) != 0) { 1344267843Sdelphij if (file_printf(ms, 1345267843Sdelphij ", unknown capability %.3s", p) 1346267843Sdelphij == -1) 1347267843Sdelphij return -1; 1348267843Sdelphij break; 1349267843Sdelphij } 1350267843Sdelphij p += strlen(p) + 1; 1351267843Sdelphij tag = *p++; 1352267843Sdelphij memcpy(&len, p, sizeof(len)); 1353267843Sdelphij p += 4; 1354267843Sdelphij len = getu32(swap, len); 1355267843Sdelphij if (tag != 1) { 1356267843Sdelphij if (file_printf(ms, ", unknown gnu" 1357267843Sdelphij " capability tag %d", tag) 1358267843Sdelphij == -1) 1359267843Sdelphij return -1; 1360267843Sdelphij break; 1361267843Sdelphij } 1362267843Sdelphij // gnu attributes 1363267843Sdelphij#endif 1364267843Sdelphij break; 1365267843Sdelphij } 1366186690Sobrien (void)memcpy(xcap_addr, cbuf, xcap_sizeof); 1367186690Sobrien switch (xcap_tag) { 1368186690Sobrien case CA_SUNW_NULL: 1369186690Sobrien break; 1370186690Sobrien case CA_SUNW_HW_1: 1371186690Sobrien cap_hw1 |= xcap_val; 1372186690Sobrien break; 1373186690Sobrien case CA_SUNW_SF_1: 1374186690Sobrien cap_sf1 |= xcap_val; 1375186690Sobrien break; 1376186690Sobrien default: 1377186690Sobrien if (file_printf(ms, 1378186690Sobrien ", with unknown capability " 1379328875Seadler "%#" INT64_T_FORMAT "x = %#" 1380226048Sobrien INT64_T_FORMAT "x", 1381191736Sobrien (unsigned long long)xcap_tag, 1382191736Sobrien (unsigned long long)xcap_val) == -1) 1383186690Sobrien return -1; 1384275668Sdelphij if (nbadcap++ > 2) 1385275668Sdelphij coff = xsh_size; 1386186690Sobrien break; 1387186690Sobrien } 1388186690Sobrien } 1389267843Sdelphij /*FALLTHROUGH*/ 1390267843Sdelphij skip: 1391226048Sobrien default: 1392226048Sobrien break; 1393133359Sobrien } 1394133359Sobrien } 1395267843Sdelphij 1396328875Seadler if (has_debug_info) { 1397328875Seadler if (file_printf(ms, ", with debug_info") == -1) 1398328875Seadler return -1; 1399328875Seadler } 1400159764Sobrien if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1) 1401133359Sobrien return -1; 1402186690Sobrien if (cap_hw1) { 1403186690Sobrien const cap_desc_t *cdp; 1404186690Sobrien switch (mach) { 1405186690Sobrien case EM_SPARC: 1406186690Sobrien case EM_SPARC32PLUS: 1407186690Sobrien case EM_SPARCV9: 1408186690Sobrien cdp = cap_desc_sparc; 1409186690Sobrien break; 1410186690Sobrien case EM_386: 1411186690Sobrien case EM_IA_64: 1412186690Sobrien case EM_AMD64: 1413186690Sobrien cdp = cap_desc_386; 1414186690Sobrien break; 1415186690Sobrien default: 1416186690Sobrien cdp = NULL; 1417186690Sobrien break; 1418186690Sobrien } 1419186690Sobrien if (file_printf(ms, ", uses") == -1) 1420186690Sobrien return -1; 1421186690Sobrien if (cdp) { 1422186690Sobrien while (cdp->cd_name) { 1423186690Sobrien if (cap_hw1 & cdp->cd_mask) { 1424186690Sobrien if (file_printf(ms, 1425186690Sobrien " %s", cdp->cd_name) == -1) 1426186690Sobrien return -1; 1427186690Sobrien cap_hw1 &= ~cdp->cd_mask; 1428186690Sobrien } 1429186690Sobrien ++cdp; 1430186690Sobrien } 1431186690Sobrien if (cap_hw1) 1432186690Sobrien if (file_printf(ms, 1433328875Seadler " unknown hardware capability %#" 1434226048Sobrien INT64_T_FORMAT "x", 1435191736Sobrien (unsigned long long)cap_hw1) == -1) 1436186690Sobrien return -1; 1437186690Sobrien } else { 1438186690Sobrien if (file_printf(ms, 1439328875Seadler " hardware capability %#" INT64_T_FORMAT "x", 1440191736Sobrien (unsigned long long)cap_hw1) == -1) 1441186690Sobrien return -1; 1442186690Sobrien } 1443186690Sobrien } 1444186690Sobrien if (cap_sf1) { 1445186690Sobrien if (cap_sf1 & SF1_SUNW_FPUSED) { 1446186690Sobrien if (file_printf(ms, 1447186690Sobrien (cap_sf1 & SF1_SUNW_FPKNWN) 1448186690Sobrien ? ", uses frame pointer" 1449186690Sobrien : ", not known to use frame pointer") == -1) 1450186690Sobrien return -1; 1451186690Sobrien } 1452186690Sobrien cap_sf1 &= ~SF1_SUNW_MASK; 1453186690Sobrien if (cap_sf1) 1454186690Sobrien if (file_printf(ms, 1455328875Seadler ", with unknown software capability %#" 1456226048Sobrien INT64_T_FORMAT "x", 1457191736Sobrien (unsigned long long)cap_sf1) == -1) 1458186690Sobrien return -1; 1459186690Sobrien } 1460133359Sobrien return 0; 1461133359Sobrien} 1462133359Sobrien 1463133359Sobrien/* 1464133359Sobrien * Look through the program headers of an executable image, searching 1465133359Sobrien * for a PT_INTERP section; if one is found, it's dynamically linked, 1466133359Sobrien * otherwise it's statically linked. 1467133359Sobrien */ 1468133359Sobrienprivate int 1469186690Sobriendophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 1470277592Sdelphij int num, size_t size, off_t fsize, int sh_num, int *flags, 1471277592Sdelphij uint16_t *notecount) 1472133359Sobrien{ 1473133359Sobrien Elf32_Phdr ph32; 1474133359Sobrien Elf64_Phdr ph64; 1475133359Sobrien const char *linking_style = "statically"; 1476277592Sdelphij const char *interp = ""; 1477133359Sobrien unsigned char nbuf[BUFSIZ]; 1478277592Sdelphij char ibuf[BUFSIZ]; 1479226048Sobrien ssize_t bufsize; 1480267843Sdelphij size_t offset, align, len; 1481169942Sobrien 1482159764Sobrien if (size != xph_sizeof) { 1483133359Sobrien if (file_printf(ms, ", corrupted program header size") == -1) 1484186690Sobrien return -1; 1485133359Sobrien return 0; 1486133359Sobrien } 1487169942Sobrien 1488133359Sobrien for ( ; num; num--) { 1489277592Sdelphij if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) { 1490267843Sdelphij file_badread(ms); 1491133359Sobrien return -1; 1492133359Sobrien } 1493169942Sobrien 1494226048Sobrien off += size; 1495277592Sdelphij bufsize = 0; 1496277592Sdelphij align = 4; 1497169942Sobrien 1498226048Sobrien /* Things we can determine before we seek */ 1499159764Sobrien switch (xph_type) { 1500133359Sobrien case PT_DYNAMIC: 1501133359Sobrien linking_style = "dynamically"; 1502133359Sobrien break; 1503277592Sdelphij case PT_NOTE: 1504277592Sdelphij if (sh_num) /* Did this through section headers */ 1505277592Sdelphij continue; 1506277592Sdelphij if (((align = xph_align) & 0x80000000UL) != 0 || 1507277592Sdelphij align < 4) { 1508277592Sdelphij if (file_printf(ms, 1509328875Seadler ", invalid note alignment %#lx", 1510277592Sdelphij (unsigned long)align) == -1) 1511277592Sdelphij return -1; 1512277592Sdelphij align = 4; 1513277592Sdelphij } 1514277592Sdelphij /*FALLTHROUGH*/ 1515133359Sobrien case PT_INTERP: 1516277592Sdelphij len = xph_filesz < sizeof(nbuf) ? xph_filesz 1517277592Sdelphij : sizeof(nbuf); 1518277592Sdelphij bufsize = pread(fd, nbuf, len, xph_offset); 1519277592Sdelphij if (bufsize == -1) { 1520277592Sdelphij file_badread(ms); 1521277592Sdelphij return -1; 1522277592Sdelphij } 1523133359Sobrien break; 1524226048Sobrien default: 1525276415Sdelphij if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 1526226048Sobrien /* Maybe warn here? */ 1527226048Sobrien continue; 1528226048Sobrien } 1529226048Sobrien break; 1530226048Sobrien } 1531226048Sobrien 1532226048Sobrien /* Things we can determine when we seek */ 1533226048Sobrien switch (xph_type) { 1534277592Sdelphij case PT_INTERP: 1535277592Sdelphij if (bufsize && nbuf[0]) { 1536277592Sdelphij nbuf[bufsize - 1] = '\0'; 1537277592Sdelphij interp = (const char *)nbuf; 1538277592Sdelphij } else 1539277592Sdelphij interp = "*empty*"; 1540277592Sdelphij break; 1541133359Sobrien case PT_NOTE: 1542133359Sobrien /* 1543133359Sobrien * This is a PT_NOTE section; loop through all the notes 1544133359Sobrien * in the section. 1545133359Sobrien */ 1546133359Sobrien offset = 0; 1547133359Sobrien for (;;) { 1548133359Sobrien if (offset >= (size_t)bufsize) 1549133359Sobrien break; 1550133359Sobrien offset = donote(ms, nbuf, offset, 1551186690Sobrien (size_t)bufsize, clazz, swap, align, 1552300899Sdelphij flags, notecount, fd, 0, 0, 0); 1553133359Sobrien if (offset == 0) 1554133359Sobrien break; 1555133359Sobrien } 1556133359Sobrien break; 1557175296Sobrien default: 1558175296Sobrien break; 1559133359Sobrien } 1560133359Sobrien } 1561277592Sdelphij if (file_printf(ms, ", %s linked", linking_style) 1562133359Sobrien == -1) 1563277592Sdelphij return -1; 1564277592Sdelphij if (interp[0]) 1565277592Sdelphij if (file_printf(ms, ", interpreter %s", 1566277592Sdelphij file_printable(ibuf, sizeof(ibuf), interp)) == -1) 1567277592Sdelphij return -1; 1568133359Sobrien return 0; 1569133359Sobrien} 1570133359Sobrien 1571133359Sobrien 1572133359Sobrienprotected int 1573133359Sobrienfile_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, 1574133359Sobrien size_t nbytes) 1575133359Sobrien{ 157668349Sobrien union { 1577103373Sobrien int32_t l; 1578103373Sobrien char c[sizeof (int32_t)]; 157968349Sobrien } u; 1580186690Sobrien int clazz; 158168349Sobrien int swap; 1582169942Sobrien struct stat st; 1583169942Sobrien off_t fsize; 1584169942Sobrien int flags = 0; 1585186690Sobrien Elf32_Ehdr elf32hdr; 1586186690Sobrien Elf64_Ehdr elf64hdr; 1587277592Sdelphij uint16_t type, phnum, shnum, notecount; 158868349Sobrien 1589284778Sdelphij if (ms->flags & (MAGIC_MIME|MAGIC_APPLE|MAGIC_EXTENSION)) 1590186690Sobrien return 0; 159168349Sobrien /* 159268349Sobrien * ELF executables have multiple section headers in arbitrary 159368349Sobrien * file locations and thus file(1) cannot determine it from easily. 159468349Sobrien * Instead we traverse thru all section headers until a symbol table 159568349Sobrien * one is found or else the binary is stripped. 1596186690Sobrien * Return immediately if it's not ELF (so we avoid pipe2file unless needed). 159768349Sobrien */ 159868349Sobrien if (buf[EI_MAG0] != ELFMAG0 159968349Sobrien || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) 160068349Sobrien || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) 1601186690Sobrien return 0; 160268349Sobrien 1603186690Sobrien /* 1604186690Sobrien * If we cannot seek, it must be a pipe, socket or fifo. 1605186690Sobrien */ 1606186690Sobrien if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) 1607186690Sobrien fd = file_pipe2file(ms, fd, buf, nbytes); 160868349Sobrien 1609186690Sobrien if (fstat(fd, &st) == -1) { 1610186690Sobrien file_badread(ms); 1611186690Sobrien return -1; 161268349Sobrien } 1613276415Sdelphij if (S_ISREG(st.st_mode) || st.st_size != 0) 1614276415Sdelphij fsize = st.st_size; 1615276415Sdelphij else 1616276415Sdelphij fsize = SIZE_UNKNOWN; 161768349Sobrien 1618186690Sobrien clazz = buf[EI_CLASS]; 161968349Sobrien 1620186690Sobrien switch (clazz) { 1621186690Sobrien case ELFCLASS32: 1622186690Sobrien#undef elf_getu 1623186690Sobrien#define elf_getu(a, b) elf_getu32(a, b) 1624186690Sobrien#undef elfhdr 1625186690Sobrien#define elfhdr elf32hdr 1626186690Sobrien#include "elfclass.h" 1627186690Sobrien case ELFCLASS64: 1628186690Sobrien#undef elf_getu 1629186690Sobrien#define elf_getu(a, b) elf_getu64(a, b) 1630186690Sobrien#undef elfhdr 1631186690Sobrien#define elfhdr elf64hdr 1632186690Sobrien#include "elfclass.h" 1633186690Sobrien default: 1634186690Sobrien if (file_printf(ms, ", unknown class %d", clazz) == -1) 1635186690Sobrien return -1; 1636186690Sobrien break; 163768349Sobrien } 1638133359Sobrien return 0; 163968349Sobrien} 164068349Sobrien#endif 1641