readelf.c revision 275666
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 30267843SdelphijFILE_RCSID("@(#)$File: readelf.c,v 1.103 2014/05/02 02:25:10 christos Exp $") 31191736Sobrien#endif 32191736Sobrien 3368349Sobrien#ifdef BUILTIN_ELF 3468349Sobrien#include <string.h> 3568349Sobrien#include <ctype.h> 3668349Sobrien#include <stdlib.h> 3768349Sobrien#ifdef HAVE_UNISTD_H 3868349Sobrien#include <unistd.h> 3968349Sobrien#endif 4068349Sobrien 4168349Sobrien#include "readelf.h" 42186690Sobrien#include "magic.h" 4368349Sobrien 4468349Sobrien#ifdef ELFCORE 45169942Sobrienprivate int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t, 46169942Sobrien off_t, int *); 4768349Sobrien#endif 48169942Sobrienprivate int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t, 49186690Sobrien off_t, int *, int); 50226048Sobrienprivate int doshn(struct magic_set *, int, int, int, off_t, int, size_t, 51267843Sdelphij off_t, int *, int, int); 52186690Sobrienprivate size_t donote(struct magic_set *, void *, size_t, size_t, int, 53159764Sobrien int, size_t, int *); 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 63275666Sdelphij#define MAX_PHNUM 256 64275666Sdelphij#define MAX_SHNUM 1024 65275666Sdelphij 66275666Sdelphijprivate int 67275666Sdelphijtoomany(struct magic_set *ms, const char *name, uint16_t num) 68275666Sdelphij{ 69275666Sdelphij if (file_printf(ms, ", too many %s header sections (%u)", name, num 70275666Sdelphij ) == -1) 71275666Sdelphij return -1; 72275666Sdelphij return 0; 73275666Sdelphij} 74275666Sdelphij 75133359Sobrienprivate uint16_t 76103373Sobriengetu16(int swap, uint16_t value) 7768349Sobrien{ 7868349Sobrien union { 7968349Sobrien uint16_t ui; 8068349Sobrien char c[2]; 8168349Sobrien } retval, tmpval; 8268349Sobrien 8368349Sobrien if (swap) { 8468349Sobrien tmpval.ui = value; 8568349Sobrien 8668349Sobrien retval.c[0] = tmpval.c[1]; 8768349Sobrien retval.c[1] = tmpval.c[0]; 8868349Sobrien 8968349Sobrien return retval.ui; 9068349Sobrien } else 9168349Sobrien return value; 9268349Sobrien} 9368349Sobrien 94133359Sobrienprivate uint32_t 95103373Sobriengetu32(int swap, uint32_t value) 9668349Sobrien{ 9768349Sobrien union { 9868349Sobrien uint32_t ui; 9968349Sobrien char c[4]; 10068349Sobrien } retval, tmpval; 10168349Sobrien 10268349Sobrien if (swap) { 10368349Sobrien tmpval.ui = value; 10468349Sobrien 10568349Sobrien retval.c[0] = tmpval.c[3]; 10668349Sobrien retval.c[1] = tmpval.c[2]; 10768349Sobrien retval.c[2] = tmpval.c[1]; 10868349Sobrien retval.c[3] = tmpval.c[0]; 10968349Sobrien 11068349Sobrien return retval.ui; 11168349Sobrien } else 11268349Sobrien return value; 11368349Sobrien} 11468349Sobrien 115133359Sobrienprivate uint64_t 116103373Sobriengetu64(int swap, uint64_t value) 11768349Sobrien{ 11868349Sobrien union { 11968349Sobrien uint64_t ui; 12068349Sobrien char c[8]; 12168349Sobrien } retval, tmpval; 12268349Sobrien 12368349Sobrien if (swap) { 12468349Sobrien tmpval.ui = value; 12568349Sobrien 12668349Sobrien retval.c[0] = tmpval.c[7]; 12768349Sobrien retval.c[1] = tmpval.c[6]; 12868349Sobrien retval.c[2] = tmpval.c[5]; 12968349Sobrien retval.c[3] = tmpval.c[4]; 13068349Sobrien retval.c[4] = tmpval.c[3]; 13168349Sobrien retval.c[5] = tmpval.c[2]; 13268349Sobrien retval.c[6] = tmpval.c[1]; 13368349Sobrien retval.c[7] = tmpval.c[0]; 13468349Sobrien 13568349Sobrien return retval.ui; 13668349Sobrien } else 13768349Sobrien return value; 13868349Sobrien} 13968349Sobrien 140186690Sobrien#define elf_getu16(swap, value) getu16(swap, value) 141186690Sobrien#define elf_getu32(swap, value) getu32(swap, value) 142267843Sdelphij#define elf_getu64(swap, value) getu64(swap, value) 143159764Sobrien 144186690Sobrien#define xsh_addr (clazz == ELFCLASS32 \ 145267843Sdelphij ? (void *)&sh32 \ 146267843Sdelphij : (void *)&sh64) 147186690Sobrien#define xsh_sizeof (clazz == ELFCLASS32 \ 148267843Sdelphij ? sizeof(sh32) \ 149267843Sdelphij : sizeof(sh64)) 150267843Sdelphij#define xsh_size (size_t)(clazz == ELFCLASS32 \ 151186690Sobrien ? elf_getu32(swap, sh32.sh_size) \ 152186690Sobrien : elf_getu64(swap, sh64.sh_size)) 153226048Sobrien#define xsh_offset (off_t)(clazz == ELFCLASS32 \ 154186690Sobrien ? elf_getu32(swap, sh32.sh_offset) \ 155186690Sobrien : elf_getu64(swap, sh64.sh_offset)) 156186690Sobrien#define xsh_type (clazz == ELFCLASS32 \ 157186690Sobrien ? elf_getu32(swap, sh32.sh_type) \ 158186690Sobrien : elf_getu32(swap, sh64.sh_type)) 159267843Sdelphij#define xsh_name (clazz == ELFCLASS32 \ 160267843Sdelphij ? elf_getu32(swap, sh32.sh_name) \ 161267843Sdelphij : elf_getu32(swap, sh64.sh_name)) 162186690Sobrien#define xph_addr (clazz == ELFCLASS32 \ 163186690Sobrien ? (void *) &ph32 \ 16468349Sobrien : (void *) &ph64) 165186690Sobrien#define xph_sizeof (clazz == ELFCLASS32 \ 166267843Sdelphij ? sizeof(ph32) \ 167267843Sdelphij : sizeof(ph64)) 168186690Sobrien#define xph_type (clazz == ELFCLASS32 \ 169186690Sobrien ? elf_getu32(swap, ph32.p_type) \ 170186690Sobrien : elf_getu32(swap, ph64.p_type)) 171186690Sobrien#define xph_offset (off_t)(clazz == ELFCLASS32 \ 172186690Sobrien ? elf_getu32(swap, ph32.p_offset) \ 173186690Sobrien : elf_getu64(swap, ph64.p_offset)) 174186690Sobrien#define xph_align (size_t)((clazz == ELFCLASS32 \ 175186690Sobrien ? (off_t) (ph32.p_align ? \ 176186690Sobrien elf_getu32(swap, ph32.p_align) : 4) \ 177186690Sobrien : (off_t) (ph64.p_align ? \ 178186690Sobrien elf_getu64(swap, ph64.p_align) : 4))) 179186690Sobrien#define xph_filesz (size_t)((clazz == ELFCLASS32 \ 180186690Sobrien ? elf_getu32(swap, ph32.p_filesz) \ 181186690Sobrien : elf_getu64(swap, ph64.p_filesz))) 182186690Sobrien#define xnh_addr (clazz == ELFCLASS32 \ 183267843Sdelphij ? (void *)&nh32 \ 184267843Sdelphij : (void *)&nh64) 185186690Sobrien#define xph_memsz (size_t)((clazz == ELFCLASS32 \ 186186690Sobrien ? elf_getu32(swap, ph32.p_memsz) \ 187186690Sobrien : elf_getu64(swap, ph64.p_memsz))) 188186690Sobrien#define xnh_sizeof (clazz == ELFCLASS32 \ 189186690Sobrien ? sizeof nh32 \ 190133359Sobrien : sizeof nh64) 191186690Sobrien#define xnh_type (clazz == ELFCLASS32 \ 192186690Sobrien ? elf_getu32(swap, nh32.n_type) \ 193186690Sobrien : elf_getu32(swap, nh64.n_type)) 194186690Sobrien#define xnh_namesz (clazz == ELFCLASS32 \ 195186690Sobrien ? elf_getu32(swap, nh32.n_namesz) \ 196186690Sobrien : elf_getu32(swap, nh64.n_namesz)) 197186690Sobrien#define xnh_descsz (clazz == ELFCLASS32 \ 198186690Sobrien ? elf_getu32(swap, nh32.n_descsz) \ 199186690Sobrien : elf_getu32(swap, nh64.n_descsz)) 200186690Sobrien#define prpsoffsets(i) (clazz == ELFCLASS32 \ 201186690Sobrien ? prpsoffsets32[i] \ 20268349Sobrien : prpsoffsets64[i]) 203186690Sobrien#define xcap_addr (clazz == ELFCLASS32 \ 204267843Sdelphij ? (void *)&cap32 \ 205267843Sdelphij : (void *)&cap64) 206186690Sobrien#define xcap_sizeof (clazz == ELFCLASS32 \ 207186690Sobrien ? sizeof cap32 \ 208186690Sobrien : sizeof cap64) 209186690Sobrien#define xcap_tag (clazz == ELFCLASS32 \ 210186690Sobrien ? elf_getu32(swap, cap32.c_tag) \ 211186690Sobrien : elf_getu64(swap, cap64.c_tag)) 212186690Sobrien#define xcap_val (clazz == ELFCLASS32 \ 213186690Sobrien ? elf_getu32(swap, cap32.c_un.c_val) \ 214186690Sobrien : elf_getu64(swap, cap64.c_un.c_val)) 21568349Sobrien 21668349Sobrien#ifdef ELFCORE 217186690Sobrien/* 218186690Sobrien * Try larger offsets first to avoid false matches 219186690Sobrien * from earlier data that happen to look like strings. 220186690Sobrien */ 221186690Sobrienstatic const size_t prpsoffsets32[] = { 222186690Sobrien#ifdef USE_NT_PSINFO 223186690Sobrien 104, /* SunOS 5.x (command line) */ 224186690Sobrien 88, /* SunOS 5.x (short name) */ 225186690Sobrien#endif /* USE_NT_PSINFO */ 226186690Sobrien 227186690Sobrien 100, /* SunOS 5.x (command line) */ 228186690Sobrien 84, /* SunOS 5.x (short name) */ 229186690Sobrien 230186690Sobrien 44, /* Linux (command line) */ 231186690Sobrien 28, /* Linux 2.0.36 (short name) */ 232186690Sobrien 23368349Sobrien 8, /* FreeBSD */ 23468349Sobrien}; 23568349Sobrien 236186690Sobrienstatic const size_t prpsoffsets64[] = { 237186690Sobrien#ifdef USE_NT_PSINFO 238186690Sobrien 152, /* SunOS 5.x (command line) */ 239186690Sobrien 136, /* SunOS 5.x (short name) */ 240186690Sobrien#endif /* USE_NT_PSINFO */ 241186690Sobrien 242186690Sobrien 136, /* SunOS 5.x, 64-bit (command line) */ 243186690Sobrien 120, /* SunOS 5.x, 64-bit (short name) */ 244186690Sobrien 245186690Sobrien 56, /* Linux (command line) */ 246186690Sobrien 40, /* Linux (tested on core from 2.4.x, short name) */ 247186690Sobrien 248159764Sobrien 16, /* FreeBSD, 64-bit */ 24968349Sobrien}; 25068349Sobrien 25168349Sobrien#define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0]) 25268349Sobrien#define NOFFSETS64 (sizeof prpsoffsets64 / sizeof prpsoffsets64[0]) 25368349Sobrien 254186690Sobrien#define NOFFSETS (clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64) 25568349Sobrien 25668349Sobrien/* 25768349Sobrien * Look through the program headers of an executable image, searching 25868349Sobrien * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or 25968349Sobrien * "FreeBSD"; if one is found, try looking in various places in its 26068349Sobrien * contents for a 16-character string containing only printable 26168349Sobrien * characters - if found, that string should be the name of the program 26268349Sobrien * that dropped core. Note: right after that 16-character string is, 26368349Sobrien * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and 26468349Sobrien * Linux, a longer string (80 characters, in 5.x, probably other 26568349Sobrien * SVR4-flavored systems, and Linux) containing the start of the 26668349Sobrien * command line for that program. 26768349Sobrien * 268186690Sobrien * SunOS 5.x core files contain two PT_NOTE sections, with the types 269186690Sobrien * NT_PRPSINFO (old) and NT_PSINFO (new). These structs contain the 270186690Sobrien * same info about the command name and command line, so it probably 271186690Sobrien * isn't worthwhile to look for NT_PSINFO, but the offsets are provided 272186690Sobrien * above (see USE_NT_PSINFO), in case we ever decide to do so. The 273186690Sobrien * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent; 274186690Sobrien * the SunOS 5.x file command relies on this (and prefers the latter). 275186690Sobrien * 27668349Sobrien * The signal number probably appears in a section of type NT_PRSTATUS, 27768349Sobrien * but that's also rather OS-dependent, in ways that are harder to 27868349Sobrien * dissect with heuristics, so I'm not bothering with the signal number. 27968349Sobrien * (I suppose the signal number could be of interest in situations where 28068349Sobrien * you don't have the binary of the program that dropped core; if you 28168349Sobrien * *do* have that binary, the debugger will probably tell you what 28268349Sobrien * signal it was.) 28368349Sobrien */ 284103373Sobrien 285103373Sobrien#define OS_STYLE_SVR4 0 286103373Sobrien#define OS_STYLE_FREEBSD 1 287103373Sobrien#define OS_STYLE_NETBSD 2 288103373Sobrien 289186690Sobrienprivate const char os_style_names[][8] = { 290103373Sobrien "SVR4", 291103373Sobrien "FreeBSD", 292103373Sobrien "NetBSD", 293103373Sobrien}; 294103373Sobrien 295226048Sobrien#define FLAGS_DID_CORE 0x01 296226048Sobrien#define FLAGS_DID_NOTE 0x02 297226048Sobrien#define FLAGS_DID_BUILD_ID 0x04 298226048Sobrien#define FLAGS_DID_CORE_STYLE 0x08 299226048Sobrien#define FLAGS_IS_CORE 0x10 300159764Sobrien 301133359Sobrienprivate int 302186690Sobriendophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 303169942Sobrien int num, size_t size, off_t fsize, int *flags) 30468349Sobrien{ 30568349Sobrien Elf32_Phdr ph32; 30668349Sobrien Elf64_Phdr ph64; 307267843Sdelphij size_t offset, len; 308133359Sobrien unsigned char nbuf[BUFSIZ]; 309133359Sobrien ssize_t bufsize; 31068349Sobrien 311159764Sobrien if (size != xph_sizeof) { 312133359Sobrien if (file_printf(ms, ", corrupted program header size") == -1) 313133359Sobrien return -1; 314133359Sobrien return 0; 315133359Sobrien } 316159764Sobrien 31768349Sobrien /* 31868349Sobrien * Loop through all the program headers. 31968349Sobrien */ 32068349Sobrien for ( ; num; num--) { 321267843Sdelphij if (pread(fd, xph_addr, xph_sizeof, off) == -1) { 322133359Sobrien file_badread(ms); 323133359Sobrien return -1; 324133359Sobrien } 325226048Sobrien off += size; 326226048Sobrien 327169942Sobrien if (xph_offset > fsize) { 328226048Sobrien /* Perhaps warn here */ 329169942Sobrien continue; 330169942Sobrien } 331169942Sobrien 332159764Sobrien if (xph_type != PT_NOTE) 33368349Sobrien continue; 33468349Sobrien 33568349Sobrien /* 33668349Sobrien * This is a PT_NOTE section; loop through all the notes 33768349Sobrien * in the section. 33868349Sobrien */ 339267843Sdelphij len = xph_filesz < sizeof(nbuf) ? xph_filesz : sizeof(nbuf); 340267843Sdelphij if ((bufsize = pread(fd, nbuf, len, xph_offset)) == -1) { 341133359Sobrien file_badread(ms); 342133359Sobrien return -1; 343133359Sobrien } 34468349Sobrien offset = 0; 34568349Sobrien for (;;) { 346133359Sobrien if (offset >= (size_t)bufsize) 34768349Sobrien break; 348133359Sobrien offset = donote(ms, nbuf, offset, (size_t)bufsize, 349186690Sobrien clazz, swap, 4, flags); 350133359Sobrien if (offset == 0) 351133359Sobrien break; 35268349Sobrien 353133359Sobrien } 354133359Sobrien } 355133359Sobrien return 0; 356133359Sobrien} 357133359Sobrien#endif 358133359Sobrien 359267843Sdelphijstatic void 360267843Sdelphijdo_note_netbsd_version(struct magic_set *ms, int swap, void *v) 361267843Sdelphij{ 362267843Sdelphij uint32_t desc; 363267843Sdelphij (void)memcpy(&desc, v, sizeof(desc)); 364267843Sdelphij desc = elf_getu32(swap, desc); 365267843Sdelphij 366267843Sdelphij if (file_printf(ms, ", for NetBSD") == -1) 367267843Sdelphij return; 368267843Sdelphij /* 369267843Sdelphij * The version number used to be stuck as 199905, and was thus 370267843Sdelphij * basically content-free. Newer versions of NetBSD have fixed 371267843Sdelphij * this and now use the encoding of __NetBSD_Version__: 372267843Sdelphij * 373267843Sdelphij * MMmmrrpp00 374267843Sdelphij * 375267843Sdelphij * M = major version 376267843Sdelphij * m = minor version 377267843Sdelphij * r = release ["",A-Z,Z[A-Z] but numeric] 378267843Sdelphij * p = patchlevel 379267843Sdelphij */ 380267843Sdelphij if (desc > 100000000U) { 381267843Sdelphij uint32_t ver_patch = (desc / 100) % 100; 382267843Sdelphij uint32_t ver_rel = (desc / 10000) % 100; 383267843Sdelphij uint32_t ver_min = (desc / 1000000) % 100; 384267843Sdelphij uint32_t ver_maj = desc / 100000000; 385267843Sdelphij 386267843Sdelphij if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) 387267843Sdelphij return; 388267843Sdelphij if (ver_rel == 0 && ver_patch != 0) { 389267843Sdelphij if (file_printf(ms, ".%u", ver_patch) == -1) 390267843Sdelphij return; 391267843Sdelphij } else if (ver_rel != 0) { 392267843Sdelphij while (ver_rel > 26) { 393267843Sdelphij if (file_printf(ms, "Z") == -1) 394267843Sdelphij return; 395267843Sdelphij ver_rel -= 26; 396267843Sdelphij } 397267843Sdelphij if (file_printf(ms, "%c", 'A' + ver_rel - 1) 398267843Sdelphij == -1) 399267843Sdelphij return; 400267843Sdelphij } 401267843Sdelphij } 402267843Sdelphij} 403267843Sdelphij 404267843Sdelphijstatic void 405267843Sdelphijdo_note_freebsd_version(struct magic_set *ms, int swap, void *v) 406267843Sdelphij{ 407267843Sdelphij uint32_t desc; 408267843Sdelphij 409267843Sdelphij (void)memcpy(&desc, v, sizeof(desc)); 410267843Sdelphij desc = elf_getu32(swap, desc); 411267843Sdelphij if (file_printf(ms, ", for FreeBSD") == -1) 412267843Sdelphij return; 413267843Sdelphij 414267843Sdelphij /* 415267843Sdelphij * Contents is __FreeBSD_version, whose relation to OS 416267843Sdelphij * versions is defined by a huge table in the Porter's 417267843Sdelphij * Handbook. This is the general scheme: 418267843Sdelphij * 419267843Sdelphij * Releases: 420267843Sdelphij * Mmp000 (before 4.10) 421267843Sdelphij * Mmi0p0 (before 5.0) 422267843Sdelphij * Mmm0p0 423267843Sdelphij * 424267843Sdelphij * Development branches: 425267843Sdelphij * Mmpxxx (before 4.6) 426267843Sdelphij * Mmp1xx (before 4.10) 427267843Sdelphij * Mmi1xx (before 5.0) 428267843Sdelphij * M000xx (pre-M.0) 429267843Sdelphij * Mmm1xx 430267843Sdelphij * 431267843Sdelphij * M = major version 432267843Sdelphij * m = minor version 433267843Sdelphij * i = minor version increment (491000 -> 4.10) 434267843Sdelphij * p = patchlevel 435267843Sdelphij * x = revision 436267843Sdelphij * 437267843Sdelphij * The first release of FreeBSD to use ELF by default 438267843Sdelphij * was version 3.0. 439267843Sdelphij */ 440267843Sdelphij if (desc == 460002) { 441267843Sdelphij if (file_printf(ms, " 4.6.2") == -1) 442267843Sdelphij return; 443267843Sdelphij } else if (desc < 460100) { 444267843Sdelphij if (file_printf(ms, " %d.%d", desc / 100000, 445267843Sdelphij desc / 10000 % 10) == -1) 446267843Sdelphij return; 447267843Sdelphij if (desc / 1000 % 10 > 0) 448267843Sdelphij if (file_printf(ms, ".%d", desc / 1000 % 10) == -1) 449267843Sdelphij return; 450267843Sdelphij if ((desc % 1000 > 0) || (desc % 100000 == 0)) 451267843Sdelphij if (file_printf(ms, " (%d)", desc) == -1) 452267843Sdelphij return; 453267843Sdelphij } else if (desc < 500000) { 454267843Sdelphij if (file_printf(ms, " %d.%d", desc / 100000, 455267843Sdelphij desc / 10000 % 10 + desc / 1000 % 10) == -1) 456267843Sdelphij return; 457267843Sdelphij if (desc / 100 % 10 > 0) { 458267843Sdelphij if (file_printf(ms, " (%d)", desc) == -1) 459267843Sdelphij return; 460267843Sdelphij } else if (desc / 10 % 10 > 0) { 461267843Sdelphij if (file_printf(ms, ".%d", desc / 10 % 10) == -1) 462267843Sdelphij return; 463267843Sdelphij } 464267843Sdelphij } else { 465267843Sdelphij if (file_printf(ms, " %d.%d", desc / 100000, 466267843Sdelphij desc / 1000 % 100) == -1) 467267843Sdelphij return; 468267843Sdelphij if ((desc / 100 % 10 > 0) || 469267843Sdelphij (desc % 100000 / 100 == 0)) { 470267843Sdelphij if (file_printf(ms, " (%d)", desc) == -1) 471267843Sdelphij return; 472267843Sdelphij } else if (desc / 10 % 10 > 0) { 473267843Sdelphij if (file_printf(ms, ".%d", desc / 10 % 10) == -1) 474267843Sdelphij return; 475267843Sdelphij } 476267843Sdelphij } 477267843Sdelphij} 478267843Sdelphij 479133359Sobrienprivate size_t 480186690Sobriendonote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, 481186690Sobrien int clazz, int swap, size_t align, int *flags) 482133359Sobrien{ 483133359Sobrien Elf32_Nhdr nh32; 484133359Sobrien Elf64_Nhdr nh64; 485133359Sobrien size_t noff, doff; 486133359Sobrien#ifdef ELFCORE 487133359Sobrien int os_style = -1; 488133359Sobrien#endif 489133359Sobrien uint32_t namesz, descsz; 490186690Sobrien unsigned char *nbuf = CAST(unsigned char *, vbuf); 491133359Sobrien 492275666Sdelphij if (xnh_sizeof + offset > size) { 493275666Sdelphij /* 494275666Sdelphij * We're out of note headers. 495275666Sdelphij */ 496275666Sdelphij return xnh_sizeof + offset; 497275666Sdelphij } 498275666Sdelphij 499159764Sobrien (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); 500159764Sobrien offset += xnh_sizeof; 501133359Sobrien 502159764Sobrien namesz = xnh_namesz; 503159764Sobrien descsz = xnh_descsz; 504133359Sobrien if ((namesz == 0) && (descsz == 0)) { 505133359Sobrien /* 506133359Sobrien * We're out of note headers. 507133359Sobrien */ 508169942Sobrien return (offset >= size) ? offset : size; 509133359Sobrien } 510133359Sobrien 511133359Sobrien if (namesz & 0x80000000) { 512133359Sobrien (void)file_printf(ms, ", bad note name size 0x%lx", 513133359Sobrien (unsigned long)namesz); 514275666Sdelphij return 0; 515133359Sobrien } 516133359Sobrien 517133359Sobrien if (descsz & 0x80000000) { 518133359Sobrien (void)file_printf(ms, ", bad note description size 0x%lx", 519133359Sobrien (unsigned long)descsz); 520275666Sdelphij return 0; 521133359Sobrien } 522133359Sobrien 523133359Sobrien 524133359Sobrien noff = offset; 525133359Sobrien doff = ELF_ALIGN(offset + namesz); 526133359Sobrien 527133359Sobrien if (offset + namesz > size) { 528133359Sobrien /* 529133359Sobrien * We're past the end of the buffer. 530133359Sobrien */ 531133359Sobrien return doff; 532133359Sobrien } 533133359Sobrien 534133359Sobrien offset = ELF_ALIGN(doff + descsz); 535139368Sobrien if (doff + descsz > size) { 536169942Sobrien /* 537169942Sobrien * We're past the end of the buffer. 538169942Sobrien */ 539169942Sobrien return (offset >= size) ? offset : size; 540133359Sobrien } 541133359Sobrien 542226048Sobrien if ((*flags & (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) == 543226048Sobrien (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) 544169942Sobrien goto core; 545169942Sobrien 546267843Sdelphij if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 && 547267843Sdelphij xnh_type == NT_GNU_VERSION && descsz == 2) { 548267843Sdelphij file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]); 549267843Sdelphij } 550133359Sobrien if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 551159764Sobrien xnh_type == NT_GNU_VERSION && descsz == 16) { 552133359Sobrien uint32_t desc[4]; 553133359Sobrien (void)memcpy(desc, &nbuf[doff], sizeof(desc)); 554133359Sobrien 555133359Sobrien if (file_printf(ms, ", for GNU/") == -1) 556133359Sobrien return size; 557186690Sobrien switch (elf_getu32(swap, desc[0])) { 558133359Sobrien case GNU_OS_LINUX: 559133359Sobrien if (file_printf(ms, "Linux") == -1) 560133359Sobrien return size; 561133359Sobrien break; 562133359Sobrien case GNU_OS_HURD: 563133359Sobrien if (file_printf(ms, "Hurd") == -1) 564133359Sobrien return size; 565133359Sobrien break; 566133359Sobrien case GNU_OS_SOLARIS: 567133359Sobrien if (file_printf(ms, "Solaris") == -1) 568133359Sobrien return size; 569133359Sobrien break; 570186690Sobrien case GNU_OS_KFREEBSD: 571186690Sobrien if (file_printf(ms, "kFreeBSD") == -1) 572186690Sobrien return size; 573186690Sobrien break; 574186690Sobrien case GNU_OS_KNETBSD: 575186690Sobrien if (file_printf(ms, "kNetBSD") == -1) 576186690Sobrien return size; 577186690Sobrien break; 578133359Sobrien default: 579133359Sobrien if (file_printf(ms, "<unknown>") == -1) 580133359Sobrien return size; 581133359Sobrien } 582186690Sobrien if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]), 583186690Sobrien elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1) 584133359Sobrien return size; 585169942Sobrien *flags |= FLAGS_DID_NOTE; 586133359Sobrien return size; 587133359Sobrien } 588133359Sobrien 589226048Sobrien if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 590226048Sobrien xnh_type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) { 591267843Sdelphij uint8_t desc[20]; 592267843Sdelphij uint32_t i; 593267843Sdelphij if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" : 594226048Sobrien "sha1") == -1) 595226048Sobrien return size; 596226048Sobrien (void)memcpy(desc, &nbuf[doff], descsz); 597267843Sdelphij for (i = 0; i < descsz; i++) 598267843Sdelphij if (file_printf(ms, "%02x", desc[i]) == -1) 599226048Sobrien return size; 600226048Sobrien *flags |= FLAGS_DID_BUILD_ID; 601226048Sobrien } 602226048Sobrien 603267843Sdelphij if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 && 604267843Sdelphij xnh_type == NT_NETBSD_PAX && descsz == 4) { 605267843Sdelphij static const char *pax[] = { 606267843Sdelphij "+mprotect", 607267843Sdelphij "-mprotect", 608267843Sdelphij "+segvguard", 609267843Sdelphij "-segvguard", 610267843Sdelphij "+ASLR", 611267843Sdelphij "-ASLR", 612267843Sdelphij }; 613133359Sobrien uint32_t desc; 614267843Sdelphij size_t i; 615267843Sdelphij int did = 0; 616267843Sdelphij 617133359Sobrien (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 618186690Sobrien desc = elf_getu32(swap, desc); 619133359Sobrien 620267843Sdelphij if (desc && file_printf(ms, ", PaX: ") == -1) 621133359Sobrien return size; 622133359Sobrien 623267843Sdelphij for (i = 0; i < __arraycount(pax); i++) { 624267843Sdelphij if (((1 << i) & desc) == 0) 625267843Sdelphij continue; 626267843Sdelphij if (file_printf(ms, "%s%s", did++ ? "," : "", 627267843Sdelphij pax[i]) == -1) 628133359Sobrien return size; 629133359Sobrien } 630133359Sobrien } 63168349Sobrien 632267843Sdelphij if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { 633267843Sdelphij switch (xnh_type) { 634267843Sdelphij case NT_NETBSD_VERSION: 635267843Sdelphij if (descsz == 4) { 636267843Sdelphij do_note_netbsd_version(ms, swap, &nbuf[doff]); 637267843Sdelphij *flags |= FLAGS_DID_NOTE; 638139368Sobrien return size; 639267843Sdelphij } 640267843Sdelphij break; 641267843Sdelphij case NT_NETBSD_MARCH: 642267843Sdelphij if (file_printf(ms, ", compiled for: %.*s", (int)descsz, 643267843Sdelphij (const char *)&nbuf[doff]) == -1) 644139368Sobrien return size; 645267843Sdelphij break; 646267843Sdelphij case NT_NETBSD_CMODEL: 647267843Sdelphij if (file_printf(ms, ", compiler model: %.*s", 648267843Sdelphij (int)descsz, (const char *)&nbuf[doff]) == -1) 649139368Sobrien return size; 650267843Sdelphij break; 651267843Sdelphij default: 652267843Sdelphij if (file_printf(ms, ", note=%u", xnh_type) == -1) 653133359Sobrien return size; 654267843Sdelphij break; 655133359Sobrien } 656133359Sobrien return size; 657133359Sobrien } 658103373Sobrien 659267843Sdelphij if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) { 660267843Sdelphij if (xnh_type == NT_FREEBSD_VERSION && descsz == 4) { 661267843Sdelphij do_note_freebsd_version(ms, swap, &nbuf[doff]); 662267843Sdelphij *flags |= FLAGS_DID_NOTE; 663267843Sdelphij return size; 664267843Sdelphij } 665267843Sdelphij } 666267843Sdelphij 667133359Sobrien if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && 668159764Sobrien xnh_type == NT_OPENBSD_VERSION && descsz == 4) { 669133359Sobrien if (file_printf(ms, ", for OpenBSD") == -1) 670133359Sobrien return size; 671133359Sobrien /* Content of note is always 0 */ 672169942Sobrien *flags |= FLAGS_DID_NOTE; 673133359Sobrien return size; 674133359Sobrien } 675103373Sobrien 676159764Sobrien if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 && 677159764Sobrien xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) { 678159764Sobrien uint32_t desc; 679159764Sobrien if (file_printf(ms, ", for DragonFly") == -1) 680159764Sobrien return size; 681159764Sobrien (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 682186690Sobrien desc = elf_getu32(swap, desc); 683159764Sobrien if (file_printf(ms, " %d.%d.%d", desc / 100000, 684159764Sobrien desc / 10000 % 10, desc % 10000) == -1) 685159764Sobrien return size; 686169942Sobrien *flags |= FLAGS_DID_NOTE; 687159764Sobrien return size; 688159764Sobrien } 689159764Sobrien 690169942Sobriencore: 691133359Sobrien /* 692133359Sobrien * Sigh. The 2.0.36 kernel in Debian 2.1, at 693133359Sobrien * least, doesn't correctly implement name 694133359Sobrien * sections, in core dumps, as specified by 695133359Sobrien * the "Program Linking" section of "UNIX(R) System 696133359Sobrien * V Release 4 Programmer's Guide: ANSI C and 697133359Sobrien * Programming Support Tools", because my copy 698133359Sobrien * clearly says "The first 'namesz' bytes in 'name' 699133359Sobrien * contain a *null-terminated* [emphasis mine] 700133359Sobrien * character representation of the entry's owner 701133359Sobrien * or originator", but the 2.0.36 kernel code 702133359Sobrien * doesn't include the terminating null in the 703133359Sobrien * name.... 704133359Sobrien */ 705133359Sobrien if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) || 706133359Sobrien (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) { 707133359Sobrien os_style = OS_STYLE_SVR4; 708133359Sobrien } 709133359Sobrien 710133359Sobrien if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) { 711133359Sobrien os_style = OS_STYLE_FREEBSD; 712133359Sobrien } 713133359Sobrien 714133359Sobrien if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11) 715133359Sobrien == 0)) { 716133359Sobrien os_style = OS_STYLE_NETBSD; 717133359Sobrien } 718133359Sobrien 719133359Sobrien#ifdef ELFCORE 720169942Sobrien if ((*flags & FLAGS_DID_CORE) != 0) 721169942Sobrien return size; 722169942Sobrien 723175296Sobrien if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) { 724169942Sobrien if (file_printf(ms, ", %s-style", os_style_names[os_style]) 725169942Sobrien == -1) 726169942Sobrien return size; 727175296Sobrien *flags |= FLAGS_DID_CORE_STYLE; 728159764Sobrien } 729133359Sobrien 730159764Sobrien switch (os_style) { 731159764Sobrien case OS_STYLE_NETBSD: 732159764Sobrien if (xnh_type == NT_NETBSD_CORE_PROCINFO) { 733159764Sobrien uint32_t signo; 734159764Sobrien /* 735159764Sobrien * Extract the program name. It is at 736159764Sobrien * offset 0x7c, and is up to 32-bytes, 737159764Sobrien * including the terminating NUL. 738159764Sobrien */ 739159764Sobrien if (file_printf(ms, ", from '%.31s'", 740159764Sobrien &nbuf[doff + 0x7c]) == -1) 741159764Sobrien return size; 742159764Sobrien 743159764Sobrien /* 744159764Sobrien * Extract the signal number. It is at 745159764Sobrien * offset 0x08. 746159764Sobrien */ 747159764Sobrien (void)memcpy(&signo, &nbuf[doff + 0x08], 748159764Sobrien sizeof(signo)); 749159764Sobrien if (file_printf(ms, " (signal %u)", 750186690Sobrien elf_getu32(swap, signo)) == -1) 751159764Sobrien return size; 752175296Sobrien *flags |= FLAGS_DID_CORE; 753133359Sobrien return size; 754159764Sobrien } 755159764Sobrien break; 756133359Sobrien 757159764Sobrien default: 758226048Sobrien if (xnh_type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) { 759159764Sobrien size_t i, j; 760159764Sobrien unsigned char c; 761159764Sobrien /* 762159764Sobrien * Extract the program name. We assume 763159764Sobrien * it to be 16 characters (that's what it 764159764Sobrien * is in SunOS 5.x and Linux). 765159764Sobrien * 766159764Sobrien * Unfortunately, it's at a different offset 767175296Sobrien * in various OSes, so try multiple offsets. 768159764Sobrien * If the characters aren't all printable, 769159764Sobrien * reject it. 770159764Sobrien */ 771159764Sobrien for (i = 0; i < NOFFSETS; i++) { 772175296Sobrien unsigned char *cname, *cp; 773159764Sobrien size_t reloffset = prpsoffsets(i); 774159764Sobrien size_t noffset = doff + reloffset; 775226048Sobrien size_t k; 776159764Sobrien for (j = 0; j < 16; j++, noffset++, 777159764Sobrien reloffset++) { 77868349Sobrien /* 779159764Sobrien * Make sure we're not past 780159764Sobrien * the end of the buffer; if 781159764Sobrien * we are, just give up. 78268349Sobrien */ 783159764Sobrien if (noffset >= size) 784133359Sobrien goto tryanother; 785159764Sobrien 786133359Sobrien /* 787159764Sobrien * Make sure we're not past 788159764Sobrien * the end of the contents; 789159764Sobrien * if we are, this obviously 790159764Sobrien * isn't the right offset. 791133359Sobrien */ 792159764Sobrien if (reloffset >= descsz) 793133359Sobrien goto tryanother; 794159764Sobrien 795159764Sobrien c = nbuf[noffset]; 796159764Sobrien if (c == '\0') { 797159764Sobrien /* 798159764Sobrien * A '\0' at the 799159764Sobrien * beginning is 800159764Sobrien * obviously wrong. 801159764Sobrien * Any other '\0' 802159764Sobrien * means we're done. 803159764Sobrien */ 804159764Sobrien if (j == 0) 805159764Sobrien goto tryanother; 806159764Sobrien else 807159764Sobrien break; 808159764Sobrien } else { 809159764Sobrien /* 810159764Sobrien * A nonprintable 811159764Sobrien * character is also 812159764Sobrien * wrong. 813159764Sobrien */ 814159764Sobrien if (!isprint(c) || isquote(c)) 815159764Sobrien goto tryanother; 816159764Sobrien } 81768349Sobrien } 818159764Sobrien /* 819159764Sobrien * Well, that worked. 820159764Sobrien */ 821226048Sobrien 822226048Sobrien /* 823226048Sobrien * Try next offsets, in case this match is 824226048Sobrien * in the middle of a string. 825226048Sobrien */ 826226048Sobrien for (k = i + 1 ; k < NOFFSETS ; k++) { 827226048Sobrien size_t no; 828226048Sobrien int adjust = 1; 829226048Sobrien if (prpsoffsets(k) >= prpsoffsets(i)) 830226048Sobrien continue; 831226048Sobrien for (no = doff + prpsoffsets(k); 832226048Sobrien no < doff + prpsoffsets(i); no++) 833226048Sobrien adjust = adjust 834226048Sobrien && isprint(nbuf[no]); 835226048Sobrien if (adjust) 836226048Sobrien i = k; 837226048Sobrien } 838226048Sobrien 839175296Sobrien cname = (unsigned char *) 840175296Sobrien &nbuf[doff + prpsoffsets(i)]; 841175296Sobrien for (cp = cname; *cp && isprint(*cp); cp++) 842175296Sobrien continue; 843186690Sobrien /* 844186690Sobrien * Linux apparently appends a space at the end 845186690Sobrien * of the command line: remove it. 846186690Sobrien */ 847186690Sobrien while (cp > cname && isspace(cp[-1])) 848175296Sobrien cp--; 849175296Sobrien if (file_printf(ms, ", from '%.*s'", 850175296Sobrien (int)(cp - cname), cname) == -1) 851159764Sobrien return size; 852175296Sobrien *flags |= FLAGS_DID_CORE; 853133359Sobrien return size; 854133359Sobrien 855159764Sobrien tryanother: 856159764Sobrien ; 857159764Sobrien } 85868349Sobrien } 859159764Sobrien break; 86068349Sobrien } 861133359Sobrien#endif 862133359Sobrien return offset; 86368349Sobrien} 86468349Sobrien 865186690Sobrien/* SunOS 5.x hardware capability descriptions */ 866186690Sobrientypedef struct cap_desc { 867186690Sobrien uint64_t cd_mask; 868186690Sobrien const char *cd_name; 869186690Sobrien} cap_desc_t; 870186690Sobrien 871186690Sobrienstatic const cap_desc_t cap_desc_sparc[] = { 872186690Sobrien { AV_SPARC_MUL32, "MUL32" }, 873186690Sobrien { AV_SPARC_DIV32, "DIV32" }, 874186690Sobrien { AV_SPARC_FSMULD, "FSMULD" }, 875186690Sobrien { AV_SPARC_V8PLUS, "V8PLUS" }, 876186690Sobrien { AV_SPARC_POPC, "POPC" }, 877186690Sobrien { AV_SPARC_VIS, "VIS" }, 878186690Sobrien { AV_SPARC_VIS2, "VIS2" }, 879186690Sobrien { AV_SPARC_ASI_BLK_INIT, "ASI_BLK_INIT" }, 880186690Sobrien { AV_SPARC_FMAF, "FMAF" }, 881186690Sobrien { AV_SPARC_FJFMAU, "FJFMAU" }, 882186690Sobrien { AV_SPARC_IMA, "IMA" }, 883186690Sobrien { 0, NULL } 884186690Sobrien}; 885186690Sobrien 886186690Sobrienstatic const cap_desc_t cap_desc_386[] = { 887186690Sobrien { AV_386_FPU, "FPU" }, 888186690Sobrien { AV_386_TSC, "TSC" }, 889186690Sobrien { AV_386_CX8, "CX8" }, 890186690Sobrien { AV_386_SEP, "SEP" }, 891186690Sobrien { AV_386_AMD_SYSC, "AMD_SYSC" }, 892186690Sobrien { AV_386_CMOV, "CMOV" }, 893186690Sobrien { AV_386_MMX, "MMX" }, 894186690Sobrien { AV_386_AMD_MMX, "AMD_MMX" }, 895186690Sobrien { AV_386_AMD_3DNow, "AMD_3DNow" }, 896186690Sobrien { AV_386_AMD_3DNowx, "AMD_3DNowx" }, 897186690Sobrien { AV_386_FXSR, "FXSR" }, 898186690Sobrien { AV_386_SSE, "SSE" }, 899186690Sobrien { AV_386_SSE2, "SSE2" }, 900186690Sobrien { AV_386_PAUSE, "PAUSE" }, 901186690Sobrien { AV_386_SSE3, "SSE3" }, 902186690Sobrien { AV_386_MON, "MON" }, 903186690Sobrien { AV_386_CX16, "CX16" }, 904186690Sobrien { AV_386_AHF, "AHF" }, 905186690Sobrien { AV_386_TSCP, "TSCP" }, 906186690Sobrien { AV_386_AMD_SSE4A, "AMD_SSE4A" }, 907186690Sobrien { AV_386_POPCNT, "POPCNT" }, 908186690Sobrien { AV_386_AMD_LZCNT, "AMD_LZCNT" }, 909186690Sobrien { AV_386_SSSE3, "SSSE3" }, 910186690Sobrien { AV_386_SSE4_1, "SSE4.1" }, 911186690Sobrien { AV_386_SSE4_2, "SSE4.2" }, 912186690Sobrien { 0, NULL } 913186690Sobrien}; 914186690Sobrien 915133359Sobrienprivate int 916186690Sobriendoshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, 917267843Sdelphij size_t size, off_t fsize, int *flags, int mach, int strtab) 91868349Sobrien{ 919133359Sobrien Elf32_Shdr sh32; 920133359Sobrien Elf64_Shdr sh64; 921159764Sobrien int stripped = 1; 922275666Sdelphij size_t nbadcap = 0; 923159764Sobrien void *nbuf; 924267843Sdelphij off_t noff, coff, name_off; 925186690Sobrien uint64_t cap_hw1 = 0; /* SunOS 5.x hardware capabilites */ 926186690Sobrien uint64_t cap_sf1 = 0; /* SunOS 5.x software capabilites */ 927267843Sdelphij char name[50]; 928133359Sobrien 929159764Sobrien if (size != xsh_sizeof) { 930133359Sobrien if (file_printf(ms, ", corrupted section header size") == -1) 931133359Sobrien return -1; 932133359Sobrien return 0; 933133359Sobrien } 934133359Sobrien 935267843Sdelphij /* Read offset of name section to be able to read section names later */ 936267843Sdelphij if (pread(fd, xsh_addr, xsh_sizeof, off + size * strtab) == -1) { 937267843Sdelphij file_badread(ms); 938267843Sdelphij return -1; 939267843Sdelphij } 940267843Sdelphij name_off = xsh_offset; 941267843Sdelphij 942133359Sobrien for ( ; num; num--) { 943267843Sdelphij /* Read the name of this section. */ 944267843Sdelphij if (pread(fd, name, sizeof(name), name_off + xsh_name) == -1) { 945267843Sdelphij file_badread(ms); 946226048Sobrien return -1; 947226048Sobrien } 948267843Sdelphij name[sizeof(name) - 1] = '\0'; 949267843Sdelphij if (strcmp(name, ".debug_info") == 0) 950267843Sdelphij stripped = 0; 951267843Sdelphij 952267843Sdelphij if (pread(fd, xsh_addr, xsh_sizeof, off) == -1) { 953133359Sobrien file_badread(ms); 954133359Sobrien return -1; 955133359Sobrien } 956226048Sobrien off += size; 957226048Sobrien 958226048Sobrien /* Things we can determine before we seek */ 959159764Sobrien switch (xsh_type) { 960159764Sobrien case SHT_SYMTAB: 961159764Sobrien#if 0 962159764Sobrien case SHT_DYNSYM: 963159764Sobrien#endif 964159764Sobrien stripped = 0; 965159764Sobrien break; 966226048Sobrien default: 967226048Sobrien if (xsh_offset > fsize) { 968226048Sobrien /* Perhaps warn here */ 969226048Sobrien continue; 970226048Sobrien } 971226048Sobrien break; 972226048Sobrien } 973226048Sobrien 974226048Sobrien /* Things we can determine when we seek */ 975226048Sobrien switch (xsh_type) { 976159764Sobrien case SHT_NOTE: 977267843Sdelphij if ((nbuf = malloc(xsh_size)) == NULL) { 978159764Sobrien file_error(ms, errno, "Cannot allocate memory" 979159764Sobrien " for note"); 980159764Sobrien return -1; 981159764Sobrien } 982267843Sdelphij if (pread(fd, nbuf, xsh_size, xsh_offset) == -1) { 983159764Sobrien file_badread(ms); 984159764Sobrien free(nbuf); 985159764Sobrien return -1; 986159764Sobrien } 987159764Sobrien 988159764Sobrien noff = 0; 989159764Sobrien for (;;) { 990191736Sobrien if (noff >= (off_t)xsh_size) 991159764Sobrien break; 992159764Sobrien noff = donote(ms, nbuf, (size_t)noff, 993267843Sdelphij xsh_size, clazz, swap, 4, flags); 994159764Sobrien if (noff == 0) 995159764Sobrien break; 996159764Sobrien } 997159764Sobrien free(nbuf); 998159764Sobrien break; 999186690Sobrien case SHT_SUNW_cap: 1000267843Sdelphij switch (mach) { 1001267843Sdelphij case EM_SPARC: 1002267843Sdelphij case EM_SPARCV9: 1003267843Sdelphij case EM_IA_64: 1004267843Sdelphij case EM_386: 1005267843Sdelphij case EM_AMD64: 1006267843Sdelphij break; 1007267843Sdelphij default: 1008267843Sdelphij goto skip; 1009267843Sdelphij } 1010267843Sdelphij 1011275666Sdelphij if (nbadcap > 5) 1012275666Sdelphij break; 1013267843Sdelphij if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) { 1014226048Sobrien file_badseek(ms); 1015186690Sobrien return -1; 1016186690Sobrien } 1017186690Sobrien coff = 0; 1018186690Sobrien for (;;) { 1019186690Sobrien Elf32_Cap cap32; 1020186690Sobrien Elf64_Cap cap64; 1021191736Sobrien char cbuf[/*CONSTCOND*/ 1022191736Sobrien MAX(sizeof cap32, sizeof cap64)]; 1023226048Sobrien if ((coff += xcap_sizeof) > (off_t)xsh_size) 1024186690Sobrien break; 1025186690Sobrien if (read(fd, cbuf, (size_t)xcap_sizeof) != 1026186690Sobrien (ssize_t)xcap_sizeof) { 1027186690Sobrien file_badread(ms); 1028186690Sobrien return -1; 1029186690Sobrien } 1030267843Sdelphij if (cbuf[0] == 'A') { 1031267843Sdelphij#ifdef notyet 1032267843Sdelphij char *p = cbuf + 1; 1033267843Sdelphij uint32_t len, tag; 1034267843Sdelphij memcpy(&len, p, sizeof(len)); 1035267843Sdelphij p += 4; 1036267843Sdelphij len = getu32(swap, len); 1037267843Sdelphij if (memcmp("gnu", p, 3) != 0) { 1038267843Sdelphij if (file_printf(ms, 1039267843Sdelphij ", unknown capability %.3s", p) 1040267843Sdelphij == -1) 1041267843Sdelphij return -1; 1042267843Sdelphij break; 1043267843Sdelphij } 1044267843Sdelphij p += strlen(p) + 1; 1045267843Sdelphij tag = *p++; 1046267843Sdelphij memcpy(&len, p, sizeof(len)); 1047267843Sdelphij p += 4; 1048267843Sdelphij len = getu32(swap, len); 1049267843Sdelphij if (tag != 1) { 1050267843Sdelphij if (file_printf(ms, ", unknown gnu" 1051267843Sdelphij " capability tag %d", tag) 1052267843Sdelphij == -1) 1053267843Sdelphij return -1; 1054267843Sdelphij break; 1055267843Sdelphij } 1056267843Sdelphij // gnu attributes 1057267843Sdelphij#endif 1058267843Sdelphij break; 1059267843Sdelphij } 1060186690Sobrien (void)memcpy(xcap_addr, cbuf, xcap_sizeof); 1061186690Sobrien switch (xcap_tag) { 1062186690Sobrien case CA_SUNW_NULL: 1063186690Sobrien break; 1064186690Sobrien case CA_SUNW_HW_1: 1065186690Sobrien cap_hw1 |= xcap_val; 1066186690Sobrien break; 1067186690Sobrien case CA_SUNW_SF_1: 1068186690Sobrien cap_sf1 |= xcap_val; 1069186690Sobrien break; 1070186690Sobrien default: 1071186690Sobrien if (file_printf(ms, 1072186690Sobrien ", with unknown capability " 1073226048Sobrien "0x%" INT64_T_FORMAT "x = 0x%" 1074226048Sobrien INT64_T_FORMAT "x", 1075191736Sobrien (unsigned long long)xcap_tag, 1076191736Sobrien (unsigned long long)xcap_val) == -1) 1077186690Sobrien return -1; 1078275666Sdelphij if (nbadcap++ > 2) 1079275666Sdelphij coff = xsh_size; 1080186690Sobrien break; 1081186690Sobrien } 1082186690Sobrien } 1083267843Sdelphij /*FALLTHROUGH*/ 1084267843Sdelphij skip: 1085226048Sobrien default: 1086226048Sobrien break; 1087133359Sobrien } 1088133359Sobrien } 1089267843Sdelphij 1090159764Sobrien if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1) 1091133359Sobrien return -1; 1092186690Sobrien if (cap_hw1) { 1093186690Sobrien const cap_desc_t *cdp; 1094186690Sobrien switch (mach) { 1095186690Sobrien case EM_SPARC: 1096186690Sobrien case EM_SPARC32PLUS: 1097186690Sobrien case EM_SPARCV9: 1098186690Sobrien cdp = cap_desc_sparc; 1099186690Sobrien break; 1100186690Sobrien case EM_386: 1101186690Sobrien case EM_IA_64: 1102186690Sobrien case EM_AMD64: 1103186690Sobrien cdp = cap_desc_386; 1104186690Sobrien break; 1105186690Sobrien default: 1106186690Sobrien cdp = NULL; 1107186690Sobrien break; 1108186690Sobrien } 1109186690Sobrien if (file_printf(ms, ", uses") == -1) 1110186690Sobrien return -1; 1111186690Sobrien if (cdp) { 1112186690Sobrien while (cdp->cd_name) { 1113186690Sobrien if (cap_hw1 & cdp->cd_mask) { 1114186690Sobrien if (file_printf(ms, 1115186690Sobrien " %s", cdp->cd_name) == -1) 1116186690Sobrien return -1; 1117186690Sobrien cap_hw1 &= ~cdp->cd_mask; 1118186690Sobrien } 1119186690Sobrien ++cdp; 1120186690Sobrien } 1121186690Sobrien if (cap_hw1) 1122186690Sobrien if (file_printf(ms, 1123226048Sobrien " unknown hardware capability 0x%" 1124226048Sobrien INT64_T_FORMAT "x", 1125191736Sobrien (unsigned long long)cap_hw1) == -1) 1126186690Sobrien return -1; 1127186690Sobrien } else { 1128186690Sobrien if (file_printf(ms, 1129226048Sobrien " hardware capability 0x%" INT64_T_FORMAT "x", 1130191736Sobrien (unsigned long long)cap_hw1) == -1) 1131186690Sobrien return -1; 1132186690Sobrien } 1133186690Sobrien } 1134186690Sobrien if (cap_sf1) { 1135186690Sobrien if (cap_sf1 & SF1_SUNW_FPUSED) { 1136186690Sobrien if (file_printf(ms, 1137186690Sobrien (cap_sf1 & SF1_SUNW_FPKNWN) 1138186690Sobrien ? ", uses frame pointer" 1139186690Sobrien : ", not known to use frame pointer") == -1) 1140186690Sobrien return -1; 1141186690Sobrien } 1142186690Sobrien cap_sf1 &= ~SF1_SUNW_MASK; 1143186690Sobrien if (cap_sf1) 1144186690Sobrien if (file_printf(ms, 1145226048Sobrien ", with unknown software capability 0x%" 1146226048Sobrien INT64_T_FORMAT "x", 1147191736Sobrien (unsigned long long)cap_sf1) == -1) 1148186690Sobrien return -1; 1149186690Sobrien } 1150133359Sobrien return 0; 1151133359Sobrien} 1152133359Sobrien 1153133359Sobrien/* 1154133359Sobrien * Look through the program headers of an executable image, searching 1155133359Sobrien * for a PT_INTERP section; if one is found, it's dynamically linked, 1156133359Sobrien * otherwise it's statically linked. 1157133359Sobrien */ 1158133359Sobrienprivate int 1159186690Sobriendophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 1160186690Sobrien int num, size_t size, off_t fsize, int *flags, int sh_num) 1161133359Sobrien{ 1162133359Sobrien Elf32_Phdr ph32; 1163133359Sobrien Elf64_Phdr ph64; 1164133359Sobrien const char *linking_style = "statically"; 1165133359Sobrien const char *shared_libraries = ""; 1166133359Sobrien unsigned char nbuf[BUFSIZ]; 1167226048Sobrien ssize_t bufsize; 1168267843Sdelphij size_t offset, align, len; 1169169942Sobrien 1170159764Sobrien if (size != xph_sizeof) { 1171133359Sobrien if (file_printf(ms, ", corrupted program header size") == -1) 1172186690Sobrien return -1; 1173133359Sobrien return 0; 1174133359Sobrien } 1175169942Sobrien 1176133359Sobrien for ( ; num; num--) { 1177267843Sdelphij if (pread(fd, xph_addr, xph_sizeof, off) == -1) { 1178267843Sdelphij file_badread(ms); 1179133359Sobrien return -1; 1180133359Sobrien } 1181169942Sobrien 1182226048Sobrien off += size; 1183169942Sobrien 1184226048Sobrien /* Things we can determine before we seek */ 1185159764Sobrien switch (xph_type) { 1186133359Sobrien case PT_DYNAMIC: 1187133359Sobrien linking_style = "dynamically"; 1188133359Sobrien break; 1189133359Sobrien case PT_INTERP: 1190133359Sobrien shared_libraries = " (uses shared libs)"; 1191133359Sobrien break; 1192226048Sobrien default: 1193226048Sobrien if (xph_offset > fsize) { 1194226048Sobrien /* Maybe warn here? */ 1195226048Sobrien continue; 1196226048Sobrien } 1197226048Sobrien break; 1198226048Sobrien } 1199226048Sobrien 1200226048Sobrien /* Things we can determine when we seek */ 1201226048Sobrien switch (xph_type) { 1202133359Sobrien case PT_NOTE: 1203226048Sobrien if ((align = xph_align) & 0x80000000UL) { 1204133359Sobrien if (file_printf(ms, 1205133359Sobrien ", invalid note alignment 0x%lx", 1206133359Sobrien (unsigned long)align) == -1) 1207133359Sobrien return -1; 1208133359Sobrien align = 4; 1209133359Sobrien } 1210186690Sobrien if (sh_num) 1211186690Sobrien break; 1212133359Sobrien /* 1213133359Sobrien * This is a PT_NOTE section; loop through all the notes 1214133359Sobrien * in the section. 1215133359Sobrien */ 1216267843Sdelphij len = xph_filesz < sizeof(nbuf) ? xph_filesz 1217267843Sdelphij : sizeof(nbuf); 1218267843Sdelphij bufsize = pread(fd, nbuf, len, xph_offset); 1219133359Sobrien if (bufsize == -1) { 1220133359Sobrien file_badread(ms); 1221133359Sobrien return -1; 1222133359Sobrien } 1223133359Sobrien offset = 0; 1224133359Sobrien for (;;) { 1225133359Sobrien if (offset >= (size_t)bufsize) 1226133359Sobrien break; 1227133359Sobrien offset = donote(ms, nbuf, offset, 1228186690Sobrien (size_t)bufsize, clazz, swap, align, 1229169942Sobrien flags); 1230133359Sobrien if (offset == 0) 1231133359Sobrien break; 1232133359Sobrien } 1233133359Sobrien break; 1234175296Sobrien default: 1235175296Sobrien break; 1236133359Sobrien } 1237133359Sobrien } 1238133359Sobrien if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries) 1239133359Sobrien == -1) 1240133359Sobrien return -1; 1241133359Sobrien return 0; 1242133359Sobrien} 1243133359Sobrien 1244133359Sobrien 1245133359Sobrienprotected int 1246133359Sobrienfile_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, 1247133359Sobrien size_t nbytes) 1248133359Sobrien{ 124968349Sobrien union { 1250103373Sobrien int32_t l; 1251103373Sobrien char c[sizeof (int32_t)]; 125268349Sobrien } u; 1253186690Sobrien int clazz; 125468349Sobrien int swap; 1255169942Sobrien struct stat st; 1256169942Sobrien off_t fsize; 1257169942Sobrien int flags = 0; 1258186690Sobrien Elf32_Ehdr elf32hdr; 1259186690Sobrien Elf64_Ehdr elf64hdr; 1260275666Sdelphij uint16_t type, phnum, shnum; 126168349Sobrien 1262191736Sobrien if (ms->flags & (MAGIC_MIME|MAGIC_APPLE)) 1263186690Sobrien return 0; 126468349Sobrien /* 126568349Sobrien * ELF executables have multiple section headers in arbitrary 126668349Sobrien * file locations and thus file(1) cannot determine it from easily. 126768349Sobrien * Instead we traverse thru all section headers until a symbol table 126868349Sobrien * one is found or else the binary is stripped. 1269186690Sobrien * Return immediately if it's not ELF (so we avoid pipe2file unless needed). 127068349Sobrien */ 127168349Sobrien if (buf[EI_MAG0] != ELFMAG0 127268349Sobrien || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) 127368349Sobrien || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) 1274186690Sobrien return 0; 127568349Sobrien 1276186690Sobrien /* 1277186690Sobrien * If we cannot seek, it must be a pipe, socket or fifo. 1278186690Sobrien */ 1279186690Sobrien if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) 1280186690Sobrien fd = file_pipe2file(ms, fd, buf, nbytes); 128168349Sobrien 1282186690Sobrien if (fstat(fd, &st) == -1) { 1283186690Sobrien file_badread(ms); 1284186690Sobrien return -1; 128568349Sobrien } 1286186690Sobrien fsize = st.st_size; 128768349Sobrien 1288186690Sobrien clazz = buf[EI_CLASS]; 128968349Sobrien 1290186690Sobrien switch (clazz) { 1291186690Sobrien case ELFCLASS32: 1292186690Sobrien#undef elf_getu 1293186690Sobrien#define elf_getu(a, b) elf_getu32(a, b) 1294186690Sobrien#undef elfhdr 1295186690Sobrien#define elfhdr elf32hdr 1296186690Sobrien#include "elfclass.h" 1297186690Sobrien case ELFCLASS64: 1298186690Sobrien#undef elf_getu 1299186690Sobrien#define elf_getu(a, b) elf_getu64(a, b) 1300186690Sobrien#undef elfhdr 1301186690Sobrien#define elfhdr elf64hdr 1302186690Sobrien#include "elfclass.h" 1303186690Sobrien default: 1304186690Sobrien if (file_printf(ms, ", unknown class %d", clazz) == -1) 1305186690Sobrien return -1; 1306186690Sobrien break; 130768349Sobrien } 1308133359Sobrien return 0; 130968349Sobrien} 131068349Sobrien#endif 1311