readelf.c revision 337827
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 30337827SeadlerFILE_RCSID("@(#)$File: readelf.c,v 1.144 2018/07/08 23:37:33 christos Exp $") 31191736Sobrien#endif 32191736Sobrien 3368349Sobrien#ifdef BUILTIN_ELF 3468349Sobrien#include <string.h> 3568349Sobrien#include <ctype.h> 3668349Sobrien#include <stdlib.h> 3768349Sobrien#ifdef HAVE_UNISTD_H 3868349Sobrien#include <unistd.h> 3968349Sobrien#endif 4068349Sobrien 4168349Sobrien#include "readelf.h" 42186690Sobrien#include "magic.h" 4368349Sobrien 4468349Sobrien#ifdef ELFCORE 45169942Sobrienprivate int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t, 46276577Sdelphij off_t, int *, uint16_t *); 4768349Sobrien#endif 48169942Sobrienprivate int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t, 49276577Sdelphij off_t, int, int *, uint16_t *); 50226048Sobrienprivate int doshn(struct magic_set *, int, int, int, off_t, int, size_t, 51276577Sdelphij off_t, int, int, int *, uint16_t *); 52186690Sobrienprivate size_t donote(struct magic_set *, void *, size_t, size_t, int, 53298192Sdelphij int, size_t, int *, uint16_t *, int, off_t, int, off_t); 5468349Sobrien 55133359Sobrien#define ELF_ALIGN(a) ((((a) + align - 1) / align) * align) 5668349Sobrien 57159764Sobrien#define isquote(c) (strchr("'\"`", (c)) != NULL) 58159764Sobrien 59133359Sobrienprivate uint16_t getu16(int, uint16_t); 60133359Sobrienprivate uint32_t getu32(int, uint32_t); 61133359Sobrienprivate uint64_t getu64(int, uint64_t); 62133359Sobrien 63275698Sdelphij#define MAX_PHNUM 128 64275698Sdelphij#define MAX_SHNUM 32768 65337827Seadler#define SIZE_UNKNOWN CAST(off_t, -1) 66275666Sdelphij 67275666Sdelphijprivate int 68275666Sdelphijtoomany(struct magic_set *ms, const char *name, uint16_t num) 69275666Sdelphij{ 70337827Seadler if (file_printf(ms, ", too many %s (%u)", name, num) == -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 \ 145337827Seadler ? CAST(void *, &sh32) \ 146337827Seadler : CAST(void *, &sh64)) 147186690Sobrien#define xsh_sizeof (clazz == ELFCLASS32 \ 148267843Sdelphij ? sizeof(sh32) \ 149267843Sdelphij : sizeof(sh64)) 150337827Seadler#define xsh_size CAST(size_t, (clazz == ELFCLASS32 \ 151186690Sobrien ? elf_getu32(swap, sh32.sh_size) \ 152337827Seadler : elf_getu64(swap, sh64.sh_size))) 153337827Seadler#define xsh_offset CAST(off_t, (clazz == ELFCLASS32 \ 154186690Sobrien ? elf_getu32(swap, sh32.sh_offset) \ 155337827Seadler : 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)) 162337827Seadler 163186690Sobrien#define xph_addr (clazz == ELFCLASS32 \ 164337827Seadler ? CAST(void *, &ph32) \ 165337827Seadler : CAST(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)) 172337827Seadler#define xph_offset CAST(off_t, (clazz == ELFCLASS32 \ 173186690Sobrien ? elf_getu32(swap, ph32.p_offset) \ 174337827Seadler : elf_getu64(swap, ph64.p_offset))) 175337827Seadler#define xph_align CAST(size_t, (clazz == ELFCLASS32 \ 176337827Seadler ? CAST(off_t, (ph32.p_align ? \ 177337827Seadler elf_getu32(swap, ph32.p_align) : 4))\ 178337827Seadler : CAST(off_t, (ph64.p_align ? \ 179337827Seadler elf_getu64(swap, ph64.p_align) : 4)))) 180337827Seadler#define xph_vaddr CAST(size_t, (clazz == ELFCLASS32 \ 181337827Seadler ? CAST(off_t, (ph32.p_vaddr ? \ 182337827Seadler elf_getu32(swap, ph32.p_vaddr) : 4))\ 183337827Seadler : CAST(off_t, (ph64.p_vaddr ? \ 184337827Seadler elf_getu64(swap, ph64.p_vaddr) : 4)))) 185337827Seadler#define xph_filesz CAST(size_t, (clazz == ELFCLASS32 \ 186186690Sobrien ? elf_getu32(swap, ph32.p_filesz) \ 187186690Sobrien : elf_getu64(swap, ph64.p_filesz))) 188337827Seadler#define xph_memsz CAST(size_t, ((clazz == ELFCLASS32 \ 189337827Seadler ? elf_getu32(swap, ph32.p_memsz) \ 190337827Seadler : elf_getu64(swap, ph64.p_memsz)))) 191186690Sobrien#define xnh_addr (clazz == ELFCLASS32 \ 192337827Seadler ? CAST(void *, &nh32) \ 193337827Seadler : CAST(void *, &nh64)) 194186690Sobrien#define xnh_sizeof (clazz == ELFCLASS32 \ 195298192Sdelphij ? sizeof(nh32) \ 196298192Sdelphij : sizeof(nh64)) 197186690Sobrien#define xnh_type (clazz == ELFCLASS32 \ 198186690Sobrien ? elf_getu32(swap, nh32.n_type) \ 199186690Sobrien : elf_getu32(swap, nh64.n_type)) 200186690Sobrien#define xnh_namesz (clazz == ELFCLASS32 \ 201186690Sobrien ? elf_getu32(swap, nh32.n_namesz) \ 202186690Sobrien : elf_getu32(swap, nh64.n_namesz)) 203186690Sobrien#define xnh_descsz (clazz == ELFCLASS32 \ 204186690Sobrien ? elf_getu32(swap, nh32.n_descsz) \ 205186690Sobrien : elf_getu32(swap, nh64.n_descsz)) 206337827Seadler 207337827Seadler#define xdh_addr (clazz == ELFCLASS32 \ 208337827Seadler ? CAST(void *, &dh32) \ 209337827Seadler : CAST(void *, &dh64)) 210337827Seadler#define xdh_sizeof (clazz == ELFCLASS32 \ 211337827Seadler ? sizeof(dh32) \ 212337827Seadler : sizeof(dh64)) 213337827Seadler#define xdh_tag (clazz == ELFCLASS32 \ 214337827Seadler ? elf_getu32(swap, dh32.d_tag) \ 215337827Seadler : elf_getu64(swap, dh64.d_tag)) 216337827Seadler#define xdh_val (clazz == ELFCLASS32 \ 217337827Seadler ? elf_getu32(swap, dh32.d_un.d_val) \ 218337827Seadler : elf_getu64(swap, dh64.d_un.d_val)) 219337827Seadler 220186690Sobrien#define xcap_addr (clazz == ELFCLASS32 \ 221337827Seadler ? CAST(void *, &cap32) \ 222337827Seadler : CAST(void *, &cap64)) 223186690Sobrien#define xcap_sizeof (clazz == ELFCLASS32 \ 224337827Seadler ? sizeof(cap32) \ 225337827Seadler : sizeof(cap64)) 226186690Sobrien#define xcap_tag (clazz == ELFCLASS32 \ 227186690Sobrien ? elf_getu32(swap, cap32.c_tag) \ 228186690Sobrien : elf_getu64(swap, cap64.c_tag)) 229186690Sobrien#define xcap_val (clazz == ELFCLASS32 \ 230186690Sobrien ? elf_getu32(swap, cap32.c_un.c_val) \ 231186690Sobrien : elf_getu64(swap, cap64.c_un.c_val)) 232337827Seadler 233298192Sdelphij#define xauxv_addr (clazz == ELFCLASS32 \ 234337827Seadler ? CAST(void *, &auxv32) \ 235337827Seadler : CAST(void *, &auxv64)) 236298192Sdelphij#define xauxv_sizeof (clazz == ELFCLASS32 \ 237298192Sdelphij ? sizeof(auxv32) \ 238298192Sdelphij : sizeof(auxv64)) 239298192Sdelphij#define xauxv_type (clazz == ELFCLASS32 \ 240298192Sdelphij ? elf_getu32(swap, auxv32.a_type) \ 241298192Sdelphij : elf_getu64(swap, auxv64.a_type)) 242298192Sdelphij#define xauxv_val (clazz == ELFCLASS32 \ 243298192Sdelphij ? elf_getu32(swap, auxv32.a_v) \ 244298192Sdelphij : elf_getu64(swap, auxv64.a_v)) 24568349Sobrien 246337827Seadler#define prpsoffsets(i) (clazz == ELFCLASS32 \ 247337827Seadler ? prpsoffsets32[i] \ 248337827Seadler : prpsoffsets64[i]) 249337827Seadler 25068349Sobrien#ifdef ELFCORE 251186690Sobrien/* 252186690Sobrien * Try larger offsets first to avoid false matches 253186690Sobrien * from earlier data that happen to look like strings. 254186690Sobrien */ 255186690Sobrienstatic const size_t prpsoffsets32[] = { 256186690Sobrien#ifdef USE_NT_PSINFO 257186690Sobrien 104, /* SunOS 5.x (command line) */ 258186690Sobrien 88, /* SunOS 5.x (short name) */ 259186690Sobrien#endif /* USE_NT_PSINFO */ 260186690Sobrien 261186690Sobrien 100, /* SunOS 5.x (command line) */ 262186690Sobrien 84, /* SunOS 5.x (short name) */ 263186690Sobrien 264186690Sobrien 44, /* Linux (command line) */ 265186690Sobrien 28, /* Linux 2.0.36 (short name) */ 266186690Sobrien 26768349Sobrien 8, /* FreeBSD */ 26868349Sobrien}; 26968349Sobrien 270186690Sobrienstatic const size_t prpsoffsets64[] = { 271186690Sobrien#ifdef USE_NT_PSINFO 272186690Sobrien 152, /* SunOS 5.x (command line) */ 273186690Sobrien 136, /* SunOS 5.x (short name) */ 274186690Sobrien#endif /* USE_NT_PSINFO */ 275186690Sobrien 276186690Sobrien 136, /* SunOS 5.x, 64-bit (command line) */ 277186690Sobrien 120, /* SunOS 5.x, 64-bit (short name) */ 278186690Sobrien 279186690Sobrien 56, /* Linux (command line) */ 280186690Sobrien 40, /* Linux (tested on core from 2.4.x, short name) */ 281186690Sobrien 282159764Sobrien 16, /* FreeBSD, 64-bit */ 28368349Sobrien}; 28468349Sobrien 285337827Seadler#define NOFFSETS32 (sizeof(prpsoffsets32) / sizeof(prpsoffsets32[0])) 286337827Seadler#define NOFFSETS64 (sizeof(prpsoffsets64) / sizeof(prpsoffsets64[0])) 28768349Sobrien 288186690Sobrien#define NOFFSETS (clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64) 28968349Sobrien 29068349Sobrien/* 29168349Sobrien * Look through the program headers of an executable image, searching 29268349Sobrien * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or 29368349Sobrien * "FreeBSD"; if one is found, try looking in various places in its 29468349Sobrien * contents for a 16-character string containing only printable 29568349Sobrien * characters - if found, that string should be the name of the program 29668349Sobrien * that dropped core. Note: right after that 16-character string is, 29768349Sobrien * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and 29868349Sobrien * Linux, a longer string (80 characters, in 5.x, probably other 29968349Sobrien * SVR4-flavored systems, and Linux) containing the start of the 30068349Sobrien * command line for that program. 30168349Sobrien * 302186690Sobrien * SunOS 5.x core files contain two PT_NOTE sections, with the types 303186690Sobrien * NT_PRPSINFO (old) and NT_PSINFO (new). These structs contain the 304186690Sobrien * same info about the command name and command line, so it probably 305186690Sobrien * isn't worthwhile to look for NT_PSINFO, but the offsets are provided 306186690Sobrien * above (see USE_NT_PSINFO), in case we ever decide to do so. The 307186690Sobrien * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent; 308186690Sobrien * the SunOS 5.x file command relies on this (and prefers the latter). 309186690Sobrien * 31068349Sobrien * The signal number probably appears in a section of type NT_PRSTATUS, 31168349Sobrien * but that's also rather OS-dependent, in ways that are harder to 31268349Sobrien * dissect with heuristics, so I'm not bothering with the signal number. 31368349Sobrien * (I suppose the signal number could be of interest in situations where 31468349Sobrien * you don't have the binary of the program that dropped core; if you 31568349Sobrien * *do* have that binary, the debugger will probably tell you what 31668349Sobrien * signal it was.) 31768349Sobrien */ 318103373Sobrien 319103373Sobrien#define OS_STYLE_SVR4 0 320103373Sobrien#define OS_STYLE_FREEBSD 1 321103373Sobrien#define OS_STYLE_NETBSD 2 322103373Sobrien 323186690Sobrienprivate const char os_style_names[][8] = { 324103373Sobrien "SVR4", 325103373Sobrien "FreeBSD", 326103373Sobrien "NetBSD", 327103373Sobrien}; 328103373Sobrien 329337827Seadler#define FLAGS_CORE_STYLE 0x0003 330159764Sobrien 331337827Seadler#define FLAGS_DID_CORE 0x0004 332337827Seadler#define FLAGS_DID_OS_NOTE 0x0008 333337827Seadler#define FLAGS_DID_BUILD_ID 0x0010 334337827Seadler#define FLAGS_DID_CORE_STYLE 0x0020 335337827Seadler#define FLAGS_DID_NETBSD_PAX 0x0040 336337827Seadler#define FLAGS_DID_NETBSD_MARCH 0x0080 337337827Seadler#define FLAGS_DID_NETBSD_CMODEL 0x0100 338337827Seadler#define FLAGS_DID_NETBSD_EMULATION 0x0200 339337827Seadler#define FLAGS_DID_NETBSD_UNKNOWN 0x0400 340337827Seadler#define FLAGS_IS_CORE 0x0800 341337827Seadler#define FLAGS_DID_AUXV 0x1000 342328874Seadler 343133359Sobrienprivate int 344186690Sobriendophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 345276577Sdelphij int num, size_t size, off_t fsize, int *flags, uint16_t *notecount) 34668349Sobrien{ 34768349Sobrien Elf32_Phdr ph32; 34868349Sobrien Elf64_Phdr ph64; 349267843Sdelphij size_t offset, len; 350133359Sobrien unsigned char nbuf[BUFSIZ]; 351133359Sobrien ssize_t bufsize; 352298192Sdelphij off_t ph_off = off; 353298192Sdelphij int ph_num = num; 35468349Sobrien 355159764Sobrien if (size != xph_sizeof) { 356133359Sobrien if (file_printf(ms, ", corrupted program header size") == -1) 357133359Sobrien return -1; 358133359Sobrien return 0; 359133359Sobrien } 360159764Sobrien 36168349Sobrien /* 36268349Sobrien * Loop through all the program headers. 36368349Sobrien */ 36468349Sobrien for ( ; num; num--) { 365337827Seadler if (pread(fd, xph_addr, xph_sizeof, off) < 366337827Seadler CAST(ssize_t, xph_sizeof)) { 367133359Sobrien file_badread(ms); 368133359Sobrien return -1; 369133359Sobrien } 370226048Sobrien off += size; 371226048Sobrien 372275698Sdelphij if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 373226048Sobrien /* Perhaps warn here */ 374169942Sobrien continue; 375169942Sobrien } 376169942Sobrien 377159764Sobrien if (xph_type != PT_NOTE) 37868349Sobrien continue; 37968349Sobrien 38068349Sobrien /* 38168349Sobrien * This is a PT_NOTE section; loop through all the notes 38268349Sobrien * in the section. 38368349Sobrien */ 384267843Sdelphij len = xph_filesz < sizeof(nbuf) ? xph_filesz : sizeof(nbuf); 385267843Sdelphij if ((bufsize = pread(fd, nbuf, len, xph_offset)) == -1) { 386133359Sobrien file_badread(ms); 387133359Sobrien return -1; 388133359Sobrien } 38968349Sobrien offset = 0; 39068349Sobrien for (;;) { 391133359Sobrien if (offset >= (size_t)bufsize) 39268349Sobrien break; 393133359Sobrien offset = donote(ms, nbuf, offset, (size_t)bufsize, 394298192Sdelphij clazz, swap, 4, flags, notecount, fd, ph_off, 395298192Sdelphij ph_num, fsize); 396133359Sobrien if (offset == 0) 397133359Sobrien break; 39868349Sobrien 399133359Sobrien } 400133359Sobrien } 401133359Sobrien return 0; 402133359Sobrien} 403133359Sobrien#endif 404133359Sobrien 405267843Sdelphijstatic void 406267843Sdelphijdo_note_netbsd_version(struct magic_set *ms, int swap, void *v) 407267843Sdelphij{ 408267843Sdelphij uint32_t desc; 409337827Seadler memcpy(&desc, v, sizeof(desc)); 410267843Sdelphij desc = elf_getu32(swap, desc); 411267843Sdelphij 412267843Sdelphij if (file_printf(ms, ", for NetBSD") == -1) 413267843Sdelphij return; 414267843Sdelphij /* 415267843Sdelphij * The version number used to be stuck as 199905, and was thus 416267843Sdelphij * basically content-free. Newer versions of NetBSD have fixed 417267843Sdelphij * this and now use the encoding of __NetBSD_Version__: 418267843Sdelphij * 419267843Sdelphij * MMmmrrpp00 420267843Sdelphij * 421267843Sdelphij * M = major version 422267843Sdelphij * m = minor version 423267843Sdelphij * r = release ["",A-Z,Z[A-Z] but numeric] 424267843Sdelphij * p = patchlevel 425267843Sdelphij */ 426267843Sdelphij if (desc > 100000000U) { 427267843Sdelphij uint32_t ver_patch = (desc / 100) % 100; 428267843Sdelphij uint32_t ver_rel = (desc / 10000) % 100; 429267843Sdelphij uint32_t ver_min = (desc / 1000000) % 100; 430267843Sdelphij uint32_t ver_maj = desc / 100000000; 431267843Sdelphij 432267843Sdelphij if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) 433267843Sdelphij return; 434267843Sdelphij if (ver_rel == 0 && ver_patch != 0) { 435267843Sdelphij if (file_printf(ms, ".%u", ver_patch) == -1) 436267843Sdelphij return; 437267843Sdelphij } else if (ver_rel != 0) { 438267843Sdelphij while (ver_rel > 26) { 439267843Sdelphij if (file_printf(ms, "Z") == -1) 440267843Sdelphij return; 441267843Sdelphij ver_rel -= 26; 442267843Sdelphij } 443267843Sdelphij if (file_printf(ms, "%c", 'A' + ver_rel - 1) 444267843Sdelphij == -1) 445267843Sdelphij return; 446267843Sdelphij } 447267843Sdelphij } 448267843Sdelphij} 449267843Sdelphij 450267843Sdelphijstatic void 451267843Sdelphijdo_note_freebsd_version(struct magic_set *ms, int swap, void *v) 452267843Sdelphij{ 453267843Sdelphij uint32_t desc; 454267843Sdelphij 455337827Seadler memcpy(&desc, v, sizeof(desc)); 456267843Sdelphij desc = elf_getu32(swap, desc); 457267843Sdelphij if (file_printf(ms, ", for FreeBSD") == -1) 458267843Sdelphij return; 459267843Sdelphij 460267843Sdelphij /* 461267843Sdelphij * Contents is __FreeBSD_version, whose relation to OS 462267843Sdelphij * versions is defined by a huge table in the Porter's 463267843Sdelphij * Handbook. This is the general scheme: 464267843Sdelphij * 465267843Sdelphij * Releases: 466267843Sdelphij * Mmp000 (before 4.10) 467267843Sdelphij * Mmi0p0 (before 5.0) 468267843Sdelphij * Mmm0p0 469267843Sdelphij * 470267843Sdelphij * Development branches: 471267843Sdelphij * Mmpxxx (before 4.6) 472267843Sdelphij * Mmp1xx (before 4.10) 473267843Sdelphij * Mmi1xx (before 5.0) 474267843Sdelphij * M000xx (pre-M.0) 475267843Sdelphij * Mmm1xx 476267843Sdelphij * 477267843Sdelphij * M = major version 478267843Sdelphij * m = minor version 479267843Sdelphij * i = minor version increment (491000 -> 4.10) 480267843Sdelphij * p = patchlevel 481267843Sdelphij * x = revision 482267843Sdelphij * 483267843Sdelphij * The first release of FreeBSD to use ELF by default 484267843Sdelphij * was version 3.0. 485267843Sdelphij */ 486267843Sdelphij if (desc == 460002) { 487267843Sdelphij if (file_printf(ms, " 4.6.2") == -1) 488267843Sdelphij return; 489267843Sdelphij } else if (desc < 460100) { 490267843Sdelphij if (file_printf(ms, " %d.%d", desc / 100000, 491267843Sdelphij desc / 10000 % 10) == -1) 492267843Sdelphij return; 493267843Sdelphij if (desc / 1000 % 10 > 0) 494267843Sdelphij if (file_printf(ms, ".%d", desc / 1000 % 10) == -1) 495267843Sdelphij return; 496267843Sdelphij if ((desc % 1000 > 0) || (desc % 100000 == 0)) 497267843Sdelphij if (file_printf(ms, " (%d)", desc) == -1) 498267843Sdelphij return; 499267843Sdelphij } else if (desc < 500000) { 500267843Sdelphij if (file_printf(ms, " %d.%d", desc / 100000, 501267843Sdelphij desc / 10000 % 10 + desc / 1000 % 10) == -1) 502267843Sdelphij return; 503267843Sdelphij if (desc / 100 % 10 > 0) { 504267843Sdelphij if (file_printf(ms, " (%d)", desc) == -1) 505267843Sdelphij return; 506267843Sdelphij } else if (desc / 10 % 10 > 0) { 507267843Sdelphij if (file_printf(ms, ".%d", desc / 10 % 10) == -1) 508267843Sdelphij return; 509267843Sdelphij } 510267843Sdelphij } else { 511267843Sdelphij if (file_printf(ms, " %d.%d", desc / 100000, 512267843Sdelphij desc / 1000 % 100) == -1) 513267843Sdelphij return; 514267843Sdelphij if ((desc / 100 % 10 > 0) || 515267843Sdelphij (desc % 100000 / 100 == 0)) { 516267843Sdelphij if (file_printf(ms, " (%d)", desc) == -1) 517267843Sdelphij return; 518267843Sdelphij } else if (desc / 10 % 10 > 0) { 519267843Sdelphij if (file_printf(ms, ".%d", desc / 10 % 10) == -1) 520267843Sdelphij return; 521267843Sdelphij } 522267843Sdelphij } 523267843Sdelphij} 524267843Sdelphij 525276577Sdelphijprivate int 526284237Sdelphij/*ARGSUSED*/ 527276577Sdelphijdo_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 528276577Sdelphij int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz, 529276577Sdelphij size_t noff, size_t doff, int *flags) 530133359Sobrien{ 531276577Sdelphij if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 532323281Sgordon type == NT_GNU_BUILD_ID && (descsz >= 4 && descsz <= 20)) { 533276577Sdelphij uint8_t desc[20]; 534309847Sdelphij const char *btype; 535276577Sdelphij uint32_t i; 536276577Sdelphij *flags |= FLAGS_DID_BUILD_ID; 537309847Sdelphij switch (descsz) { 538309847Sdelphij case 8: 539309847Sdelphij btype = "xxHash"; 540309847Sdelphij break; 541309847Sdelphij case 16: 542309847Sdelphij btype = "md5/uuid"; 543309847Sdelphij break; 544309847Sdelphij case 20: 545309847Sdelphij btype = "sha1"; 546309847Sdelphij break; 547309847Sdelphij default: 548309847Sdelphij btype = "unknown"; 549309847Sdelphij break; 550309847Sdelphij } 551309847Sdelphij if (file_printf(ms, ", BuildID[%s]=", btype) == -1) 552276577Sdelphij return 1; 553337827Seadler memcpy(desc, &nbuf[doff], descsz); 554276577Sdelphij for (i = 0; i < descsz; i++) 555276577Sdelphij if (file_printf(ms, "%02x", desc[i]) == -1) 556276577Sdelphij return 1; 557276577Sdelphij return 1; 558275666Sdelphij } 559337827Seadler if (namesz == 4 && strcmp((char *)&nbuf[noff], "Go") == 0 && 560337827Seadler type == NT_GO_BUILD_ID && descsz < 128) { 561337827Seadler if (file_printf(ms, ", Go BuildID=%s", 562337827Seadler (char *)&nbuf[doff]) == -1) 563337827Seadler return 1; 564337827Seadler return 1; 565337827Seadler } 566276577Sdelphij return 0; 567276577Sdelphij} 568275666Sdelphij 569276577Sdelphijprivate int 570276577Sdelphijdo_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 571276577Sdelphij int swap, uint32_t namesz, uint32_t descsz, 572276577Sdelphij size_t noff, size_t doff, int *flags) 573276577Sdelphij{ 574267843Sdelphij if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 && 575276577Sdelphij type == NT_GNU_VERSION && descsz == 2) { 576276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 577267843Sdelphij file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]); 578276577Sdelphij return 1; 579267843Sdelphij } 580276577Sdelphij 581133359Sobrien if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 582276577Sdelphij type == NT_GNU_VERSION && descsz == 16) { 583133359Sobrien uint32_t desc[4]; 584337827Seadler memcpy(desc, &nbuf[doff], sizeof(desc)); 585133359Sobrien 586276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 587133359Sobrien if (file_printf(ms, ", for GNU/") == -1) 588276577Sdelphij return 1; 589186690Sobrien switch (elf_getu32(swap, desc[0])) { 590133359Sobrien case GNU_OS_LINUX: 591133359Sobrien if (file_printf(ms, "Linux") == -1) 592276577Sdelphij return 1; 593133359Sobrien break; 594133359Sobrien case GNU_OS_HURD: 595133359Sobrien if (file_printf(ms, "Hurd") == -1) 596276577Sdelphij return 1; 597133359Sobrien break; 598133359Sobrien case GNU_OS_SOLARIS: 599133359Sobrien if (file_printf(ms, "Solaris") == -1) 600276577Sdelphij return 1; 601133359Sobrien break; 602186690Sobrien case GNU_OS_KFREEBSD: 603186690Sobrien if (file_printf(ms, "kFreeBSD") == -1) 604276577Sdelphij return 1; 605186690Sobrien break; 606186690Sobrien case GNU_OS_KNETBSD: 607186690Sobrien if (file_printf(ms, "kNetBSD") == -1) 608276577Sdelphij return 1; 609186690Sobrien break; 610133359Sobrien default: 611133359Sobrien if (file_printf(ms, "<unknown>") == -1) 612276577Sdelphij return 1; 613133359Sobrien } 614186690Sobrien if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]), 615186690Sobrien elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1) 616276577Sdelphij return 1; 617276577Sdelphij return 1; 618133359Sobrien } 619133359Sobrien 620276577Sdelphij if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { 621276577Sdelphij if (type == NT_NETBSD_VERSION && descsz == 4) { 622276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 623276577Sdelphij do_note_netbsd_version(ms, swap, &nbuf[doff]); 624276577Sdelphij return 1; 625276577Sdelphij } 626226048Sobrien } 627226048Sobrien 628276577Sdelphij if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) { 629276577Sdelphij if (type == NT_FREEBSD_VERSION && descsz == 4) { 630276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 631276577Sdelphij do_note_freebsd_version(ms, swap, &nbuf[doff]); 632276577Sdelphij return 1; 633276577Sdelphij } 634276577Sdelphij } 635276577Sdelphij 636276577Sdelphij if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && 637276577Sdelphij type == NT_OPENBSD_VERSION && descsz == 4) { 638276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 639276577Sdelphij if (file_printf(ms, ", for OpenBSD") == -1) 640276577Sdelphij return 1; 641276577Sdelphij /* Content of note is always 0 */ 642276577Sdelphij return 1; 643276577Sdelphij } 644276577Sdelphij 645276577Sdelphij if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 && 646276577Sdelphij type == NT_DRAGONFLY_VERSION && descsz == 4) { 647276577Sdelphij uint32_t desc; 648276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 649276577Sdelphij if (file_printf(ms, ", for DragonFly") == -1) 650276577Sdelphij return 1; 651337827Seadler memcpy(&desc, &nbuf[doff], sizeof(desc)); 652276577Sdelphij desc = elf_getu32(swap, desc); 653276577Sdelphij if (file_printf(ms, " %d.%d.%d", desc / 100000, 654276577Sdelphij desc / 10000 % 10, desc % 10000) == -1) 655276577Sdelphij return 1; 656276577Sdelphij return 1; 657276577Sdelphij } 658276577Sdelphij return 0; 659276577Sdelphij} 660276577Sdelphij 661276577Sdelphijprivate int 662276577Sdelphijdo_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 663276577Sdelphij int swap, uint32_t namesz, uint32_t descsz, 664276577Sdelphij size_t noff, size_t doff, int *flags) 665276577Sdelphij{ 666267843Sdelphij if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 && 667276577Sdelphij type == NT_NETBSD_PAX && descsz == 4) { 668267843Sdelphij static const char *pax[] = { 669267843Sdelphij "+mprotect", 670267843Sdelphij "-mprotect", 671267843Sdelphij "+segvguard", 672267843Sdelphij "-segvguard", 673267843Sdelphij "+ASLR", 674267843Sdelphij "-ASLR", 675267843Sdelphij }; 676133359Sobrien uint32_t desc; 677267843Sdelphij size_t i; 678267843Sdelphij int did = 0; 679267843Sdelphij 680276577Sdelphij *flags |= FLAGS_DID_NETBSD_PAX; 681337827Seadler memcpy(&desc, &nbuf[doff], sizeof(desc)); 682186690Sobrien desc = elf_getu32(swap, desc); 683133359Sobrien 684267843Sdelphij if (desc && file_printf(ms, ", PaX: ") == -1) 685276577Sdelphij return 1; 686133359Sobrien 687267843Sdelphij for (i = 0; i < __arraycount(pax); i++) { 688284237Sdelphij if (((1 << (int)i) & desc) == 0) 689267843Sdelphij continue; 690267843Sdelphij if (file_printf(ms, "%s%s", did++ ? "," : "", 691267843Sdelphij pax[i]) == -1) 692276577Sdelphij return 1; 693133359Sobrien } 694276577Sdelphij return 1; 695133359Sobrien } 696276577Sdelphij return 0; 697276577Sdelphij} 69868349Sobrien 699276577Sdelphijprivate int 700276577Sdelphijdo_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 701276577Sdelphij int swap, uint32_t namesz, uint32_t descsz, 702276577Sdelphij size_t noff, size_t doff, int *flags, size_t size, int clazz) 703276577Sdelphij{ 704276577Sdelphij#ifdef ELFCORE 705276577Sdelphij int os_style = -1; 706133359Sobrien /* 707133359Sobrien * Sigh. The 2.0.36 kernel in Debian 2.1, at 708133359Sobrien * least, doesn't correctly implement name 709133359Sobrien * sections, in core dumps, as specified by 710133359Sobrien * the "Program Linking" section of "UNIX(R) System 711133359Sobrien * V Release 4 Programmer's Guide: ANSI C and 712133359Sobrien * Programming Support Tools", because my copy 713133359Sobrien * clearly says "The first 'namesz' bytes in 'name' 714133359Sobrien * contain a *null-terminated* [emphasis mine] 715133359Sobrien * character representation of the entry's owner 716133359Sobrien * or originator", but the 2.0.36 kernel code 717133359Sobrien * doesn't include the terminating null in the 718133359Sobrien * name.... 719133359Sobrien */ 720133359Sobrien if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) || 721133359Sobrien (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) { 722133359Sobrien os_style = OS_STYLE_SVR4; 723133359Sobrien } 724133359Sobrien 725133359Sobrien if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) { 726133359Sobrien os_style = OS_STYLE_FREEBSD; 727133359Sobrien } 728133359Sobrien 729133359Sobrien if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11) 730133359Sobrien == 0)) { 731133359Sobrien os_style = OS_STYLE_NETBSD; 732133359Sobrien } 733133359Sobrien 734175296Sobrien if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) { 735169942Sobrien if (file_printf(ms, ", %s-style", os_style_names[os_style]) 736169942Sobrien == -1) 737276577Sdelphij return 1; 738175296Sobrien *flags |= FLAGS_DID_CORE_STYLE; 739328874Seadler *flags |= os_style; 740159764Sobrien } 741133359Sobrien 742159764Sobrien switch (os_style) { 743159764Sobrien case OS_STYLE_NETBSD: 744276577Sdelphij if (type == NT_NETBSD_CORE_PROCINFO) { 745276577Sdelphij char sbuf[512]; 746328874Seadler struct NetBSD_elfcore_procinfo pi; 747328874Seadler memset(&pi, 0, sizeof(pi)); 748328874Seadler memcpy(&pi, nbuf + doff, descsz); 749328874Seadler 750328874Seadler if (file_printf(ms, ", from '%.31s', pid=%u, uid=%u, " 751328874Seadler "gid=%u, nlwps=%u, lwp=%u (signal %u/code %u)", 752276577Sdelphij file_printable(sbuf, sizeof(sbuf), 753328874Seadler CAST(char *, pi.cpi_name)), 754337827Seadler elf_getu32(swap, (uint32_t)pi.cpi_pid), 755328874Seadler elf_getu32(swap, pi.cpi_euid), 756328874Seadler elf_getu32(swap, pi.cpi_egid), 757328874Seadler elf_getu32(swap, pi.cpi_nlwps), 758337827Seadler elf_getu32(swap, (uint32_t)pi.cpi_siglwp), 759328874Seadler elf_getu32(swap, pi.cpi_signo), 760328874Seadler elf_getu32(swap, pi.cpi_sigcode)) == -1) 761276577Sdelphij return 1; 762328874Seadler 763175296Sobrien *flags |= FLAGS_DID_CORE; 764276577Sdelphij return 1; 765159764Sobrien } 766159764Sobrien break; 767133359Sobrien 768159764Sobrien default: 769276577Sdelphij if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) { 770159764Sobrien size_t i, j; 771159764Sobrien unsigned char c; 772159764Sobrien /* 773159764Sobrien * Extract the program name. We assume 774159764Sobrien * it to be 16 characters (that's what it 775159764Sobrien * is in SunOS 5.x and Linux). 776159764Sobrien * 777159764Sobrien * Unfortunately, it's at a different offset 778175296Sobrien * in various OSes, so try multiple offsets. 779159764Sobrien * If the characters aren't all printable, 780159764Sobrien * reject it. 781159764Sobrien */ 782159764Sobrien for (i = 0; i < NOFFSETS; i++) { 783175296Sobrien unsigned char *cname, *cp; 784159764Sobrien size_t reloffset = prpsoffsets(i); 785159764Sobrien size_t noffset = doff + reloffset; 786226048Sobrien size_t k; 787159764Sobrien for (j = 0; j < 16; j++, noffset++, 788159764Sobrien reloffset++) { 78968349Sobrien /* 790159764Sobrien * Make sure we're not past 791159764Sobrien * the end of the buffer; if 792159764Sobrien * we are, just give up. 79368349Sobrien */ 794159764Sobrien if (noffset >= size) 795133359Sobrien goto tryanother; 796159764Sobrien 797133359Sobrien /* 798159764Sobrien * Make sure we're not past 799159764Sobrien * the end of the contents; 800159764Sobrien * if we are, this obviously 801159764Sobrien * isn't the right offset. 802133359Sobrien */ 803159764Sobrien if (reloffset >= descsz) 804133359Sobrien goto tryanother; 805159764Sobrien 806159764Sobrien c = nbuf[noffset]; 807159764Sobrien if (c == '\0') { 808159764Sobrien /* 809159764Sobrien * A '\0' at the 810159764Sobrien * beginning is 811159764Sobrien * obviously wrong. 812159764Sobrien * Any other '\0' 813159764Sobrien * means we're done. 814159764Sobrien */ 815159764Sobrien if (j == 0) 816159764Sobrien goto tryanother; 817159764Sobrien else 818159764Sobrien break; 819159764Sobrien } else { 820159764Sobrien /* 821159764Sobrien * A nonprintable 822159764Sobrien * character is also 823159764Sobrien * wrong. 824159764Sobrien */ 825159764Sobrien if (!isprint(c) || isquote(c)) 826159764Sobrien goto tryanother; 827159764Sobrien } 82868349Sobrien } 829159764Sobrien /* 830159764Sobrien * Well, that worked. 831159764Sobrien */ 832226048Sobrien 833226048Sobrien /* 834226048Sobrien * Try next offsets, in case this match is 835226048Sobrien * in the middle of a string. 836226048Sobrien */ 837276577Sdelphij for (k = i + 1 ; k < NOFFSETS; k++) { 838226048Sobrien size_t no; 839226048Sobrien int adjust = 1; 840226048Sobrien if (prpsoffsets(k) >= prpsoffsets(i)) 841226048Sobrien continue; 842226048Sobrien for (no = doff + prpsoffsets(k); 843226048Sobrien no < doff + prpsoffsets(i); no++) 844226048Sobrien adjust = adjust 845226048Sobrien && isprint(nbuf[no]); 846226048Sobrien if (adjust) 847226048Sobrien i = k; 848226048Sobrien } 849226048Sobrien 850175296Sobrien cname = (unsigned char *) 851175296Sobrien &nbuf[doff + prpsoffsets(i)]; 852337827Seadler for (cp = cname; cp < nbuf + size && *cp 853337827Seadler && isprint(*cp); cp++) 854175296Sobrien continue; 855186690Sobrien /* 856186690Sobrien * Linux apparently appends a space at the end 857186690Sobrien * of the command line: remove it. 858186690Sobrien */ 859186690Sobrien while (cp > cname && isspace(cp[-1])) 860175296Sobrien cp--; 861175296Sobrien if (file_printf(ms, ", from '%.*s'", 862175296Sobrien (int)(cp - cname), cname) == -1) 863276577Sdelphij return 1; 864175296Sobrien *flags |= FLAGS_DID_CORE; 865276577Sdelphij return 1; 866133359Sobrien 867159764Sobrien tryanother: 868159764Sobrien ; 869159764Sobrien } 87068349Sobrien } 871159764Sobrien break; 87268349Sobrien } 873133359Sobrien#endif 874276577Sdelphij return 0; 875276577Sdelphij} 876276577Sdelphij 877298192Sdelphijprivate off_t 878298192Sdelphijget_offset_from_virtaddr(struct magic_set *ms, int swap, int clazz, int fd, 879298192Sdelphij off_t off, int num, off_t fsize, uint64_t virtaddr) 880298192Sdelphij{ 881298192Sdelphij Elf32_Phdr ph32; 882298192Sdelphij Elf64_Phdr ph64; 883298192Sdelphij 884298192Sdelphij /* 885298192Sdelphij * Loop through all the program headers and find the header with 886298192Sdelphij * virtual address in which the "virtaddr" belongs to. 887298192Sdelphij */ 888298192Sdelphij for ( ; num; num--) { 889298192Sdelphij if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) { 890298192Sdelphij file_badread(ms); 891298192Sdelphij return -1; 892298192Sdelphij } 893298192Sdelphij off += xph_sizeof; 894298192Sdelphij 895298192Sdelphij if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 896298192Sdelphij /* Perhaps warn here */ 897298192Sdelphij continue; 898298192Sdelphij } 899298192Sdelphij 900298192Sdelphij if (virtaddr >= xph_vaddr && virtaddr < xph_vaddr + xph_filesz) 901298192Sdelphij return xph_offset + (virtaddr - xph_vaddr); 902298192Sdelphij } 903298192Sdelphij return 0; 904298192Sdelphij} 905298192Sdelphij 906276577Sdelphijprivate size_t 907298192Sdelphijget_string_on_virtaddr(struct magic_set *ms, 908298192Sdelphij int swap, int clazz, int fd, off_t ph_off, int ph_num, 909298192Sdelphij off_t fsize, uint64_t virtaddr, char *buf, ssize_t buflen) 910298192Sdelphij{ 911298192Sdelphij char *bptr; 912298192Sdelphij off_t offset; 913298192Sdelphij 914298192Sdelphij if (buflen == 0) 915298192Sdelphij return 0; 916298192Sdelphij 917298192Sdelphij offset = get_offset_from_virtaddr(ms, swap, clazz, fd, ph_off, ph_num, 918298192Sdelphij fsize, virtaddr); 919328874Seadler if ((buflen = pread(fd, buf, CAST(size_t, buflen), offset)) <= 0) { 920298192Sdelphij file_badread(ms); 921298192Sdelphij return 0; 922298192Sdelphij } 923298192Sdelphij 924298192Sdelphij buf[buflen - 1] = '\0'; 925298192Sdelphij 926298192Sdelphij /* We expect only printable characters, so return if buffer contains 927298192Sdelphij * non-printable character before the '\0' or just '\0'. */ 928298192Sdelphij for (bptr = buf; *bptr && isprint((unsigned char)*bptr); bptr++) 929298192Sdelphij continue; 930298192Sdelphij if (*bptr != '\0') 931298192Sdelphij return 0; 932298192Sdelphij 933298192Sdelphij return bptr - buf; 934298192Sdelphij} 935298192Sdelphij 936298192Sdelphij 937337827Seadler/*ARGSUSED*/ 938298192Sdelphijprivate int 939298192Sdelphijdo_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 940298192Sdelphij int swap, uint32_t namesz __attribute__((__unused__)), 941298192Sdelphij uint32_t descsz __attribute__((__unused__)), 942298192Sdelphij size_t noff __attribute__((__unused__)), size_t doff, 943298192Sdelphij int *flags, size_t size __attribute__((__unused__)), int clazz, 944298192Sdelphij int fd, off_t ph_off, int ph_num, off_t fsize) 945298192Sdelphij{ 946298192Sdelphij#ifdef ELFCORE 947298192Sdelphij Aux32Info auxv32; 948298192Sdelphij Aux64Info auxv64; 949298192Sdelphij size_t elsize = xauxv_sizeof; 950298192Sdelphij const char *tag; 951298192Sdelphij int is_string; 952298192Sdelphij size_t nval; 953298192Sdelphij 954328874Seadler if ((*flags & (FLAGS_IS_CORE|FLAGS_DID_CORE_STYLE)) != 955328874Seadler (FLAGS_IS_CORE|FLAGS_DID_CORE_STYLE)) 956298192Sdelphij return 0; 957298192Sdelphij 958328874Seadler switch (*flags & FLAGS_CORE_STYLE) { 959328874Seadler case OS_STYLE_SVR4: 960328874Seadler if (type != NT_AUXV) 961328874Seadler return 0; 962328874Seadler break; 963328874Seadler#ifdef notyet 964328874Seadler case OS_STYLE_NETBSD: 965328874Seadler if (type != NT_NETBSD_CORE_AUXV) 966328874Seadler return 0; 967328874Seadler break; 968328874Seadler case OS_STYLE_FREEBSD: 969328874Seadler if (type != NT_FREEBSD_PROCSTAT_AUXV) 970328874Seadler return 0; 971328874Seadler break; 972328874Seadler#endif 973328874Seadler default: 974328874Seadler return 0; 975328874Seadler } 976328874Seadler 977298192Sdelphij *flags |= FLAGS_DID_AUXV; 978298192Sdelphij 979298192Sdelphij nval = 0; 980298192Sdelphij for (size_t off = 0; off + elsize <= descsz; off += elsize) { 981337827Seadler memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof); 982298192Sdelphij /* Limit processing to 50 vector entries to prevent DoS */ 983298192Sdelphij if (nval++ >= 50) { 984298192Sdelphij file_error(ms, 0, "Too many ELF Auxv elements"); 985298192Sdelphij return 1; 986298192Sdelphij } 987298192Sdelphij 988298192Sdelphij switch(xauxv_type) { 989298192Sdelphij case AT_LINUX_EXECFN: 990298192Sdelphij is_string = 1; 991298192Sdelphij tag = "execfn"; 992298192Sdelphij break; 993298192Sdelphij case AT_LINUX_PLATFORM: 994298192Sdelphij is_string = 1; 995298192Sdelphij tag = "platform"; 996298192Sdelphij break; 997298192Sdelphij case AT_LINUX_UID: 998298192Sdelphij is_string = 0; 999298192Sdelphij tag = "real uid"; 1000298192Sdelphij break; 1001298192Sdelphij case AT_LINUX_GID: 1002298192Sdelphij is_string = 0; 1003298192Sdelphij tag = "real gid"; 1004298192Sdelphij break; 1005298192Sdelphij case AT_LINUX_EUID: 1006298192Sdelphij is_string = 0; 1007298192Sdelphij tag = "effective uid"; 1008298192Sdelphij break; 1009298192Sdelphij case AT_LINUX_EGID: 1010298192Sdelphij is_string = 0; 1011298192Sdelphij tag = "effective gid"; 1012298192Sdelphij break; 1013298192Sdelphij default: 1014298192Sdelphij is_string = 0; 1015298192Sdelphij tag = NULL; 1016298192Sdelphij break; 1017298192Sdelphij } 1018298192Sdelphij 1019298192Sdelphij if (tag == NULL) 1020298192Sdelphij continue; 1021298192Sdelphij 1022298192Sdelphij if (is_string) { 1023298192Sdelphij char buf[256]; 1024298192Sdelphij ssize_t buflen; 1025298192Sdelphij buflen = get_string_on_virtaddr(ms, swap, clazz, fd, 1026298192Sdelphij ph_off, ph_num, fsize, xauxv_val, buf, sizeof(buf)); 1027298192Sdelphij 1028298192Sdelphij if (buflen == 0) 1029298192Sdelphij continue; 1030298192Sdelphij 1031298192Sdelphij if (file_printf(ms, ", %s: '%s'", tag, buf) == -1) 1032298192Sdelphij return 0; 1033298192Sdelphij } else { 1034298192Sdelphij if (file_printf(ms, ", %s: %d", tag, (int) xauxv_val) 1035298192Sdelphij == -1) 1036298192Sdelphij return 0; 1037298192Sdelphij } 1038298192Sdelphij } 1039298192Sdelphij return 1; 1040298192Sdelphij#else 1041298192Sdelphij return 0; 1042298192Sdelphij#endif 1043298192Sdelphij} 1044298192Sdelphij 1045298192Sdelphijprivate size_t 1046337827Seadlerdodynamic(struct magic_set *ms, void *vbuf, size_t offset, size_t size, 1047337827Seadler int clazz, int swap) 1048337827Seadler{ 1049337827Seadler Elf32_Dyn dh32; 1050337827Seadler Elf64_Dyn dh64; 1051337827Seadler unsigned char *dbuf = CAST(unsigned char *, vbuf); 1052337827Seadler 1053337827Seadler if (xdh_sizeof + offset > size) { 1054337827Seadler /* 1055337827Seadler * We're out of note headers. 1056337827Seadler */ 1057337827Seadler return xdh_sizeof + offset; 1058337827Seadler } 1059337827Seadler 1060337827Seadler memcpy(xdh_addr, &dbuf[offset], xdh_sizeof); 1061337827Seadler offset += xdh_sizeof; 1062337827Seadler 1063337827Seadler switch (xdh_tag) { 1064337827Seadler case DT_FLAGS_1: 1065337827Seadler if (xdh_val == DF_1_PIE) 1066337827Seadler ms->mode |= 0111; 1067337827Seadler else 1068337827Seadler ms->mode &= ~0111; 1069337827Seadler break; 1070337827Seadler default: 1071337827Seadler break; 1072337827Seadler } 1073337827Seadler return offset; 1074337827Seadler} 1075337827Seadler 1076337827Seadler 1077337827Seadlerprivate size_t 1078276577Sdelphijdonote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, 1079298192Sdelphij int clazz, int swap, size_t align, int *flags, uint16_t *notecount, 1080298192Sdelphij int fd, off_t ph_off, int ph_num, off_t fsize) 1081276577Sdelphij{ 1082276577Sdelphij Elf32_Nhdr nh32; 1083276577Sdelphij Elf64_Nhdr nh64; 1084276577Sdelphij size_t noff, doff; 1085276577Sdelphij uint32_t namesz, descsz; 1086276577Sdelphij unsigned char *nbuf = CAST(unsigned char *, vbuf); 1087276577Sdelphij 1088276577Sdelphij if (*notecount == 0) 1089276577Sdelphij return 0; 1090276577Sdelphij --*notecount; 1091276577Sdelphij 1092276577Sdelphij if (xnh_sizeof + offset > size) { 1093276577Sdelphij /* 1094276577Sdelphij * We're out of note headers. 1095276577Sdelphij */ 1096276577Sdelphij return xnh_sizeof + offset; 1097276577Sdelphij } 1098276577Sdelphij 1099337827Seadler memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); 1100276577Sdelphij offset += xnh_sizeof; 1101276577Sdelphij 1102276577Sdelphij namesz = xnh_namesz; 1103276577Sdelphij descsz = xnh_descsz; 1104298192Sdelphij 1105276577Sdelphij if ((namesz == 0) && (descsz == 0)) { 1106276577Sdelphij /* 1107276577Sdelphij * We're out of note headers. 1108276577Sdelphij */ 1109276577Sdelphij return (offset >= size) ? offset : size; 1110276577Sdelphij } 1111276577Sdelphij 1112276577Sdelphij if (namesz & 0x80000000) { 1113337827Seadler file_printf(ms, ", bad note name size %#lx", 1114337827Seadler CAST(unsigned long, namesz)); 1115276577Sdelphij return 0; 1116276577Sdelphij } 1117276577Sdelphij 1118276577Sdelphij if (descsz & 0x80000000) { 1119337827Seadler file_printf(ms, ", bad note description size %#lx", 1120337827Seadler CAST(unsigned long, descsz)); 1121276577Sdelphij return 0; 1122276577Sdelphij } 1123276577Sdelphij 1124276577Sdelphij noff = offset; 1125276577Sdelphij doff = ELF_ALIGN(offset + namesz); 1126276577Sdelphij 1127276577Sdelphij if (offset + namesz > size) { 1128276577Sdelphij /* 1129276577Sdelphij * We're past the end of the buffer. 1130276577Sdelphij */ 1131276577Sdelphij return doff; 1132276577Sdelphij } 1133276577Sdelphij 1134276577Sdelphij offset = ELF_ALIGN(doff + descsz); 1135276577Sdelphij if (doff + descsz > size) { 1136276577Sdelphij /* 1137276577Sdelphij * We're past the end of the buffer. 1138276577Sdelphij */ 1139276577Sdelphij return (offset >= size) ? offset : size; 1140276577Sdelphij } 1141276577Sdelphij 1142298192Sdelphij 1143276577Sdelphij if ((*flags & FLAGS_DID_OS_NOTE) == 0) { 1144276577Sdelphij if (do_os_note(ms, nbuf, xnh_type, swap, 1145276577Sdelphij namesz, descsz, noff, doff, flags)) 1146298192Sdelphij return offset; 1147276577Sdelphij } 1148276577Sdelphij 1149276577Sdelphij if ((*flags & FLAGS_DID_BUILD_ID) == 0) { 1150276577Sdelphij if (do_bid_note(ms, nbuf, xnh_type, swap, 1151276577Sdelphij namesz, descsz, noff, doff, flags)) 1152298192Sdelphij return offset; 1153276577Sdelphij } 1154276577Sdelphij 1155276577Sdelphij if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) { 1156276577Sdelphij if (do_pax_note(ms, nbuf, xnh_type, swap, 1157276577Sdelphij namesz, descsz, noff, doff, flags)) 1158298192Sdelphij return offset; 1159276577Sdelphij } 1160276577Sdelphij 1161276577Sdelphij if ((*flags & FLAGS_DID_CORE) == 0) { 1162276577Sdelphij if (do_core_note(ms, nbuf, xnh_type, swap, 1163276577Sdelphij namesz, descsz, noff, doff, flags, size, clazz)) 1164298192Sdelphij return offset; 1165276577Sdelphij } 1166276577Sdelphij 1167298192Sdelphij if ((*flags & FLAGS_DID_AUXV) == 0) { 1168298192Sdelphij if (do_auxv_note(ms, nbuf, xnh_type, swap, 1169298192Sdelphij namesz, descsz, noff, doff, flags, size, clazz, 1170298192Sdelphij fd, ph_off, ph_num, fsize)) 1171298192Sdelphij return offset; 1172298192Sdelphij } 1173298192Sdelphij 1174337827Seadler if (namesz == 7 && strcmp(CAST(char *, &nbuf[noff]), "NetBSD") == 0) { 1175337827Seadler int descw, flag; 1176337827Seadler const char *str, *tag; 1177276577Sdelphij if (descsz > 100) 1178276577Sdelphij descsz = 100; 1179276577Sdelphij switch (xnh_type) { 1180276577Sdelphij case NT_NETBSD_VERSION: 1181298192Sdelphij return offset; 1182276577Sdelphij case NT_NETBSD_MARCH: 1183337827Seadler flag = FLAGS_DID_NETBSD_MARCH; 1184337827Seadler tag = "compiled for"; 1185276577Sdelphij break; 1186276577Sdelphij case NT_NETBSD_CMODEL: 1187337827Seadler flag = FLAGS_DID_NETBSD_CMODEL; 1188337827Seadler tag = "compiler model"; 1189276577Sdelphij break; 1190337827Seadler case NT_NETBSD_EMULATION: 1191337827Seadler flag = FLAGS_DID_NETBSD_EMULATION; 1192337827Seadler tag = "emulation:"; 1193337827Seadler break; 1194276577Sdelphij default: 1195276577Sdelphij if (*flags & FLAGS_DID_NETBSD_UNKNOWN) 1196298192Sdelphij return offset; 1197276577Sdelphij *flags |= FLAGS_DID_NETBSD_UNKNOWN; 1198276577Sdelphij if (file_printf(ms, ", note=%u", xnh_type) == -1) 1199298192Sdelphij return offset; 1200337827Seadler return offset; 1201276577Sdelphij } 1202337827Seadler 1203337827Seadler if (*flags & flag) 1204337827Seadler return offset; 1205337827Seadler str = CAST(const char *, &nbuf[doff]); 1206337827Seadler descw = CAST(int, descsz); 1207337827Seadler *flags |= flag; 1208337827Seadler file_printf(ms, ", %s: %.*s", tag, descw, str); 1209298192Sdelphij return offset; 1210276577Sdelphij } 1211276577Sdelphij 1212133359Sobrien return offset; 121368349Sobrien} 121468349Sobrien 1215186690Sobrien/* SunOS 5.x hardware capability descriptions */ 1216186690Sobrientypedef struct cap_desc { 1217186690Sobrien uint64_t cd_mask; 1218186690Sobrien const char *cd_name; 1219186690Sobrien} cap_desc_t; 1220186690Sobrien 1221186690Sobrienstatic const cap_desc_t cap_desc_sparc[] = { 1222186690Sobrien { AV_SPARC_MUL32, "MUL32" }, 1223186690Sobrien { AV_SPARC_DIV32, "DIV32" }, 1224186690Sobrien { AV_SPARC_FSMULD, "FSMULD" }, 1225186690Sobrien { AV_SPARC_V8PLUS, "V8PLUS" }, 1226186690Sobrien { AV_SPARC_POPC, "POPC" }, 1227186690Sobrien { AV_SPARC_VIS, "VIS" }, 1228186690Sobrien { AV_SPARC_VIS2, "VIS2" }, 1229186690Sobrien { AV_SPARC_ASI_BLK_INIT, "ASI_BLK_INIT" }, 1230186690Sobrien { AV_SPARC_FMAF, "FMAF" }, 1231186690Sobrien { AV_SPARC_FJFMAU, "FJFMAU" }, 1232186690Sobrien { AV_SPARC_IMA, "IMA" }, 1233186690Sobrien { 0, NULL } 1234186690Sobrien}; 1235186690Sobrien 1236186690Sobrienstatic const cap_desc_t cap_desc_386[] = { 1237186690Sobrien { AV_386_FPU, "FPU" }, 1238186690Sobrien { AV_386_TSC, "TSC" }, 1239186690Sobrien { AV_386_CX8, "CX8" }, 1240186690Sobrien { AV_386_SEP, "SEP" }, 1241186690Sobrien { AV_386_AMD_SYSC, "AMD_SYSC" }, 1242186690Sobrien { AV_386_CMOV, "CMOV" }, 1243186690Sobrien { AV_386_MMX, "MMX" }, 1244186690Sobrien { AV_386_AMD_MMX, "AMD_MMX" }, 1245186690Sobrien { AV_386_AMD_3DNow, "AMD_3DNow" }, 1246186690Sobrien { AV_386_AMD_3DNowx, "AMD_3DNowx" }, 1247186690Sobrien { AV_386_FXSR, "FXSR" }, 1248186690Sobrien { AV_386_SSE, "SSE" }, 1249186690Sobrien { AV_386_SSE2, "SSE2" }, 1250186690Sobrien { AV_386_PAUSE, "PAUSE" }, 1251186690Sobrien { AV_386_SSE3, "SSE3" }, 1252186690Sobrien { AV_386_MON, "MON" }, 1253186690Sobrien { AV_386_CX16, "CX16" }, 1254186690Sobrien { AV_386_AHF, "AHF" }, 1255186690Sobrien { AV_386_TSCP, "TSCP" }, 1256186690Sobrien { AV_386_AMD_SSE4A, "AMD_SSE4A" }, 1257186690Sobrien { AV_386_POPCNT, "POPCNT" }, 1258186690Sobrien { AV_386_AMD_LZCNT, "AMD_LZCNT" }, 1259186690Sobrien { AV_386_SSSE3, "SSSE3" }, 1260186690Sobrien { AV_386_SSE4_1, "SSE4.1" }, 1261186690Sobrien { AV_386_SSE4_2, "SSE4.2" }, 1262186690Sobrien { 0, NULL } 1263186690Sobrien}; 1264186690Sobrien 1265133359Sobrienprivate int 1266186690Sobriendoshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, 1267276577Sdelphij size_t size, off_t fsize, int mach, int strtab, int *flags, 1268276577Sdelphij uint16_t *notecount) 126968349Sobrien{ 1270133359Sobrien Elf32_Shdr sh32; 1271133359Sobrien Elf64_Shdr sh64; 1272328874Seadler int stripped = 1, has_debug_info = 0; 1273275666Sdelphij size_t nbadcap = 0; 1274159764Sobrien void *nbuf; 1275267843Sdelphij off_t noff, coff, name_off; 1276328874Seadler uint64_t cap_hw1 = 0; /* SunOS 5.x hardware capabilities */ 1277328874Seadler uint64_t cap_sf1 = 0; /* SunOS 5.x software capabilities */ 1278267843Sdelphij char name[50]; 1279276577Sdelphij ssize_t namesize; 1280133359Sobrien 1281159764Sobrien if (size != xsh_sizeof) { 1282133359Sobrien if (file_printf(ms, ", corrupted section header size") == -1) 1283133359Sobrien return -1; 1284133359Sobrien return 0; 1285133359Sobrien } 1286133359Sobrien 1287267843Sdelphij /* Read offset of name section to be able to read section names later */ 1288284237Sdelphij if (pread(fd, xsh_addr, xsh_sizeof, CAST(off_t, (off + size * strtab))) 1289337827Seadler < CAST(ssize_t, xsh_sizeof)) { 1290328874Seadler if (file_printf(ms, ", missing section headers") == -1) 1291328874Seadler return -1; 1292328874Seadler return 0; 1293267843Sdelphij } 1294267843Sdelphij name_off = xsh_offset; 1295267843Sdelphij 1296133359Sobrien for ( ; num; num--) { 1297267843Sdelphij /* Read the name of this section. */ 1298337827Seadler if ((namesize = pread(fd, name, sizeof(name) - 1, 1299337827Seadler name_off + xsh_name)) == -1) { 1300267843Sdelphij file_badread(ms); 1301226048Sobrien return -1; 1302226048Sobrien } 1303276577Sdelphij name[namesize] = '\0'; 1304328874Seadler if (strcmp(name, ".debug_info") == 0) { 1305328874Seadler has_debug_info = 1; 1306267843Sdelphij stripped = 0; 1307328874Seadler } 1308267843Sdelphij 1309337827Seadler if (pread(fd, xsh_addr, xsh_sizeof, off) < 1310337827Seadler CAST(ssize_t, xsh_sizeof)) { 1311133359Sobrien file_badread(ms); 1312133359Sobrien return -1; 1313133359Sobrien } 1314226048Sobrien off += size; 1315226048Sobrien 1316226048Sobrien /* Things we can determine before we seek */ 1317159764Sobrien switch (xsh_type) { 1318159764Sobrien case SHT_SYMTAB: 1319159764Sobrien#if 0 1320159764Sobrien case SHT_DYNSYM: 1321159764Sobrien#endif 1322159764Sobrien stripped = 0; 1323159764Sobrien break; 1324226048Sobrien default: 1325275698Sdelphij if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) { 1326226048Sobrien /* Perhaps warn here */ 1327226048Sobrien continue; 1328226048Sobrien } 1329226048Sobrien break; 1330226048Sobrien } 1331226048Sobrien 1332287453Sdelphij 1333226048Sobrien /* Things we can determine when we seek */ 1334226048Sobrien switch (xsh_type) { 1335159764Sobrien case SHT_NOTE: 1336337827Seadler if (CAST(uintmax_t, (xsh_size + xsh_offset)) > 1337337827Seadler CAST(uintmax_t, fsize)) { 1338287453Sdelphij if (file_printf(ms, 1339328874Seadler ", note offset/size %#" INTMAX_T_FORMAT 1340328874Seadler "x+%#" INTMAX_T_FORMAT "x exceeds" 1341328874Seadler " file size %#" INTMAX_T_FORMAT "x", 1342337827Seadler CAST(uintmax_t, xsh_offset), 1343337827Seadler CAST(uintmax_t, xsh_size), 1344337827Seadler CAST(uintmax_t, fsize)) == -1) 1345287453Sdelphij return -1; 1346287453Sdelphij return 0; 1347287453Sdelphij } 1348267843Sdelphij if ((nbuf = malloc(xsh_size)) == NULL) { 1349159764Sobrien file_error(ms, errno, "Cannot allocate memory" 1350159764Sobrien " for note"); 1351159764Sobrien return -1; 1352159764Sobrien } 1353288143Sdelphij if (pread(fd, nbuf, xsh_size, xsh_offset) < 1354337827Seadler CAST(ssize_t, xsh_size)) { 1355159764Sobrien file_badread(ms); 1356159764Sobrien free(nbuf); 1357159764Sobrien return -1; 1358159764Sobrien } 1359159764Sobrien 1360159764Sobrien noff = 0; 1361159764Sobrien for (;;) { 1362337827Seadler if (noff >= CAST(off_t, xsh_size)) 1363159764Sobrien break; 1364337827Seadler noff = donote(ms, nbuf, CAST(size_t, noff), 1365298192Sdelphij xsh_size, clazz, swap, 4, flags, notecount, 1366298192Sdelphij fd, 0, 0, 0); 1367159764Sobrien if (noff == 0) 1368159764Sobrien break; 1369159764Sobrien } 1370159764Sobrien free(nbuf); 1371159764Sobrien break; 1372186690Sobrien case SHT_SUNW_cap: 1373267843Sdelphij switch (mach) { 1374267843Sdelphij case EM_SPARC: 1375267843Sdelphij case EM_SPARCV9: 1376267843Sdelphij case EM_IA_64: 1377267843Sdelphij case EM_386: 1378267843Sdelphij case EM_AMD64: 1379267843Sdelphij break; 1380267843Sdelphij default: 1381267843Sdelphij goto skip; 1382267843Sdelphij } 1383267843Sdelphij 1384275666Sdelphij if (nbadcap > 5) 1385275666Sdelphij break; 1386337827Seadler if (lseek(fd, xsh_offset, SEEK_SET) 1387337827Seadler == CAST(off_t, -1)) { 1388226048Sobrien file_badseek(ms); 1389186690Sobrien return -1; 1390186690Sobrien } 1391186690Sobrien coff = 0; 1392186690Sobrien for (;;) { 1393186690Sobrien Elf32_Cap cap32; 1394186690Sobrien Elf64_Cap cap64; 1395191736Sobrien char cbuf[/*CONSTCOND*/ 1396337827Seadler MAX(sizeof(cap32), sizeof(cap64))]; 1397337827Seadler if ((coff += xcap_sizeof) > 1398337827Seadler CAST(off_t, xsh_size)) 1399186690Sobrien break; 1400337827Seadler if (read(fd, cbuf, CAST(size_t, xcap_sizeof)) != 1401337827Seadler CAST(ssize_t, xcap_sizeof)) { 1402186690Sobrien file_badread(ms); 1403186690Sobrien return -1; 1404186690Sobrien } 1405267843Sdelphij if (cbuf[0] == 'A') { 1406267843Sdelphij#ifdef notyet 1407267843Sdelphij char *p = cbuf + 1; 1408267843Sdelphij uint32_t len, tag; 1409267843Sdelphij memcpy(&len, p, sizeof(len)); 1410267843Sdelphij p += 4; 1411267843Sdelphij len = getu32(swap, len); 1412267843Sdelphij if (memcmp("gnu", p, 3) != 0) { 1413267843Sdelphij if (file_printf(ms, 1414267843Sdelphij ", unknown capability %.3s", p) 1415267843Sdelphij == -1) 1416267843Sdelphij return -1; 1417267843Sdelphij break; 1418267843Sdelphij } 1419267843Sdelphij p += strlen(p) + 1; 1420267843Sdelphij tag = *p++; 1421267843Sdelphij memcpy(&len, p, sizeof(len)); 1422267843Sdelphij p += 4; 1423267843Sdelphij len = getu32(swap, len); 1424267843Sdelphij if (tag != 1) { 1425267843Sdelphij if (file_printf(ms, ", unknown gnu" 1426267843Sdelphij " capability tag %d", tag) 1427267843Sdelphij == -1) 1428267843Sdelphij return -1; 1429267843Sdelphij break; 1430267843Sdelphij } 1431267843Sdelphij // gnu attributes 1432267843Sdelphij#endif 1433267843Sdelphij break; 1434267843Sdelphij } 1435337827Seadler memcpy(xcap_addr, cbuf, xcap_sizeof); 1436186690Sobrien switch (xcap_tag) { 1437186690Sobrien case CA_SUNW_NULL: 1438186690Sobrien break; 1439186690Sobrien case CA_SUNW_HW_1: 1440186690Sobrien cap_hw1 |= xcap_val; 1441186690Sobrien break; 1442186690Sobrien case CA_SUNW_SF_1: 1443186690Sobrien cap_sf1 |= xcap_val; 1444186690Sobrien break; 1445186690Sobrien default: 1446186690Sobrien if (file_printf(ms, 1447186690Sobrien ", with unknown capability " 1448328874Seadler "%#" INT64_T_FORMAT "x = %#" 1449226048Sobrien INT64_T_FORMAT "x", 1450337827Seadler CAST(unsigned long long, xcap_tag), 1451337827Seadler CAST(unsigned long long, xcap_val)) 1452337827Seadler == -1) 1453186690Sobrien return -1; 1454275666Sdelphij if (nbadcap++ > 2) 1455275666Sdelphij coff = xsh_size; 1456186690Sobrien break; 1457186690Sobrien } 1458186690Sobrien } 1459267843Sdelphij /*FALLTHROUGH*/ 1460267843Sdelphij skip: 1461226048Sobrien default: 1462226048Sobrien break; 1463133359Sobrien } 1464133359Sobrien } 1465267843Sdelphij 1466328874Seadler if (has_debug_info) { 1467328874Seadler if (file_printf(ms, ", with debug_info") == -1) 1468328874Seadler return -1; 1469328874Seadler } 1470159764Sobrien if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1) 1471133359Sobrien return -1; 1472186690Sobrien if (cap_hw1) { 1473186690Sobrien const cap_desc_t *cdp; 1474186690Sobrien switch (mach) { 1475186690Sobrien case EM_SPARC: 1476186690Sobrien case EM_SPARC32PLUS: 1477186690Sobrien case EM_SPARCV9: 1478186690Sobrien cdp = cap_desc_sparc; 1479186690Sobrien break; 1480186690Sobrien case EM_386: 1481186690Sobrien case EM_IA_64: 1482186690Sobrien case EM_AMD64: 1483186690Sobrien cdp = cap_desc_386; 1484186690Sobrien break; 1485186690Sobrien default: 1486186690Sobrien cdp = NULL; 1487186690Sobrien break; 1488186690Sobrien } 1489186690Sobrien if (file_printf(ms, ", uses") == -1) 1490186690Sobrien return -1; 1491186690Sobrien if (cdp) { 1492186690Sobrien while (cdp->cd_name) { 1493186690Sobrien if (cap_hw1 & cdp->cd_mask) { 1494186690Sobrien if (file_printf(ms, 1495186690Sobrien " %s", cdp->cd_name) == -1) 1496186690Sobrien return -1; 1497186690Sobrien cap_hw1 &= ~cdp->cd_mask; 1498186690Sobrien } 1499186690Sobrien ++cdp; 1500186690Sobrien } 1501186690Sobrien if (cap_hw1) 1502186690Sobrien if (file_printf(ms, 1503328874Seadler " unknown hardware capability %#" 1504226048Sobrien INT64_T_FORMAT "x", 1505337827Seadler CAST(unsigned long long, cap_hw1)) == -1) 1506186690Sobrien return -1; 1507186690Sobrien } else { 1508186690Sobrien if (file_printf(ms, 1509328874Seadler " hardware capability %#" INT64_T_FORMAT "x", 1510337827Seadler CAST(unsigned long long, cap_hw1)) == -1) 1511186690Sobrien return -1; 1512186690Sobrien } 1513186690Sobrien } 1514186690Sobrien if (cap_sf1) { 1515186690Sobrien if (cap_sf1 & SF1_SUNW_FPUSED) { 1516186690Sobrien if (file_printf(ms, 1517186690Sobrien (cap_sf1 & SF1_SUNW_FPKNWN) 1518186690Sobrien ? ", uses frame pointer" 1519186690Sobrien : ", not known to use frame pointer") == -1) 1520186690Sobrien return -1; 1521186690Sobrien } 1522186690Sobrien cap_sf1 &= ~SF1_SUNW_MASK; 1523186690Sobrien if (cap_sf1) 1524186690Sobrien if (file_printf(ms, 1525328874Seadler ", with unknown software capability %#" 1526226048Sobrien INT64_T_FORMAT "x", 1527337827Seadler CAST(unsigned long long, cap_sf1)) == -1) 1528186690Sobrien return -1; 1529186690Sobrien } 1530133359Sobrien return 0; 1531133359Sobrien} 1532133359Sobrien 1533133359Sobrien/* 1534133359Sobrien * Look through the program headers of an executable image, searching 1535133359Sobrien * for a PT_INTERP section; if one is found, it's dynamically linked, 1536133359Sobrien * otherwise it's statically linked. 1537133359Sobrien */ 1538133359Sobrienprivate int 1539186690Sobriendophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 1540276577Sdelphij int num, size_t size, off_t fsize, int sh_num, int *flags, 1541276577Sdelphij uint16_t *notecount) 1542133359Sobrien{ 1543133359Sobrien Elf32_Phdr ph32; 1544133359Sobrien Elf64_Phdr ph64; 1545133359Sobrien const char *linking_style = "statically"; 1546133359Sobrien unsigned char nbuf[BUFSIZ]; 1547276577Sdelphij char ibuf[BUFSIZ]; 1548337827Seadler char interp[BUFSIZ]; 1549226048Sobrien ssize_t bufsize; 1550267843Sdelphij size_t offset, align, len; 1551169942Sobrien 1552159764Sobrien if (size != xph_sizeof) { 1553133359Sobrien if (file_printf(ms, ", corrupted program header size") == -1) 1554186690Sobrien return -1; 1555133359Sobrien return 0; 1556133359Sobrien } 1557169942Sobrien 1558337827Seadler interp[0] = '\0'; 1559133359Sobrien for ( ; num; num--) { 1560337827Seadler int doread; 1561337827Seadler if (pread(fd, xph_addr, xph_sizeof, off) < 1562337827Seadler CAST(ssize_t, xph_sizeof)) { 1563267843Sdelphij file_badread(ms); 1564133359Sobrien return -1; 1565133359Sobrien } 1566169942Sobrien 1567226048Sobrien off += size; 1568276577Sdelphij bufsize = 0; 1569276577Sdelphij align = 4; 1570169942Sobrien 1571226048Sobrien /* Things we can determine before we seek */ 1572159764Sobrien switch (xph_type) { 1573133359Sobrien case PT_DYNAMIC: 1574133359Sobrien linking_style = "dynamically"; 1575337827Seadler doread = 1; 1576133359Sobrien break; 1577276577Sdelphij case PT_NOTE: 1578276577Sdelphij if (sh_num) /* Did this through section headers */ 1579276577Sdelphij continue; 1580276577Sdelphij if (((align = xph_align) & 0x80000000UL) != 0 || 1581276577Sdelphij align < 4) { 1582276577Sdelphij if (file_printf(ms, 1583328874Seadler ", invalid note alignment %#lx", 1584337827Seadler CAST(unsigned long, align)) == -1) 1585276577Sdelphij return -1; 1586276577Sdelphij align = 4; 1587276577Sdelphij } 1588276577Sdelphij /*FALLTHROUGH*/ 1589133359Sobrien case PT_INTERP: 1590337827Seadler doread = 1; 1591133359Sobrien break; 1592226048Sobrien default: 1593337827Seadler doread = 0; 1594275698Sdelphij if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 1595226048Sobrien /* Maybe warn here? */ 1596226048Sobrien continue; 1597226048Sobrien } 1598226048Sobrien break; 1599226048Sobrien } 1600226048Sobrien 1601337827Seadler if (doread) { 1602337827Seadler len = xph_filesz < sizeof(nbuf) ? xph_filesz 1603337827Seadler : sizeof(nbuf); 1604337827Seadler bufsize = pread(fd, nbuf, len, xph_offset); 1605337827Seadler if (bufsize == -1) { 1606337827Seadler file_badread(ms); 1607337827Seadler return -1; 1608337827Seadler } 1609337827Seadler } else 1610337827Seadler len = 0; 1611337827Seadler 1612226048Sobrien /* Things we can determine when we seek */ 1613226048Sobrien switch (xph_type) { 1614337827Seadler case PT_DYNAMIC: 1615337827Seadler offset = 0; 1616337827Seadler for (;;) { 1617337827Seadler if (offset >= (size_t)bufsize) 1618337827Seadler break; 1619337827Seadler offset = dodynamic(ms, nbuf, offset, 1620337827Seadler CAST(size_t, bufsize), clazz, swap); 1621337827Seadler if (offset == 0) 1622337827Seadler break; 1623337827Seadler } 1624337827Seadler break; 1625337827Seadler 1626276577Sdelphij case PT_INTERP: 1627276577Sdelphij if (bufsize && nbuf[0]) { 1628276577Sdelphij nbuf[bufsize - 1] = '\0'; 1629337827Seadler memcpy(interp, nbuf, bufsize); 1630276577Sdelphij } else 1631337827Seadler strlcpy(interp, "*empty*", sizeof(interp)); 1632276577Sdelphij break; 1633133359Sobrien case PT_NOTE: 1634133359Sobrien /* 1635133359Sobrien * This is a PT_NOTE section; loop through all the notes 1636133359Sobrien * in the section. 1637133359Sobrien */ 1638133359Sobrien offset = 0; 1639133359Sobrien for (;;) { 1640133359Sobrien if (offset >= (size_t)bufsize) 1641133359Sobrien break; 1642133359Sobrien offset = donote(ms, nbuf, offset, 1643337827Seadler CAST(size_t, bufsize), clazz, swap, align, 1644298192Sdelphij flags, notecount, fd, 0, 0, 0); 1645133359Sobrien if (offset == 0) 1646133359Sobrien break; 1647133359Sobrien } 1648133359Sobrien break; 1649175296Sobrien default: 1650175296Sobrien break; 1651133359Sobrien } 1652133359Sobrien } 1653276577Sdelphij if (file_printf(ms, ", %s linked", linking_style) 1654133359Sobrien == -1) 1655276577Sdelphij return -1; 1656276577Sdelphij if (interp[0]) 1657276577Sdelphij if (file_printf(ms, ", interpreter %s", 1658276577Sdelphij file_printable(ibuf, sizeof(ibuf), interp)) == -1) 1659276577Sdelphij return -1; 1660133359Sobrien return 0; 1661133359Sobrien} 1662133359Sobrien 1663133359Sobrien 1664133359Sobrienprotected int 1665337827Seadlerfile_tryelf(struct magic_set *ms, const struct buffer *b) 1666133359Sobrien{ 1667337827Seadler int fd = b->fd; 1668337827Seadler const unsigned char *buf = b->fbuf; 1669337827Seadler size_t nbytes = b->flen; 167068349Sobrien union { 1671103373Sobrien int32_t l; 1672337827Seadler char c[sizeof(int32_t)]; 167368349Sobrien } u; 1674186690Sobrien int clazz; 167568349Sobrien int swap; 1676169942Sobrien struct stat st; 1677169942Sobrien off_t fsize; 1678169942Sobrien int flags = 0; 1679186690Sobrien Elf32_Ehdr elf32hdr; 1680186690Sobrien Elf64_Ehdr elf64hdr; 1681276577Sdelphij uint16_t type, phnum, shnum, notecount; 168268349Sobrien 1683284237Sdelphij if (ms->flags & (MAGIC_MIME|MAGIC_APPLE|MAGIC_EXTENSION)) 1684186690Sobrien return 0; 168568349Sobrien /* 168668349Sobrien * ELF executables have multiple section headers in arbitrary 168768349Sobrien * file locations and thus file(1) cannot determine it from easily. 168868349Sobrien * Instead we traverse thru all section headers until a symbol table 168968349Sobrien * one is found or else the binary is stripped. 1690186690Sobrien * Return immediately if it's not ELF (so we avoid pipe2file unless needed). 169168349Sobrien */ 169268349Sobrien if (buf[EI_MAG0] != ELFMAG0 169368349Sobrien || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) 169468349Sobrien || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) 1695186690Sobrien return 0; 169668349Sobrien 1697186690Sobrien /* 1698186690Sobrien * If we cannot seek, it must be a pipe, socket or fifo. 1699186690Sobrien */ 1700337827Seadler if((lseek(fd, CAST(off_t, 0), SEEK_SET) == CAST(off_t, -1)) 1701337827Seadler && (errno == ESPIPE)) 1702186690Sobrien fd = file_pipe2file(ms, fd, buf, nbytes); 170368349Sobrien 1704186690Sobrien if (fstat(fd, &st) == -1) { 1705186690Sobrien file_badread(ms); 1706186690Sobrien return -1; 170768349Sobrien } 1708275698Sdelphij if (S_ISREG(st.st_mode) || st.st_size != 0) 1709275698Sdelphij fsize = st.st_size; 1710275698Sdelphij else 1711275698Sdelphij fsize = SIZE_UNKNOWN; 171268349Sobrien 1713186690Sobrien clazz = buf[EI_CLASS]; 171468349Sobrien 1715186690Sobrien switch (clazz) { 1716186690Sobrien case ELFCLASS32: 1717186690Sobrien#undef elf_getu 1718186690Sobrien#define elf_getu(a, b) elf_getu32(a, b) 1719186690Sobrien#undef elfhdr 1720186690Sobrien#define elfhdr elf32hdr 1721186690Sobrien#include "elfclass.h" 1722186690Sobrien case ELFCLASS64: 1723186690Sobrien#undef elf_getu 1724186690Sobrien#define elf_getu(a, b) elf_getu64(a, b) 1725186690Sobrien#undef elfhdr 1726186690Sobrien#define elfhdr elf64hdr 1727186690Sobrien#include "elfclass.h" 1728186690Sobrien default: 1729186690Sobrien if (file_printf(ms, ", unknown class %d", clazz) == -1) 1730186690Sobrien return -1; 1731186690Sobrien break; 173268349Sobrien } 1733133359Sobrien return 0; 173468349Sobrien} 173568349Sobrien#endif 1736