1133359Sobrien/* 2133359Sobrien * Copyright (c) Christos Zoulas 2003. 3133359Sobrien * All Rights Reserved. 4354939Sdelphij * 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. 14354939Sdelphij * 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 30362844SdelphijFILE_RCSID("@(#)$File: readelf.c,v 1.173 2020/06/07 22:12:54 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{ 70362844Sdelphij if (ms->flags & MAGIC_MIME) 71362844Sdelphij return 1; 72337827Seadler if (file_printf(ms, ", too many %s (%u)", name, num) == -1) 73275666Sdelphij return -1; 74354939Sdelphij return 1; 75275666Sdelphij} 76275666Sdelphij 77133359Sobrienprivate uint16_t 78103373Sobriengetu16(int swap, uint16_t value) 7968349Sobrien{ 8068349Sobrien union { 8168349Sobrien uint16_t ui; 8268349Sobrien char c[2]; 8368349Sobrien } retval, tmpval; 8468349Sobrien 8568349Sobrien if (swap) { 8668349Sobrien tmpval.ui = value; 8768349Sobrien 8868349Sobrien retval.c[0] = tmpval.c[1]; 8968349Sobrien retval.c[1] = tmpval.c[0]; 90354939Sdelphij 9168349Sobrien return retval.ui; 9268349Sobrien } else 9368349Sobrien return value; 9468349Sobrien} 9568349Sobrien 96133359Sobrienprivate uint32_t 97103373Sobriengetu32(int swap, uint32_t value) 9868349Sobrien{ 9968349Sobrien union { 10068349Sobrien uint32_t ui; 10168349Sobrien char c[4]; 10268349Sobrien } retval, tmpval; 10368349Sobrien 10468349Sobrien if (swap) { 10568349Sobrien tmpval.ui = value; 10668349Sobrien 10768349Sobrien retval.c[0] = tmpval.c[3]; 10868349Sobrien retval.c[1] = tmpval.c[2]; 10968349Sobrien retval.c[2] = tmpval.c[1]; 11068349Sobrien retval.c[3] = tmpval.c[0]; 111354939Sdelphij 11268349Sobrien return retval.ui; 11368349Sobrien } else 11468349Sobrien return value; 11568349Sobrien} 11668349Sobrien 117133359Sobrienprivate uint64_t 118103373Sobriengetu64(int swap, uint64_t value) 11968349Sobrien{ 12068349Sobrien union { 12168349Sobrien uint64_t ui; 12268349Sobrien char c[8]; 12368349Sobrien } retval, tmpval; 12468349Sobrien 12568349Sobrien if (swap) { 12668349Sobrien tmpval.ui = value; 12768349Sobrien 12868349Sobrien retval.c[0] = tmpval.c[7]; 12968349Sobrien retval.c[1] = tmpval.c[6]; 13068349Sobrien retval.c[2] = tmpval.c[5]; 13168349Sobrien retval.c[3] = tmpval.c[4]; 13268349Sobrien retval.c[4] = tmpval.c[3]; 13368349Sobrien retval.c[5] = tmpval.c[2]; 13468349Sobrien retval.c[6] = tmpval.c[1]; 13568349Sobrien retval.c[7] = tmpval.c[0]; 136354939Sdelphij 13768349Sobrien return retval.ui; 13868349Sobrien } else 13968349Sobrien return value; 14068349Sobrien} 14168349Sobrien 142186690Sobrien#define elf_getu16(swap, value) getu16(swap, value) 143186690Sobrien#define elf_getu32(swap, value) getu32(swap, value) 144267843Sdelphij#define elf_getu64(swap, value) getu64(swap, value) 145159764Sobrien 146186690Sobrien#define xsh_addr (clazz == ELFCLASS32 \ 147337827Seadler ? CAST(void *, &sh32) \ 148337827Seadler : CAST(void *, &sh64)) 149186690Sobrien#define xsh_sizeof (clazz == ELFCLASS32 \ 150267843Sdelphij ? sizeof(sh32) \ 151267843Sdelphij : sizeof(sh64)) 152337827Seadler#define xsh_size CAST(size_t, (clazz == ELFCLASS32 \ 153186690Sobrien ? elf_getu32(swap, sh32.sh_size) \ 154337827Seadler : elf_getu64(swap, sh64.sh_size))) 155337827Seadler#define xsh_offset CAST(off_t, (clazz == ELFCLASS32 \ 156186690Sobrien ? elf_getu32(swap, sh32.sh_offset) \ 157337827Seadler : elf_getu64(swap, sh64.sh_offset))) 158186690Sobrien#define xsh_type (clazz == ELFCLASS32 \ 159186690Sobrien ? elf_getu32(swap, sh32.sh_type) \ 160186690Sobrien : elf_getu32(swap, sh64.sh_type)) 161267843Sdelphij#define xsh_name (clazz == ELFCLASS32 \ 162267843Sdelphij ? elf_getu32(swap, sh32.sh_name) \ 163267843Sdelphij : elf_getu32(swap, sh64.sh_name)) 164337827Seadler 165186690Sobrien#define xph_addr (clazz == ELFCLASS32 \ 166337827Seadler ? CAST(void *, &ph32) \ 167337827Seadler : CAST(void *, &ph64)) 168186690Sobrien#define xph_sizeof (clazz == ELFCLASS32 \ 169267843Sdelphij ? sizeof(ph32) \ 170267843Sdelphij : sizeof(ph64)) 171186690Sobrien#define xph_type (clazz == ELFCLASS32 \ 172186690Sobrien ? elf_getu32(swap, ph32.p_type) \ 173186690Sobrien : elf_getu32(swap, ph64.p_type)) 174337827Seadler#define xph_offset CAST(off_t, (clazz == ELFCLASS32 \ 175186690Sobrien ? elf_getu32(swap, ph32.p_offset) \ 176337827Seadler : elf_getu64(swap, ph64.p_offset))) 177337827Seadler#define xph_align CAST(size_t, (clazz == ELFCLASS32 \ 178337827Seadler ? CAST(off_t, (ph32.p_align ? \ 179337827Seadler elf_getu32(swap, ph32.p_align) : 4))\ 180337827Seadler : CAST(off_t, (ph64.p_align ? \ 181337827Seadler elf_getu64(swap, ph64.p_align) : 4)))) 182337827Seadler#define xph_vaddr CAST(size_t, (clazz == ELFCLASS32 \ 183337827Seadler ? CAST(off_t, (ph32.p_vaddr ? \ 184337827Seadler elf_getu32(swap, ph32.p_vaddr) : 4))\ 185337827Seadler : CAST(off_t, (ph64.p_vaddr ? \ 186337827Seadler elf_getu64(swap, ph64.p_vaddr) : 4)))) 187337827Seadler#define xph_filesz CAST(size_t, (clazz == ELFCLASS32 \ 188186690Sobrien ? elf_getu32(swap, ph32.p_filesz) \ 189186690Sobrien : elf_getu64(swap, ph64.p_filesz))) 190337827Seadler#define xph_memsz CAST(size_t, ((clazz == ELFCLASS32 \ 191337827Seadler ? elf_getu32(swap, ph32.p_memsz) \ 192337827Seadler : elf_getu64(swap, ph64.p_memsz)))) 193186690Sobrien#define xnh_addr (clazz == ELFCLASS32 \ 194337827Seadler ? CAST(void *, &nh32) \ 195337827Seadler : CAST(void *, &nh64)) 196186690Sobrien#define xnh_sizeof (clazz == ELFCLASS32 \ 197298192Sdelphij ? sizeof(nh32) \ 198298192Sdelphij : sizeof(nh64)) 199186690Sobrien#define xnh_type (clazz == ELFCLASS32 \ 200186690Sobrien ? elf_getu32(swap, nh32.n_type) \ 201186690Sobrien : elf_getu32(swap, nh64.n_type)) 202186690Sobrien#define xnh_namesz (clazz == ELFCLASS32 \ 203186690Sobrien ? elf_getu32(swap, nh32.n_namesz) \ 204186690Sobrien : elf_getu32(swap, nh64.n_namesz)) 205186690Sobrien#define xnh_descsz (clazz == ELFCLASS32 \ 206186690Sobrien ? elf_getu32(swap, nh32.n_descsz) \ 207186690Sobrien : elf_getu32(swap, nh64.n_descsz)) 208337827Seadler 209337827Seadler#define xdh_addr (clazz == ELFCLASS32 \ 210337827Seadler ? CAST(void *, &dh32) \ 211337827Seadler : CAST(void *, &dh64)) 212337827Seadler#define xdh_sizeof (clazz == ELFCLASS32 \ 213337827Seadler ? sizeof(dh32) \ 214337827Seadler : sizeof(dh64)) 215337827Seadler#define xdh_tag (clazz == ELFCLASS32 \ 216337827Seadler ? elf_getu32(swap, dh32.d_tag) \ 217337827Seadler : elf_getu64(swap, dh64.d_tag)) 218337827Seadler#define xdh_val (clazz == ELFCLASS32 \ 219337827Seadler ? elf_getu32(swap, dh32.d_un.d_val) \ 220337827Seadler : elf_getu64(swap, dh64.d_un.d_val)) 221337827Seadler 222186690Sobrien#define xcap_addr (clazz == ELFCLASS32 \ 223337827Seadler ? CAST(void *, &cap32) \ 224337827Seadler : CAST(void *, &cap64)) 225186690Sobrien#define xcap_sizeof (clazz == ELFCLASS32 \ 226337827Seadler ? sizeof(cap32) \ 227337827Seadler : sizeof(cap64)) 228186690Sobrien#define xcap_tag (clazz == ELFCLASS32 \ 229186690Sobrien ? elf_getu32(swap, cap32.c_tag) \ 230186690Sobrien : elf_getu64(swap, cap64.c_tag)) 231186690Sobrien#define xcap_val (clazz == ELFCLASS32 \ 232186690Sobrien ? elf_getu32(swap, cap32.c_un.c_val) \ 233186690Sobrien : elf_getu64(swap, cap64.c_un.c_val)) 234337827Seadler 235298192Sdelphij#define xauxv_addr (clazz == ELFCLASS32 \ 236337827Seadler ? CAST(void *, &auxv32) \ 237337827Seadler : CAST(void *, &auxv64)) 238298192Sdelphij#define xauxv_sizeof (clazz == ELFCLASS32 \ 239298192Sdelphij ? sizeof(auxv32) \ 240298192Sdelphij : sizeof(auxv64)) 241298192Sdelphij#define xauxv_type (clazz == ELFCLASS32 \ 242298192Sdelphij ? elf_getu32(swap, auxv32.a_type) \ 243298192Sdelphij : elf_getu64(swap, auxv64.a_type)) 244298192Sdelphij#define xauxv_val (clazz == ELFCLASS32 \ 245298192Sdelphij ? elf_getu32(swap, auxv32.a_v) \ 246298192Sdelphij : elf_getu64(swap, auxv64.a_v)) 24768349Sobrien 248337827Seadler#define prpsoffsets(i) (clazz == ELFCLASS32 \ 249337827Seadler ? prpsoffsets32[i] \ 250337827Seadler : prpsoffsets64[i]) 251337827Seadler 25268349Sobrien#ifdef ELFCORE 253186690Sobrien/* 254186690Sobrien * Try larger offsets first to avoid false matches 255186690Sobrien * from earlier data that happen to look like strings. 256186690Sobrien */ 257186690Sobrienstatic const size_t prpsoffsets32[] = { 258186690Sobrien#ifdef USE_NT_PSINFO 259186690Sobrien 104, /* SunOS 5.x (command line) */ 260186690Sobrien 88, /* SunOS 5.x (short name) */ 261186690Sobrien#endif /* USE_NT_PSINFO */ 262186690Sobrien 263186690Sobrien 100, /* SunOS 5.x (command line) */ 264186690Sobrien 84, /* SunOS 5.x (short name) */ 265186690Sobrien 266186690Sobrien 44, /* Linux (command line) */ 267354939Sdelphij 28, /* Linux (short name) */ 268186690Sobrien 269354939Sdelphij 48, /* Linux PowerPC (command line) */ 270354939Sdelphij 32, /* Linux PowerPC (short name) */ 271354939Sdelphij 27268349Sobrien 8, /* FreeBSD */ 27368349Sobrien}; 27468349Sobrien 275186690Sobrienstatic const size_t prpsoffsets64[] = { 276186690Sobrien#ifdef USE_NT_PSINFO 277186690Sobrien 152, /* SunOS 5.x (command line) */ 278186690Sobrien 136, /* SunOS 5.x (short name) */ 279186690Sobrien#endif /* USE_NT_PSINFO */ 280186690Sobrien 281186690Sobrien 136, /* SunOS 5.x, 64-bit (command line) */ 282186690Sobrien 120, /* SunOS 5.x, 64-bit (short name) */ 283186690Sobrien 284186690Sobrien 56, /* Linux (command line) */ 285186690Sobrien 40, /* Linux (tested on core from 2.4.x, short name) */ 286186690Sobrien 287159764Sobrien 16, /* FreeBSD, 64-bit */ 28868349Sobrien}; 28968349Sobrien 290354939Sdelphij#define NOFFSETS32 __arraycount(prpsoffsets32) 291354939Sdelphij#define NOFFSETS64 __arraycount(prpsoffsets64) 29268349Sobrien 293186690Sobrien#define NOFFSETS (clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64) 29468349Sobrien 29568349Sobrien/* 29668349Sobrien * Look through the program headers of an executable image, searching 29768349Sobrien * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or 29868349Sobrien * "FreeBSD"; if one is found, try looking in various places in its 29968349Sobrien * contents for a 16-character string containing only printable 30068349Sobrien * characters - if found, that string should be the name of the program 30168349Sobrien * that dropped core. Note: right after that 16-character string is, 30268349Sobrien * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and 30368349Sobrien * Linux, a longer string (80 characters, in 5.x, probably other 30468349Sobrien * SVR4-flavored systems, and Linux) containing the start of the 30568349Sobrien * command line for that program. 30668349Sobrien * 307186690Sobrien * SunOS 5.x core files contain two PT_NOTE sections, with the types 308186690Sobrien * NT_PRPSINFO (old) and NT_PSINFO (new). These structs contain the 309186690Sobrien * same info about the command name and command line, so it probably 310186690Sobrien * isn't worthwhile to look for NT_PSINFO, but the offsets are provided 311186690Sobrien * above (see USE_NT_PSINFO), in case we ever decide to do so. The 312186690Sobrien * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent; 313186690Sobrien * the SunOS 5.x file command relies on this (and prefers the latter). 314186690Sobrien * 31568349Sobrien * The signal number probably appears in a section of type NT_PRSTATUS, 31668349Sobrien * but that's also rather OS-dependent, in ways that are harder to 31768349Sobrien * dissect with heuristics, so I'm not bothering with the signal number. 31868349Sobrien * (I suppose the signal number could be of interest in situations where 31968349Sobrien * you don't have the binary of the program that dropped core; if you 32068349Sobrien * *do* have that binary, the debugger will probably tell you what 32168349Sobrien * signal it was.) 32268349Sobrien */ 323103373Sobrien 324103373Sobrien#define OS_STYLE_SVR4 0 325103373Sobrien#define OS_STYLE_FREEBSD 1 326103373Sobrien#define OS_STYLE_NETBSD 2 327103373Sobrien 328186690Sobrienprivate const char os_style_names[][8] = { 329103373Sobrien "SVR4", 330103373Sobrien "FreeBSD", 331103373Sobrien "NetBSD", 332103373Sobrien}; 333103373Sobrien 334337827Seadler#define FLAGS_CORE_STYLE 0x0003 335159764Sobrien 336337827Seadler#define FLAGS_DID_CORE 0x0004 337337827Seadler#define FLAGS_DID_OS_NOTE 0x0008 338337827Seadler#define FLAGS_DID_BUILD_ID 0x0010 339337827Seadler#define FLAGS_DID_CORE_STYLE 0x0020 340337827Seadler#define FLAGS_DID_NETBSD_PAX 0x0040 341337827Seadler#define FLAGS_DID_NETBSD_MARCH 0x0080 342337827Seadler#define FLAGS_DID_NETBSD_CMODEL 0x0100 343337827Seadler#define FLAGS_DID_NETBSD_EMULATION 0x0200 344337827Seadler#define FLAGS_DID_NETBSD_UNKNOWN 0x0400 345337827Seadler#define FLAGS_IS_CORE 0x0800 346337827Seadler#define FLAGS_DID_AUXV 0x1000 347328874Seadler 348133359Sobrienprivate int 349186690Sobriendophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 350276577Sdelphij int num, size_t size, off_t fsize, int *flags, uint16_t *notecount) 35168349Sobrien{ 35268349Sobrien Elf32_Phdr ph32; 35368349Sobrien Elf64_Phdr ph64; 354267843Sdelphij size_t offset, len; 355133359Sobrien unsigned char nbuf[BUFSIZ]; 356133359Sobrien ssize_t bufsize; 357298192Sdelphij off_t ph_off = off; 358298192Sdelphij int ph_num = num; 35968349Sobrien 360362844Sdelphij if (ms->flags & MAGIC_MIME) 361362844Sdelphij return 0; 362362844Sdelphij 363354939Sdelphij if (num == 0) { 364354939Sdelphij if (file_printf(ms, ", no program header") == -1) 365354939Sdelphij return -1; 366354939Sdelphij return 0; 367354939Sdelphij } 368159764Sobrien if (size != xph_sizeof) { 369133359Sobrien if (file_printf(ms, ", corrupted program header size") == -1) 370133359Sobrien return -1; 371133359Sobrien return 0; 372133359Sobrien } 373159764Sobrien 37468349Sobrien /* 37568349Sobrien * Loop through all the program headers. 37668349Sobrien */ 37768349Sobrien for ( ; num; num--) { 378337827Seadler if (pread(fd, xph_addr, xph_sizeof, off) < 379337827Seadler CAST(ssize_t, xph_sizeof)) { 380133359Sobrien file_badread(ms); 381133359Sobrien return -1; 382133359Sobrien } 383226048Sobrien off += size; 384226048Sobrien 385275698Sdelphij if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 386226048Sobrien /* Perhaps warn here */ 387169942Sobrien continue; 388169942Sobrien } 389169942Sobrien 390159764Sobrien if (xph_type != PT_NOTE) 39168349Sobrien continue; 39268349Sobrien 39368349Sobrien /* 39468349Sobrien * This is a PT_NOTE section; loop through all the notes 39568349Sobrien * in the section. 39668349Sobrien */ 397267843Sdelphij len = xph_filesz < sizeof(nbuf) ? xph_filesz : sizeof(nbuf); 398267843Sdelphij if ((bufsize = pread(fd, nbuf, len, xph_offset)) == -1) { 399133359Sobrien file_badread(ms); 400133359Sobrien return -1; 401133359Sobrien } 40268349Sobrien offset = 0; 40368349Sobrien for (;;) { 404354939Sdelphij if (offset >= CAST(size_t, bufsize)) 40568349Sobrien break; 406354939Sdelphij offset = donote(ms, nbuf, offset, CAST(size_t, bufsize), 407298192Sdelphij clazz, swap, 4, flags, notecount, fd, ph_off, 408298192Sdelphij ph_num, fsize); 409133359Sobrien if (offset == 0) 410133359Sobrien break; 41168349Sobrien 412133359Sobrien } 413133359Sobrien } 414133359Sobrien return 0; 415133359Sobrien} 416133359Sobrien#endif 417133359Sobrien 418354939Sdelphijstatic int 419267843Sdelphijdo_note_netbsd_version(struct magic_set *ms, int swap, void *v) 420267843Sdelphij{ 421267843Sdelphij uint32_t desc; 422337827Seadler memcpy(&desc, v, sizeof(desc)); 423267843Sdelphij desc = elf_getu32(swap, desc); 424267843Sdelphij 425267843Sdelphij if (file_printf(ms, ", for NetBSD") == -1) 426354939Sdelphij return -1; 427267843Sdelphij /* 428267843Sdelphij * The version number used to be stuck as 199905, and was thus 429267843Sdelphij * basically content-free. Newer versions of NetBSD have fixed 430267843Sdelphij * this and now use the encoding of __NetBSD_Version__: 431267843Sdelphij * 432267843Sdelphij * MMmmrrpp00 433267843Sdelphij * 434267843Sdelphij * M = major version 435267843Sdelphij * m = minor version 436267843Sdelphij * r = release ["",A-Z,Z[A-Z] but numeric] 437267843Sdelphij * p = patchlevel 438267843Sdelphij */ 439267843Sdelphij if (desc > 100000000U) { 440267843Sdelphij uint32_t ver_patch = (desc / 100) % 100; 441267843Sdelphij uint32_t ver_rel = (desc / 10000) % 100; 442267843Sdelphij uint32_t ver_min = (desc / 1000000) % 100; 443267843Sdelphij uint32_t ver_maj = desc / 100000000; 444267843Sdelphij 445267843Sdelphij if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) 446354939Sdelphij return -1; 447267843Sdelphij if (ver_rel == 0 && ver_patch != 0) { 448267843Sdelphij if (file_printf(ms, ".%u", ver_patch) == -1) 449354939Sdelphij return -1; 450267843Sdelphij } else if (ver_rel != 0) { 451267843Sdelphij while (ver_rel > 26) { 452267843Sdelphij if (file_printf(ms, "Z") == -1) 453354939Sdelphij return -1; 454267843Sdelphij ver_rel -= 26; 455267843Sdelphij } 456267843Sdelphij if (file_printf(ms, "%c", 'A' + ver_rel - 1) 457267843Sdelphij == -1) 458354939Sdelphij return -1; 459267843Sdelphij } 460267843Sdelphij } 461354939Sdelphij return 0; 462267843Sdelphij} 463267843Sdelphij 464354939Sdelphijstatic int 465267843Sdelphijdo_note_freebsd_version(struct magic_set *ms, int swap, void *v) 466267843Sdelphij{ 467267843Sdelphij uint32_t desc; 468267843Sdelphij 469337827Seadler memcpy(&desc, v, sizeof(desc)); 470267843Sdelphij desc = elf_getu32(swap, desc); 471267843Sdelphij if (file_printf(ms, ", for FreeBSD") == -1) 472354939Sdelphij return -1; 473267843Sdelphij 474267843Sdelphij /* 475267843Sdelphij * Contents is __FreeBSD_version, whose relation to OS 476267843Sdelphij * versions is defined by a huge table in the Porter's 477267843Sdelphij * Handbook. This is the general scheme: 478354939Sdelphij * 479267843Sdelphij * Releases: 480267843Sdelphij * Mmp000 (before 4.10) 481267843Sdelphij * Mmi0p0 (before 5.0) 482267843Sdelphij * Mmm0p0 483354939Sdelphij * 484267843Sdelphij * Development branches: 485267843Sdelphij * Mmpxxx (before 4.6) 486267843Sdelphij * Mmp1xx (before 4.10) 487267843Sdelphij * Mmi1xx (before 5.0) 488267843Sdelphij * M000xx (pre-M.0) 489267843Sdelphij * Mmm1xx 490354939Sdelphij * 491267843Sdelphij * M = major version 492267843Sdelphij * m = minor version 493267843Sdelphij * i = minor version increment (491000 -> 4.10) 494267843Sdelphij * p = patchlevel 495267843Sdelphij * x = revision 496354939Sdelphij * 497267843Sdelphij * The first release of FreeBSD to use ELF by default 498267843Sdelphij * was version 3.0. 499267843Sdelphij */ 500267843Sdelphij if (desc == 460002) { 501267843Sdelphij if (file_printf(ms, " 4.6.2") == -1) 502354939Sdelphij return -1; 503267843Sdelphij } else if (desc < 460100) { 504267843Sdelphij if (file_printf(ms, " %d.%d", desc / 100000, 505267843Sdelphij desc / 10000 % 10) == -1) 506354939Sdelphij return -1; 507267843Sdelphij if (desc / 1000 % 10 > 0) 508267843Sdelphij if (file_printf(ms, ".%d", desc / 1000 % 10) == -1) 509354939Sdelphij return -1; 510267843Sdelphij if ((desc % 1000 > 0) || (desc % 100000 == 0)) 511267843Sdelphij if (file_printf(ms, " (%d)", desc) == -1) 512354939Sdelphij return -1; 513267843Sdelphij } else if (desc < 500000) { 514267843Sdelphij if (file_printf(ms, " %d.%d", desc / 100000, 515267843Sdelphij desc / 10000 % 10 + desc / 1000 % 10) == -1) 516354939Sdelphij return -1; 517267843Sdelphij if (desc / 100 % 10 > 0) { 518267843Sdelphij if (file_printf(ms, " (%d)", desc) == -1) 519354939Sdelphij return -1; 520267843Sdelphij } else if (desc / 10 % 10 > 0) { 521267843Sdelphij if (file_printf(ms, ".%d", desc / 10 % 10) == -1) 522354939Sdelphij return -1; 523267843Sdelphij } 524267843Sdelphij } else { 525267843Sdelphij if (file_printf(ms, " %d.%d", desc / 100000, 526267843Sdelphij desc / 1000 % 100) == -1) 527354939Sdelphij return -1; 528267843Sdelphij if ((desc / 100 % 10 > 0) || 529267843Sdelphij (desc % 100000 / 100 == 0)) { 530267843Sdelphij if (file_printf(ms, " (%d)", desc) == -1) 531354939Sdelphij return -1; 532267843Sdelphij } else if (desc / 10 % 10 > 0) { 533267843Sdelphij if (file_printf(ms, ".%d", desc / 10 % 10) == -1) 534354939Sdelphij return -1; 535267843Sdelphij } 536267843Sdelphij } 537354939Sdelphij return 0; 538267843Sdelphij} 539267843Sdelphij 540276577Sdelphijprivate int 541284237Sdelphij/*ARGSUSED*/ 542276577Sdelphijdo_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 543276577Sdelphij int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz, 544276577Sdelphij size_t noff, size_t doff, int *flags) 545133359Sobrien{ 546354939Sdelphij if (namesz == 4 && strcmp(RCAST(char *, &nbuf[noff]), "GNU") == 0 && 547323281Sgordon type == NT_GNU_BUILD_ID && (descsz >= 4 && descsz <= 20)) { 548276577Sdelphij uint8_t desc[20]; 549309847Sdelphij const char *btype; 550276577Sdelphij uint32_t i; 551276577Sdelphij *flags |= FLAGS_DID_BUILD_ID; 552309847Sdelphij switch (descsz) { 553309847Sdelphij case 8: 554309847Sdelphij btype = "xxHash"; 555309847Sdelphij break; 556309847Sdelphij case 16: 557309847Sdelphij btype = "md5/uuid"; 558309847Sdelphij break; 559309847Sdelphij case 20: 560309847Sdelphij btype = "sha1"; 561309847Sdelphij break; 562309847Sdelphij default: 563309847Sdelphij btype = "unknown"; 564309847Sdelphij break; 565309847Sdelphij } 566309847Sdelphij if (file_printf(ms, ", BuildID[%s]=", btype) == -1) 567354939Sdelphij return -1; 568337827Seadler memcpy(desc, &nbuf[doff], descsz); 569276577Sdelphij for (i = 0; i < descsz; i++) 570276577Sdelphij if (file_printf(ms, "%02x", desc[i]) == -1) 571354939Sdelphij return -1; 572276577Sdelphij return 1; 573275666Sdelphij } 574354939Sdelphij if (namesz == 4 && strcmp(RCAST(char *, &nbuf[noff]), "Go") == 0 && 575337827Seadler type == NT_GO_BUILD_ID && descsz < 128) { 576362844Sdelphij char buf[256]; 577362844Sdelphij if (file_printf(ms, ", Go BuildID=%s", 578362844Sdelphij file_copystr(buf, sizeof(buf), descsz, 579362844Sdelphij RCAST(const char *, &nbuf[doff]))) == -1) 580354939Sdelphij return -1; 581337827Seadler return 1; 582337827Seadler } 583276577Sdelphij return 0; 584276577Sdelphij} 585275666Sdelphij 586276577Sdelphijprivate int 587276577Sdelphijdo_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 588276577Sdelphij int swap, uint32_t namesz, uint32_t descsz, 589276577Sdelphij size_t noff, size_t doff, int *flags) 590276577Sdelphij{ 591354939Sdelphij const char *name = RCAST(const char *, &nbuf[noff]); 592354939Sdelphij 593354939Sdelphij if (namesz == 5 && strcmp(name, "SuSE") == 0 && 594354939Sdelphij type == NT_GNU_VERSION && descsz == 2) { 595354939Sdelphij *flags |= FLAGS_DID_OS_NOTE; 596354939Sdelphij if (file_printf(ms, ", for SuSE %d.%d", nbuf[doff], 597354939Sdelphij nbuf[doff + 1]) == -1) 598354939Sdelphij return -1; 599276577Sdelphij return 1; 600267843Sdelphij } 601276577Sdelphij 602354939Sdelphij if (namesz == 4 && strcmp(name, "GNU") == 0 && 603276577Sdelphij type == NT_GNU_VERSION && descsz == 16) { 604133359Sobrien uint32_t desc[4]; 605337827Seadler memcpy(desc, &nbuf[doff], sizeof(desc)); 606133359Sobrien 607276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 608133359Sobrien if (file_printf(ms, ", for GNU/") == -1) 609354939Sdelphij return -1; 610186690Sobrien switch (elf_getu32(swap, desc[0])) { 611133359Sobrien case GNU_OS_LINUX: 612133359Sobrien if (file_printf(ms, "Linux") == -1) 613354939Sdelphij return -1; 614133359Sobrien break; 615133359Sobrien case GNU_OS_HURD: 616133359Sobrien if (file_printf(ms, "Hurd") == -1) 617354939Sdelphij return -1; 618133359Sobrien break; 619133359Sobrien case GNU_OS_SOLARIS: 620133359Sobrien if (file_printf(ms, "Solaris") == -1) 621354939Sdelphij return -1; 622133359Sobrien break; 623186690Sobrien case GNU_OS_KFREEBSD: 624186690Sobrien if (file_printf(ms, "kFreeBSD") == -1) 625354939Sdelphij return -1; 626186690Sobrien break; 627186690Sobrien case GNU_OS_KNETBSD: 628186690Sobrien if (file_printf(ms, "kNetBSD") == -1) 629354939Sdelphij return -1; 630186690Sobrien break; 631133359Sobrien default: 632133359Sobrien if (file_printf(ms, "<unknown>") == -1) 633354939Sdelphij return -1; 634133359Sobrien } 635186690Sobrien if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]), 636186690Sobrien elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1) 637354939Sdelphij return -1; 638276577Sdelphij return 1; 639133359Sobrien } 640133359Sobrien 641354939Sdelphij if (namesz == 7 && strcmp(name, "NetBSD") == 0) { 642276577Sdelphij if (type == NT_NETBSD_VERSION && descsz == 4) { 643276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 644354939Sdelphij if (do_note_netbsd_version(ms, swap, &nbuf[doff]) == -1) 645354939Sdelphij return -1; 646276577Sdelphij return 1; 647276577Sdelphij } 648226048Sobrien } 649226048Sobrien 650354939Sdelphij if (namesz == 8 && strcmp(name, "FreeBSD") == 0) { 651276577Sdelphij if (type == NT_FREEBSD_VERSION && descsz == 4) { 652276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 653354939Sdelphij if (do_note_freebsd_version(ms, swap, &nbuf[doff]) 654354939Sdelphij == -1) 655354939Sdelphij return -1; 656276577Sdelphij return 1; 657276577Sdelphij } 658276577Sdelphij } 659276577Sdelphij 660354939Sdelphij if (namesz == 8 && strcmp(name, "OpenBSD") == 0 && 661276577Sdelphij type == NT_OPENBSD_VERSION && descsz == 4) { 662276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 663276577Sdelphij if (file_printf(ms, ", for OpenBSD") == -1) 664354939Sdelphij return -1; 665276577Sdelphij /* Content of note is always 0 */ 666276577Sdelphij return 1; 667276577Sdelphij } 668276577Sdelphij 669354939Sdelphij if (namesz == 10 && strcmp(name, "DragonFly") == 0 && 670276577Sdelphij type == NT_DRAGONFLY_VERSION && descsz == 4) { 671276577Sdelphij uint32_t desc; 672276577Sdelphij *flags |= FLAGS_DID_OS_NOTE; 673276577Sdelphij if (file_printf(ms, ", for DragonFly") == -1) 674354939Sdelphij return -1; 675337827Seadler memcpy(&desc, &nbuf[doff], sizeof(desc)); 676276577Sdelphij desc = elf_getu32(swap, desc); 677276577Sdelphij if (file_printf(ms, " %d.%d.%d", desc / 100000, 678276577Sdelphij desc / 10000 % 10, desc % 10000) == -1) 679354939Sdelphij return -1; 680276577Sdelphij return 1; 681276577Sdelphij } 682276577Sdelphij return 0; 683276577Sdelphij} 684276577Sdelphij 685276577Sdelphijprivate int 686276577Sdelphijdo_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 687276577Sdelphij int swap, uint32_t namesz, uint32_t descsz, 688276577Sdelphij size_t noff, size_t doff, int *flags) 689276577Sdelphij{ 690354939Sdelphij const char *name = RCAST(const char *, &nbuf[noff]); 691354939Sdelphij 692354939Sdelphij if (namesz == 4 && strcmp(name, "PaX") == 0 && 693276577Sdelphij type == NT_NETBSD_PAX && descsz == 4) { 694267843Sdelphij static const char *pax[] = { 695267843Sdelphij "+mprotect", 696267843Sdelphij "-mprotect", 697267843Sdelphij "+segvguard", 698267843Sdelphij "-segvguard", 699267843Sdelphij "+ASLR", 700267843Sdelphij "-ASLR", 701267843Sdelphij }; 702133359Sobrien uint32_t desc; 703267843Sdelphij size_t i; 704267843Sdelphij int did = 0; 705267843Sdelphij 706276577Sdelphij *flags |= FLAGS_DID_NETBSD_PAX; 707337827Seadler memcpy(&desc, &nbuf[doff], sizeof(desc)); 708186690Sobrien desc = elf_getu32(swap, desc); 709133359Sobrien 710267843Sdelphij if (desc && file_printf(ms, ", PaX: ") == -1) 711354939Sdelphij return -1; 712133359Sobrien 713267843Sdelphij for (i = 0; i < __arraycount(pax); i++) { 714354939Sdelphij if (((1 << CAST(int, i)) & desc) == 0) 715267843Sdelphij continue; 716267843Sdelphij if (file_printf(ms, "%s%s", did++ ? "," : "", 717267843Sdelphij pax[i]) == -1) 718354939Sdelphij return -1; 719133359Sobrien } 720276577Sdelphij return 1; 721133359Sobrien } 722276577Sdelphij return 0; 723276577Sdelphij} 72468349Sobrien 725276577Sdelphijprivate int 726276577Sdelphijdo_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 727276577Sdelphij int swap, uint32_t namesz, uint32_t descsz, 728276577Sdelphij size_t noff, size_t doff, int *flags, size_t size, int clazz) 729276577Sdelphij{ 730276577Sdelphij#ifdef ELFCORE 731362844Sdelphij char buf[256]; 732354939Sdelphij const char *name = RCAST(const char *, &nbuf[noff]); 733354939Sdelphij 734276577Sdelphij int os_style = -1; 735133359Sobrien /* 736133359Sobrien * Sigh. The 2.0.36 kernel in Debian 2.1, at 737133359Sobrien * least, doesn't correctly implement name 738133359Sobrien * sections, in core dumps, as specified by 739133359Sobrien * the "Program Linking" section of "UNIX(R) System 740133359Sobrien * V Release 4 Programmer's Guide: ANSI C and 741133359Sobrien * Programming Support Tools", because my copy 742133359Sobrien * clearly says "The first 'namesz' bytes in 'name' 743133359Sobrien * contain a *null-terminated* [emphasis mine] 744133359Sobrien * character representation of the entry's owner 745133359Sobrien * or originator", but the 2.0.36 kernel code 746133359Sobrien * doesn't include the terminating null in the 747133359Sobrien * name.... 748133359Sobrien */ 749354939Sdelphij if ((namesz == 4 && strncmp(name, "CORE", 4) == 0) || 750354939Sdelphij (namesz == 5 && strcmp(name, "CORE") == 0)) { 751133359Sobrien os_style = OS_STYLE_SVR4; 752354939Sdelphij } 753133359Sobrien 754354939Sdelphij if ((namesz == 8 && strcmp(name, "FreeBSD") == 0)) { 755133359Sobrien os_style = OS_STYLE_FREEBSD; 756133359Sobrien } 757133359Sobrien 758354939Sdelphij if ((namesz >= 11 && strncmp(name, "NetBSD-CORE", 11) 759133359Sobrien == 0)) { 760133359Sobrien os_style = OS_STYLE_NETBSD; 761133359Sobrien } 762133359Sobrien 763175296Sobrien if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) { 764169942Sobrien if (file_printf(ms, ", %s-style", os_style_names[os_style]) 765169942Sobrien == -1) 766354939Sdelphij return -1; 767175296Sobrien *flags |= FLAGS_DID_CORE_STYLE; 768328874Seadler *flags |= os_style; 769159764Sobrien } 770133359Sobrien 771159764Sobrien switch (os_style) { 772159764Sobrien case OS_STYLE_NETBSD: 773276577Sdelphij if (type == NT_NETBSD_CORE_PROCINFO) { 774276577Sdelphij char sbuf[512]; 775328874Seadler struct NetBSD_elfcore_procinfo pi; 776328874Seadler memset(&pi, 0, sizeof(pi)); 777354939Sdelphij memcpy(&pi, nbuf + doff, MIN(descsz, sizeof(pi))); 778328874Seadler 779328874Seadler if (file_printf(ms, ", from '%.31s', pid=%u, uid=%u, " 780328874Seadler "gid=%u, nlwps=%u, lwp=%u (signal %u/code %u)", 781276577Sdelphij file_printable(sbuf, sizeof(sbuf), 782354939Sdelphij RCAST(char *, pi.cpi_name), sizeof(pi.cpi_name)), 783354939Sdelphij elf_getu32(swap, CAST(uint32_t, pi.cpi_pid)), 784328874Seadler elf_getu32(swap, pi.cpi_euid), 785328874Seadler elf_getu32(swap, pi.cpi_egid), 786328874Seadler elf_getu32(swap, pi.cpi_nlwps), 787354939Sdelphij elf_getu32(swap, CAST(uint32_t, pi.cpi_siglwp)), 788328874Seadler elf_getu32(swap, pi.cpi_signo), 789328874Seadler elf_getu32(swap, pi.cpi_sigcode)) == -1) 790354939Sdelphij return -1; 791328874Seadler 792175296Sobrien *flags |= FLAGS_DID_CORE; 793276577Sdelphij return 1; 794159764Sobrien } 795159764Sobrien break; 796133359Sobrien 797354939Sdelphij case OS_STYLE_FREEBSD: 798354939Sdelphij if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) { 799354939Sdelphij size_t argoff, pidoff; 800354939Sdelphij 801354939Sdelphij if (clazz == ELFCLASS32) 802354939Sdelphij argoff = 4 + 4 + 17; 803354939Sdelphij else 804354939Sdelphij argoff = 4 + 4 + 8 + 17; 805354939Sdelphij if (file_printf(ms, ", from '%.80s'", nbuf + doff + 806354939Sdelphij argoff) == -1) 807354939Sdelphij return -1; 808354939Sdelphij pidoff = argoff + 81 + 2; 809354939Sdelphij if (doff + pidoff + 4 <= size) { 810354939Sdelphij if (file_printf(ms, ", pid=%u", 811354939Sdelphij elf_getu32(swap, *RCAST(uint32_t *, (nbuf + 812354939Sdelphij doff + pidoff)))) == -1) 813354939Sdelphij return -1; 814354939Sdelphij } 815354939Sdelphij *flags |= FLAGS_DID_CORE; 816354939Sdelphij } 817354939Sdelphij break; 818354939Sdelphij 819159764Sobrien default: 820276577Sdelphij if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) { 821159764Sobrien size_t i, j; 822159764Sobrien unsigned char c; 823159764Sobrien /* 824159764Sobrien * Extract the program name. We assume 825159764Sobrien * it to be 16 characters (that's what it 826159764Sobrien * is in SunOS 5.x and Linux). 827159764Sobrien * 828159764Sobrien * Unfortunately, it's at a different offset 829175296Sobrien * in various OSes, so try multiple offsets. 830159764Sobrien * If the characters aren't all printable, 831159764Sobrien * reject it. 832159764Sobrien */ 833159764Sobrien for (i = 0; i < NOFFSETS; i++) { 834175296Sobrien unsigned char *cname, *cp; 835159764Sobrien size_t reloffset = prpsoffsets(i); 836159764Sobrien size_t noffset = doff + reloffset; 837226048Sobrien size_t k; 838159764Sobrien for (j = 0; j < 16; j++, noffset++, 839159764Sobrien reloffset++) { 84068349Sobrien /* 841159764Sobrien * Make sure we're not past 842159764Sobrien * the end of the buffer; if 843159764Sobrien * we are, just give up. 84468349Sobrien */ 845159764Sobrien if (noffset >= size) 846133359Sobrien goto tryanother; 847159764Sobrien 848133359Sobrien /* 849159764Sobrien * Make sure we're not past 850159764Sobrien * the end of the contents; 851159764Sobrien * if we are, this obviously 852159764Sobrien * isn't the right offset. 853133359Sobrien */ 854159764Sobrien if (reloffset >= descsz) 855133359Sobrien goto tryanother; 856159764Sobrien 857159764Sobrien c = nbuf[noffset]; 858159764Sobrien if (c == '\0') { 859159764Sobrien /* 860159764Sobrien * A '\0' at the 861159764Sobrien * beginning is 862159764Sobrien * obviously wrong. 863159764Sobrien * Any other '\0' 864159764Sobrien * means we're done. 865159764Sobrien */ 866159764Sobrien if (j == 0) 867159764Sobrien goto tryanother; 868159764Sobrien else 869159764Sobrien break; 870159764Sobrien } else { 871159764Sobrien /* 872159764Sobrien * A nonprintable 873159764Sobrien * character is also 874159764Sobrien * wrong. 875159764Sobrien */ 876159764Sobrien if (!isprint(c) || isquote(c)) 877159764Sobrien goto tryanother; 878159764Sobrien } 87968349Sobrien } 880159764Sobrien /* 881159764Sobrien * Well, that worked. 882159764Sobrien */ 883226048Sobrien 884226048Sobrien /* 885226048Sobrien * Try next offsets, in case this match is 886226048Sobrien * in the middle of a string. 887226048Sobrien */ 888276577Sdelphij for (k = i + 1 ; k < NOFFSETS; k++) { 889226048Sobrien size_t no; 890226048Sobrien int adjust = 1; 891226048Sobrien if (prpsoffsets(k) >= prpsoffsets(i)) 892226048Sobrien continue; 893226048Sobrien for (no = doff + prpsoffsets(k); 894226048Sobrien no < doff + prpsoffsets(i); no++) 895226048Sobrien adjust = adjust 896226048Sobrien && isprint(nbuf[no]); 897226048Sobrien if (adjust) 898226048Sobrien i = k; 899226048Sobrien } 900226048Sobrien 901354939Sdelphij cname = CAST(unsigned char *, 902354939Sdelphij &nbuf[doff + prpsoffsets(i)]); 903337827Seadler for (cp = cname; cp < nbuf + size && *cp 904337827Seadler && isprint(*cp); cp++) 905175296Sobrien continue; 906186690Sobrien /* 907186690Sobrien * Linux apparently appends a space at the end 908186690Sobrien * of the command line: remove it. 909186690Sobrien */ 910186690Sobrien while (cp > cname && isspace(cp[-1])) 911175296Sobrien cp--; 912362844Sdelphij if (file_printf(ms, ", from '%s'", 913362844Sdelphij file_copystr(buf, sizeof(buf), 914362844Sdelphij CAST(size_t, cp - cname), 915362844Sdelphij CAST(const char *, cname))) == -1) 916354939Sdelphij return -1; 917175296Sobrien *flags |= FLAGS_DID_CORE; 918276577Sdelphij return 1; 919133359Sobrien 920159764Sobrien tryanother: 921159764Sobrien ; 922159764Sobrien } 92368349Sobrien } 924159764Sobrien break; 92568349Sobrien } 926133359Sobrien#endif 927276577Sdelphij return 0; 928276577Sdelphij} 929276577Sdelphij 930298192Sdelphijprivate off_t 931298192Sdelphijget_offset_from_virtaddr(struct magic_set *ms, int swap, int clazz, int fd, 932298192Sdelphij off_t off, int num, off_t fsize, uint64_t virtaddr) 933298192Sdelphij{ 934298192Sdelphij Elf32_Phdr ph32; 935298192Sdelphij Elf64_Phdr ph64; 936298192Sdelphij 937298192Sdelphij /* 938298192Sdelphij * Loop through all the program headers and find the header with 939298192Sdelphij * virtual address in which the "virtaddr" belongs to. 940298192Sdelphij */ 941298192Sdelphij for ( ; num; num--) { 942354939Sdelphij if (pread(fd, xph_addr, xph_sizeof, off) < 943354939Sdelphij CAST(ssize_t, xph_sizeof)) { 944298192Sdelphij file_badread(ms); 945298192Sdelphij return -1; 946298192Sdelphij } 947298192Sdelphij off += xph_sizeof; 948298192Sdelphij 949298192Sdelphij if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 950298192Sdelphij /* Perhaps warn here */ 951298192Sdelphij continue; 952298192Sdelphij } 953298192Sdelphij 954298192Sdelphij if (virtaddr >= xph_vaddr && virtaddr < xph_vaddr + xph_filesz) 955298192Sdelphij return xph_offset + (virtaddr - xph_vaddr); 956298192Sdelphij } 957298192Sdelphij return 0; 958298192Sdelphij} 959298192Sdelphij 960276577Sdelphijprivate size_t 961298192Sdelphijget_string_on_virtaddr(struct magic_set *ms, 962298192Sdelphij int swap, int clazz, int fd, off_t ph_off, int ph_num, 963298192Sdelphij off_t fsize, uint64_t virtaddr, char *buf, ssize_t buflen) 964298192Sdelphij{ 965298192Sdelphij char *bptr; 966298192Sdelphij off_t offset; 967298192Sdelphij 968298192Sdelphij if (buflen == 0) 969298192Sdelphij return 0; 970298192Sdelphij 971298192Sdelphij offset = get_offset_from_virtaddr(ms, swap, clazz, fd, ph_off, ph_num, 972298192Sdelphij fsize, virtaddr); 973354939Sdelphij if (offset < 0 || 974354939Sdelphij (buflen = pread(fd, buf, CAST(size_t, buflen), offset)) <= 0) { 975298192Sdelphij file_badread(ms); 976298192Sdelphij return 0; 977298192Sdelphij } 978298192Sdelphij 979298192Sdelphij buf[buflen - 1] = '\0'; 980298192Sdelphij 981298192Sdelphij /* We expect only printable characters, so return if buffer contains 982298192Sdelphij * non-printable character before the '\0' or just '\0'. */ 983354939Sdelphij for (bptr = buf; *bptr && isprint(CAST(unsigned char, *bptr)); bptr++) 984298192Sdelphij continue; 985298192Sdelphij if (*bptr != '\0') 986298192Sdelphij return 0; 987298192Sdelphij 988298192Sdelphij return bptr - buf; 989298192Sdelphij} 990298192Sdelphij 991298192Sdelphij 992337827Seadler/*ARGSUSED*/ 993298192Sdelphijprivate int 994298192Sdelphijdo_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 995298192Sdelphij int swap, uint32_t namesz __attribute__((__unused__)), 996298192Sdelphij uint32_t descsz __attribute__((__unused__)), 997298192Sdelphij size_t noff __attribute__((__unused__)), size_t doff, 998298192Sdelphij int *flags, size_t size __attribute__((__unused__)), int clazz, 999298192Sdelphij int fd, off_t ph_off, int ph_num, off_t fsize) 1000298192Sdelphij{ 1001298192Sdelphij#ifdef ELFCORE 1002298192Sdelphij Aux32Info auxv32; 1003298192Sdelphij Aux64Info auxv64; 1004298192Sdelphij size_t elsize = xauxv_sizeof; 1005298192Sdelphij const char *tag; 1006298192Sdelphij int is_string; 1007298192Sdelphij size_t nval; 1008298192Sdelphij 1009328874Seadler if ((*flags & (FLAGS_IS_CORE|FLAGS_DID_CORE_STYLE)) != 1010328874Seadler (FLAGS_IS_CORE|FLAGS_DID_CORE_STYLE)) 1011298192Sdelphij return 0; 1012298192Sdelphij 1013328874Seadler switch (*flags & FLAGS_CORE_STYLE) { 1014328874Seadler case OS_STYLE_SVR4: 1015328874Seadler if (type != NT_AUXV) 1016328874Seadler return 0; 1017328874Seadler break; 1018328874Seadler#ifdef notyet 1019328874Seadler case OS_STYLE_NETBSD: 1020328874Seadler if (type != NT_NETBSD_CORE_AUXV) 1021328874Seadler return 0; 1022328874Seadler break; 1023328874Seadler case OS_STYLE_FREEBSD: 1024328874Seadler if (type != NT_FREEBSD_PROCSTAT_AUXV) 1025328874Seadler return 0; 1026328874Seadler break; 1027328874Seadler#endif 1028328874Seadler default: 1029328874Seadler return 0; 1030328874Seadler } 1031328874Seadler 1032298192Sdelphij *flags |= FLAGS_DID_AUXV; 1033298192Sdelphij 1034298192Sdelphij nval = 0; 1035298192Sdelphij for (size_t off = 0; off + elsize <= descsz; off += elsize) { 1036337827Seadler memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof); 1037298192Sdelphij /* Limit processing to 50 vector entries to prevent DoS */ 1038298192Sdelphij if (nval++ >= 50) { 1039298192Sdelphij file_error(ms, 0, "Too many ELF Auxv elements"); 1040298192Sdelphij return 1; 1041298192Sdelphij } 1042298192Sdelphij 1043298192Sdelphij switch(xauxv_type) { 1044298192Sdelphij case AT_LINUX_EXECFN: 1045298192Sdelphij is_string = 1; 1046298192Sdelphij tag = "execfn"; 1047298192Sdelphij break; 1048298192Sdelphij case AT_LINUX_PLATFORM: 1049298192Sdelphij is_string = 1; 1050298192Sdelphij tag = "platform"; 1051298192Sdelphij break; 1052298192Sdelphij case AT_LINUX_UID: 1053298192Sdelphij is_string = 0; 1054298192Sdelphij tag = "real uid"; 1055298192Sdelphij break; 1056298192Sdelphij case AT_LINUX_GID: 1057298192Sdelphij is_string = 0; 1058298192Sdelphij tag = "real gid"; 1059298192Sdelphij break; 1060298192Sdelphij case AT_LINUX_EUID: 1061298192Sdelphij is_string = 0; 1062298192Sdelphij tag = "effective uid"; 1063298192Sdelphij break; 1064298192Sdelphij case AT_LINUX_EGID: 1065298192Sdelphij is_string = 0; 1066298192Sdelphij tag = "effective gid"; 1067298192Sdelphij break; 1068298192Sdelphij default: 1069298192Sdelphij is_string = 0; 1070298192Sdelphij tag = NULL; 1071298192Sdelphij break; 1072298192Sdelphij } 1073298192Sdelphij 1074298192Sdelphij if (tag == NULL) 1075298192Sdelphij continue; 1076298192Sdelphij 1077298192Sdelphij if (is_string) { 1078298192Sdelphij char buf[256]; 1079298192Sdelphij ssize_t buflen; 1080298192Sdelphij buflen = get_string_on_virtaddr(ms, swap, clazz, fd, 1081298192Sdelphij ph_off, ph_num, fsize, xauxv_val, buf, sizeof(buf)); 1082298192Sdelphij 1083298192Sdelphij if (buflen == 0) 1084298192Sdelphij continue; 1085354939Sdelphij 1086298192Sdelphij if (file_printf(ms, ", %s: '%s'", tag, buf) == -1) 1087354939Sdelphij return -1; 1088298192Sdelphij } else { 1089354939Sdelphij if (file_printf(ms, ", %s: %d", tag, 1090354939Sdelphij CAST(int, xauxv_val)) == -1) 1091354939Sdelphij return -1; 1092298192Sdelphij } 1093298192Sdelphij } 1094298192Sdelphij return 1; 1095298192Sdelphij#else 1096298192Sdelphij return 0; 1097298192Sdelphij#endif 1098298192Sdelphij} 1099298192Sdelphij 1100298192Sdelphijprivate size_t 1101337827Seadlerdodynamic(struct magic_set *ms, void *vbuf, size_t offset, size_t size, 1102337827Seadler int clazz, int swap) 1103337827Seadler{ 1104337827Seadler Elf32_Dyn dh32; 1105337827Seadler Elf64_Dyn dh64; 1106337827Seadler unsigned char *dbuf = CAST(unsigned char *, vbuf); 1107337827Seadler 1108337827Seadler if (xdh_sizeof + offset > size) { 1109337827Seadler /* 1110337827Seadler * We're out of note headers. 1111337827Seadler */ 1112337827Seadler return xdh_sizeof + offset; 1113337827Seadler } 1114337827Seadler 1115337827Seadler memcpy(xdh_addr, &dbuf[offset], xdh_sizeof); 1116337827Seadler offset += xdh_sizeof; 1117337827Seadler 1118337827Seadler switch (xdh_tag) { 1119337827Seadler case DT_FLAGS_1: 1120354939Sdelphij if (xdh_val & DF_1_PIE) 1121337827Seadler ms->mode |= 0111; 1122337827Seadler else 1123337827Seadler ms->mode &= ~0111; 1124337827Seadler break; 1125337827Seadler default: 1126337827Seadler break; 1127337827Seadler } 1128337827Seadler return offset; 1129337827Seadler} 1130337827Seadler 1131337827Seadler 1132337827Seadlerprivate size_t 1133276577Sdelphijdonote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, 1134298192Sdelphij int clazz, int swap, size_t align, int *flags, uint16_t *notecount, 1135298192Sdelphij int fd, off_t ph_off, int ph_num, off_t fsize) 1136276577Sdelphij{ 1137276577Sdelphij Elf32_Nhdr nh32; 1138276577Sdelphij Elf64_Nhdr nh64; 1139276577Sdelphij size_t noff, doff; 1140276577Sdelphij uint32_t namesz, descsz; 1141362844Sdelphij char buf[256]; 1142276577Sdelphij unsigned char *nbuf = CAST(unsigned char *, vbuf); 1143276577Sdelphij 1144276577Sdelphij if (*notecount == 0) 1145276577Sdelphij return 0; 1146276577Sdelphij --*notecount; 1147276577Sdelphij 1148276577Sdelphij if (xnh_sizeof + offset > size) { 1149276577Sdelphij /* 1150276577Sdelphij * We're out of note headers. 1151276577Sdelphij */ 1152276577Sdelphij return xnh_sizeof + offset; 1153276577Sdelphij } 1154360521Sdelphij /*XXX: GCC */ 1155360521Sdelphij memset(&nh32, 0, sizeof(nh32)); 1156360521Sdelphij memset(&nh64, 0, sizeof(nh64)); 1157276577Sdelphij 1158337827Seadler memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); 1159276577Sdelphij offset += xnh_sizeof; 1160276577Sdelphij 1161276577Sdelphij namesz = xnh_namesz; 1162276577Sdelphij descsz = xnh_descsz; 1163298192Sdelphij 1164276577Sdelphij if ((namesz == 0) && (descsz == 0)) { 1165276577Sdelphij /* 1166276577Sdelphij * We're out of note headers. 1167276577Sdelphij */ 1168276577Sdelphij return (offset >= size) ? offset : size; 1169276577Sdelphij } 1170276577Sdelphij 1171276577Sdelphij if (namesz & 0x80000000) { 1172354939Sdelphij if (file_printf(ms, ", bad note name size %#lx", 1173354939Sdelphij CAST(unsigned long, namesz)) == -1) 1174354939Sdelphij return -1; 1175276577Sdelphij return 0; 1176276577Sdelphij } 1177276577Sdelphij 1178276577Sdelphij if (descsz & 0x80000000) { 1179354939Sdelphij if (file_printf(ms, ", bad note description size %#lx", 1180354939Sdelphij CAST(unsigned long, descsz)) == -1) 1181354939Sdelphij return -1; 1182276577Sdelphij return 0; 1183276577Sdelphij } 1184276577Sdelphij 1185276577Sdelphij noff = offset; 1186276577Sdelphij doff = ELF_ALIGN(offset + namesz); 1187276577Sdelphij 1188276577Sdelphij if (offset + namesz > size) { 1189276577Sdelphij /* 1190276577Sdelphij * We're past the end of the buffer. 1191276577Sdelphij */ 1192276577Sdelphij return doff; 1193276577Sdelphij } 1194276577Sdelphij 1195276577Sdelphij offset = ELF_ALIGN(doff + descsz); 1196276577Sdelphij if (doff + descsz > size) { 1197276577Sdelphij /* 1198276577Sdelphij * We're past the end of the buffer. 1199276577Sdelphij */ 1200276577Sdelphij return (offset >= size) ? offset : size; 1201276577Sdelphij } 1202276577Sdelphij 1203298192Sdelphij 1204276577Sdelphij if ((*flags & FLAGS_DID_OS_NOTE) == 0) { 1205276577Sdelphij if (do_os_note(ms, nbuf, xnh_type, swap, 1206276577Sdelphij namesz, descsz, noff, doff, flags)) 1207298192Sdelphij return offset; 1208276577Sdelphij } 1209276577Sdelphij 1210276577Sdelphij if ((*flags & FLAGS_DID_BUILD_ID) == 0) { 1211276577Sdelphij if (do_bid_note(ms, nbuf, xnh_type, swap, 1212276577Sdelphij namesz, descsz, noff, doff, flags)) 1213298192Sdelphij return offset; 1214276577Sdelphij } 1215354939Sdelphij 1216276577Sdelphij if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) { 1217276577Sdelphij if (do_pax_note(ms, nbuf, xnh_type, swap, 1218276577Sdelphij namesz, descsz, noff, doff, flags)) 1219298192Sdelphij return offset; 1220276577Sdelphij } 1221276577Sdelphij 1222276577Sdelphij if ((*flags & FLAGS_DID_CORE) == 0) { 1223276577Sdelphij if (do_core_note(ms, nbuf, xnh_type, swap, 1224276577Sdelphij namesz, descsz, noff, doff, flags, size, clazz)) 1225298192Sdelphij return offset; 1226276577Sdelphij } 1227276577Sdelphij 1228298192Sdelphij if ((*flags & FLAGS_DID_AUXV) == 0) { 1229298192Sdelphij if (do_auxv_note(ms, nbuf, xnh_type, swap, 1230298192Sdelphij namesz, descsz, noff, doff, flags, size, clazz, 1231298192Sdelphij fd, ph_off, ph_num, fsize)) 1232298192Sdelphij return offset; 1233298192Sdelphij } 1234298192Sdelphij 1235354939Sdelphij if (namesz == 7 && strcmp(RCAST(char *, &nbuf[noff]), "NetBSD") == 0) { 1236337827Seadler int descw, flag; 1237337827Seadler const char *str, *tag; 1238276577Sdelphij if (descsz > 100) 1239276577Sdelphij descsz = 100; 1240276577Sdelphij switch (xnh_type) { 1241276577Sdelphij case NT_NETBSD_VERSION: 1242298192Sdelphij return offset; 1243276577Sdelphij case NT_NETBSD_MARCH: 1244337827Seadler flag = FLAGS_DID_NETBSD_MARCH; 1245337827Seadler tag = "compiled for"; 1246276577Sdelphij break; 1247276577Sdelphij case NT_NETBSD_CMODEL: 1248337827Seadler flag = FLAGS_DID_NETBSD_CMODEL; 1249337827Seadler tag = "compiler model"; 1250276577Sdelphij break; 1251337827Seadler case NT_NETBSD_EMULATION: 1252337827Seadler flag = FLAGS_DID_NETBSD_EMULATION; 1253337827Seadler tag = "emulation:"; 1254337827Seadler break; 1255276577Sdelphij default: 1256276577Sdelphij if (*flags & FLAGS_DID_NETBSD_UNKNOWN) 1257298192Sdelphij return offset; 1258276577Sdelphij *flags |= FLAGS_DID_NETBSD_UNKNOWN; 1259276577Sdelphij if (file_printf(ms, ", note=%u", xnh_type) == -1) 1260298192Sdelphij return offset; 1261337827Seadler return offset; 1262276577Sdelphij } 1263337827Seadler 1264337827Seadler if (*flags & flag) 1265337827Seadler return offset; 1266354939Sdelphij str = RCAST(const char *, &nbuf[doff]); 1267337827Seadler descw = CAST(int, descsz); 1268337827Seadler *flags |= flag; 1269362844Sdelphij file_printf(ms, ", %s: %s", tag, 1270362844Sdelphij file_copystr(buf, sizeof(buf), descw, str)); 1271298192Sdelphij return offset; 1272276577Sdelphij } 1273276577Sdelphij 1274133359Sobrien return offset; 127568349Sobrien} 127668349Sobrien 1277186690Sobrien/* SunOS 5.x hardware capability descriptions */ 1278186690Sobrientypedef struct cap_desc { 1279186690Sobrien uint64_t cd_mask; 1280186690Sobrien const char *cd_name; 1281186690Sobrien} cap_desc_t; 1282186690Sobrien 1283186690Sobrienstatic const cap_desc_t cap_desc_sparc[] = { 1284186690Sobrien { AV_SPARC_MUL32, "MUL32" }, 1285186690Sobrien { AV_SPARC_DIV32, "DIV32" }, 1286186690Sobrien { AV_SPARC_FSMULD, "FSMULD" }, 1287186690Sobrien { AV_SPARC_V8PLUS, "V8PLUS" }, 1288186690Sobrien { AV_SPARC_POPC, "POPC" }, 1289186690Sobrien { AV_SPARC_VIS, "VIS" }, 1290186690Sobrien { AV_SPARC_VIS2, "VIS2" }, 1291186690Sobrien { AV_SPARC_ASI_BLK_INIT, "ASI_BLK_INIT" }, 1292186690Sobrien { AV_SPARC_FMAF, "FMAF" }, 1293186690Sobrien { AV_SPARC_FJFMAU, "FJFMAU" }, 1294186690Sobrien { AV_SPARC_IMA, "IMA" }, 1295186690Sobrien { 0, NULL } 1296186690Sobrien}; 1297186690Sobrien 1298186690Sobrienstatic const cap_desc_t cap_desc_386[] = { 1299186690Sobrien { AV_386_FPU, "FPU" }, 1300186690Sobrien { AV_386_TSC, "TSC" }, 1301186690Sobrien { AV_386_CX8, "CX8" }, 1302186690Sobrien { AV_386_SEP, "SEP" }, 1303186690Sobrien { AV_386_AMD_SYSC, "AMD_SYSC" }, 1304186690Sobrien { AV_386_CMOV, "CMOV" }, 1305186690Sobrien { AV_386_MMX, "MMX" }, 1306186690Sobrien { AV_386_AMD_MMX, "AMD_MMX" }, 1307186690Sobrien { AV_386_AMD_3DNow, "AMD_3DNow" }, 1308186690Sobrien { AV_386_AMD_3DNowx, "AMD_3DNowx" }, 1309186690Sobrien { AV_386_FXSR, "FXSR" }, 1310186690Sobrien { AV_386_SSE, "SSE" }, 1311186690Sobrien { AV_386_SSE2, "SSE2" }, 1312186690Sobrien { AV_386_PAUSE, "PAUSE" }, 1313186690Sobrien { AV_386_SSE3, "SSE3" }, 1314186690Sobrien { AV_386_MON, "MON" }, 1315186690Sobrien { AV_386_CX16, "CX16" }, 1316186690Sobrien { AV_386_AHF, "AHF" }, 1317186690Sobrien { AV_386_TSCP, "TSCP" }, 1318186690Sobrien { AV_386_AMD_SSE4A, "AMD_SSE4A" }, 1319186690Sobrien { AV_386_POPCNT, "POPCNT" }, 1320186690Sobrien { AV_386_AMD_LZCNT, "AMD_LZCNT" }, 1321186690Sobrien { AV_386_SSSE3, "SSSE3" }, 1322186690Sobrien { AV_386_SSE4_1, "SSE4.1" }, 1323186690Sobrien { AV_386_SSE4_2, "SSE4.2" }, 1324186690Sobrien { 0, NULL } 1325186690Sobrien}; 1326186690Sobrien 1327133359Sobrienprivate int 1328186690Sobriendoshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, 1329276577Sdelphij size_t size, off_t fsize, int mach, int strtab, int *flags, 1330276577Sdelphij uint16_t *notecount) 133168349Sobrien{ 1332133359Sobrien Elf32_Shdr sh32; 1333133359Sobrien Elf64_Shdr sh64; 1334328874Seadler int stripped = 1, has_debug_info = 0; 1335275666Sdelphij size_t nbadcap = 0; 1336159764Sobrien void *nbuf; 1337267843Sdelphij off_t noff, coff, name_off; 1338328874Seadler uint64_t cap_hw1 = 0; /* SunOS 5.x hardware capabilities */ 1339328874Seadler uint64_t cap_sf1 = 0; /* SunOS 5.x software capabilities */ 1340267843Sdelphij char name[50]; 1341276577Sdelphij ssize_t namesize; 1342133359Sobrien 1343362844Sdelphij if (ms->flags & MAGIC_MIME) 1344362844Sdelphij return 0; 1345362844Sdelphij 1346354939Sdelphij if (num == 0) { 1347354939Sdelphij if (file_printf(ms, ", no section header") == -1) 1348354939Sdelphij return -1; 1349354939Sdelphij return 0; 1350354939Sdelphij } 1351159764Sobrien if (size != xsh_sizeof) { 1352133359Sobrien if (file_printf(ms, ", corrupted section header size") == -1) 1353133359Sobrien return -1; 1354133359Sobrien return 0; 1355133359Sobrien } 1356133359Sobrien 1357267843Sdelphij /* Read offset of name section to be able to read section names later */ 1358284237Sdelphij if (pread(fd, xsh_addr, xsh_sizeof, CAST(off_t, (off + size * strtab))) 1359337827Seadler < CAST(ssize_t, xsh_sizeof)) { 1360328874Seadler if (file_printf(ms, ", missing section headers") == -1) 1361328874Seadler return -1; 1362328874Seadler return 0; 1363267843Sdelphij } 1364267843Sdelphij name_off = xsh_offset; 1365267843Sdelphij 1366360521Sdelphij if (fsize != SIZE_UNKNOWN && fsize < name_off) { 1367360521Sdelphij if (file_printf(ms, ", too large section header offset %jd", 1368360521Sdelphij (intmax_t)name_off) == -1) 1369360521Sdelphij return -1; 1370360521Sdelphij return 0; 1371360521Sdelphij } 1372360521Sdelphij 1373133359Sobrien for ( ; num; num--) { 1374267843Sdelphij /* Read the name of this section. */ 1375337827Seadler if ((namesize = pread(fd, name, sizeof(name) - 1, 1376337827Seadler name_off + xsh_name)) == -1) { 1377267843Sdelphij file_badread(ms); 1378226048Sobrien return -1; 1379226048Sobrien } 1380276577Sdelphij name[namesize] = '\0'; 1381328874Seadler if (strcmp(name, ".debug_info") == 0) { 1382328874Seadler has_debug_info = 1; 1383267843Sdelphij stripped = 0; 1384328874Seadler } 1385267843Sdelphij 1386337827Seadler if (pread(fd, xsh_addr, xsh_sizeof, off) < 1387337827Seadler CAST(ssize_t, xsh_sizeof)) { 1388133359Sobrien file_badread(ms); 1389133359Sobrien return -1; 1390133359Sobrien } 1391226048Sobrien off += size; 1392226048Sobrien 1393226048Sobrien /* Things we can determine before we seek */ 1394159764Sobrien switch (xsh_type) { 1395159764Sobrien case SHT_SYMTAB: 1396159764Sobrien#if 0 1397159764Sobrien case SHT_DYNSYM: 1398159764Sobrien#endif 1399159764Sobrien stripped = 0; 1400159764Sobrien break; 1401226048Sobrien default: 1402275698Sdelphij if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) { 1403226048Sobrien /* Perhaps warn here */ 1404226048Sobrien continue; 1405226048Sobrien } 1406226048Sobrien break; 1407226048Sobrien } 1408226048Sobrien 1409287453Sdelphij 1410226048Sobrien /* Things we can determine when we seek */ 1411226048Sobrien switch (xsh_type) { 1412159764Sobrien case SHT_NOTE: 1413337827Seadler if (CAST(uintmax_t, (xsh_size + xsh_offset)) > 1414337827Seadler CAST(uintmax_t, fsize)) { 1415287453Sdelphij if (file_printf(ms, 1416328874Seadler ", note offset/size %#" INTMAX_T_FORMAT 1417328874Seadler "x+%#" INTMAX_T_FORMAT "x exceeds" 1418328874Seadler " file size %#" INTMAX_T_FORMAT "x", 1419337827Seadler CAST(uintmax_t, xsh_offset), 1420337827Seadler CAST(uintmax_t, xsh_size), 1421337827Seadler CAST(uintmax_t, fsize)) == -1) 1422287453Sdelphij return -1; 1423354939Sdelphij return 0; 1424287453Sdelphij } 1425267843Sdelphij if ((nbuf = malloc(xsh_size)) == NULL) { 1426159764Sobrien file_error(ms, errno, "Cannot allocate memory" 1427159764Sobrien " for note"); 1428159764Sobrien return -1; 1429159764Sobrien } 1430288143Sdelphij if (pread(fd, nbuf, xsh_size, xsh_offset) < 1431337827Seadler CAST(ssize_t, xsh_size)) { 1432159764Sobrien file_badread(ms); 1433159764Sobrien free(nbuf); 1434159764Sobrien return -1; 1435159764Sobrien } 1436159764Sobrien 1437159764Sobrien noff = 0; 1438159764Sobrien for (;;) { 1439337827Seadler if (noff >= CAST(off_t, xsh_size)) 1440159764Sobrien break; 1441337827Seadler noff = donote(ms, nbuf, CAST(size_t, noff), 1442298192Sdelphij xsh_size, clazz, swap, 4, flags, notecount, 1443298192Sdelphij fd, 0, 0, 0); 1444159764Sobrien if (noff == 0) 1445159764Sobrien break; 1446159764Sobrien } 1447159764Sobrien free(nbuf); 1448159764Sobrien break; 1449186690Sobrien case SHT_SUNW_cap: 1450267843Sdelphij switch (mach) { 1451267843Sdelphij case EM_SPARC: 1452267843Sdelphij case EM_SPARCV9: 1453267843Sdelphij case EM_IA_64: 1454267843Sdelphij case EM_386: 1455267843Sdelphij case EM_AMD64: 1456267843Sdelphij break; 1457267843Sdelphij default: 1458267843Sdelphij goto skip; 1459267843Sdelphij } 1460267843Sdelphij 1461275666Sdelphij if (nbadcap > 5) 1462275666Sdelphij break; 1463337827Seadler if (lseek(fd, xsh_offset, SEEK_SET) 1464337827Seadler == CAST(off_t, -1)) { 1465226048Sobrien file_badseek(ms); 1466186690Sobrien return -1; 1467186690Sobrien } 1468186690Sobrien coff = 0; 1469186690Sobrien for (;;) { 1470186690Sobrien Elf32_Cap cap32; 1471186690Sobrien Elf64_Cap cap64; 1472191736Sobrien char cbuf[/*CONSTCOND*/ 1473337827Seadler MAX(sizeof(cap32), sizeof(cap64))]; 1474337827Seadler if ((coff += xcap_sizeof) > 1475337827Seadler CAST(off_t, xsh_size)) 1476186690Sobrien break; 1477337827Seadler if (read(fd, cbuf, CAST(size_t, xcap_sizeof)) != 1478337827Seadler CAST(ssize_t, xcap_sizeof)) { 1479186690Sobrien file_badread(ms); 1480186690Sobrien return -1; 1481186690Sobrien } 1482267843Sdelphij if (cbuf[0] == 'A') { 1483267843Sdelphij#ifdef notyet 1484267843Sdelphij char *p = cbuf + 1; 1485267843Sdelphij uint32_t len, tag; 1486267843Sdelphij memcpy(&len, p, sizeof(len)); 1487267843Sdelphij p += 4; 1488267843Sdelphij len = getu32(swap, len); 1489267843Sdelphij if (memcmp("gnu", p, 3) != 0) { 1490267843Sdelphij if (file_printf(ms, 1491267843Sdelphij ", unknown capability %.3s", p) 1492267843Sdelphij == -1) 1493267843Sdelphij return -1; 1494267843Sdelphij break; 1495267843Sdelphij } 1496267843Sdelphij p += strlen(p) + 1; 1497267843Sdelphij tag = *p++; 1498267843Sdelphij memcpy(&len, p, sizeof(len)); 1499267843Sdelphij p += 4; 1500267843Sdelphij len = getu32(swap, len); 1501267843Sdelphij if (tag != 1) { 1502267843Sdelphij if (file_printf(ms, ", unknown gnu" 1503267843Sdelphij " capability tag %d", tag) 1504267843Sdelphij == -1) 1505267843Sdelphij return -1; 1506267843Sdelphij break; 1507267843Sdelphij } 1508354939Sdelphij // gnu attributes 1509267843Sdelphij#endif 1510267843Sdelphij break; 1511267843Sdelphij } 1512337827Seadler memcpy(xcap_addr, cbuf, xcap_sizeof); 1513186690Sobrien switch (xcap_tag) { 1514186690Sobrien case CA_SUNW_NULL: 1515186690Sobrien break; 1516186690Sobrien case CA_SUNW_HW_1: 1517186690Sobrien cap_hw1 |= xcap_val; 1518186690Sobrien break; 1519186690Sobrien case CA_SUNW_SF_1: 1520186690Sobrien cap_sf1 |= xcap_val; 1521186690Sobrien break; 1522186690Sobrien default: 1523186690Sobrien if (file_printf(ms, 1524186690Sobrien ", with unknown capability " 1525328874Seadler "%#" INT64_T_FORMAT "x = %#" 1526226048Sobrien INT64_T_FORMAT "x", 1527337827Seadler CAST(unsigned long long, xcap_tag), 1528337827Seadler CAST(unsigned long long, xcap_val)) 1529337827Seadler == -1) 1530186690Sobrien return -1; 1531275666Sdelphij if (nbadcap++ > 2) 1532275666Sdelphij coff = xsh_size; 1533186690Sobrien break; 1534186690Sobrien } 1535186690Sobrien } 1536267843Sdelphij /*FALLTHROUGH*/ 1537267843Sdelphij skip: 1538226048Sobrien default: 1539226048Sobrien break; 1540133359Sobrien } 1541133359Sobrien } 1542267843Sdelphij 1543328874Seadler if (has_debug_info) { 1544328874Seadler if (file_printf(ms, ", with debug_info") == -1) 1545328874Seadler return -1; 1546328874Seadler } 1547159764Sobrien if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1) 1548133359Sobrien return -1; 1549186690Sobrien if (cap_hw1) { 1550186690Sobrien const cap_desc_t *cdp; 1551186690Sobrien switch (mach) { 1552186690Sobrien case EM_SPARC: 1553186690Sobrien case EM_SPARC32PLUS: 1554186690Sobrien case EM_SPARCV9: 1555186690Sobrien cdp = cap_desc_sparc; 1556186690Sobrien break; 1557186690Sobrien case EM_386: 1558186690Sobrien case EM_IA_64: 1559186690Sobrien case EM_AMD64: 1560186690Sobrien cdp = cap_desc_386; 1561186690Sobrien break; 1562186690Sobrien default: 1563186690Sobrien cdp = NULL; 1564186690Sobrien break; 1565186690Sobrien } 1566186690Sobrien if (file_printf(ms, ", uses") == -1) 1567186690Sobrien return -1; 1568186690Sobrien if (cdp) { 1569186690Sobrien while (cdp->cd_name) { 1570186690Sobrien if (cap_hw1 & cdp->cd_mask) { 1571186690Sobrien if (file_printf(ms, 1572186690Sobrien " %s", cdp->cd_name) == -1) 1573186690Sobrien return -1; 1574186690Sobrien cap_hw1 &= ~cdp->cd_mask; 1575186690Sobrien } 1576186690Sobrien ++cdp; 1577186690Sobrien } 1578186690Sobrien if (cap_hw1) 1579186690Sobrien if (file_printf(ms, 1580328874Seadler " unknown hardware capability %#" 1581226048Sobrien INT64_T_FORMAT "x", 1582337827Seadler CAST(unsigned long long, cap_hw1)) == -1) 1583186690Sobrien return -1; 1584186690Sobrien } else { 1585186690Sobrien if (file_printf(ms, 1586328874Seadler " hardware capability %#" INT64_T_FORMAT "x", 1587337827Seadler CAST(unsigned long long, cap_hw1)) == -1) 1588186690Sobrien return -1; 1589186690Sobrien } 1590186690Sobrien } 1591186690Sobrien if (cap_sf1) { 1592186690Sobrien if (cap_sf1 & SF1_SUNW_FPUSED) { 1593186690Sobrien if (file_printf(ms, 1594186690Sobrien (cap_sf1 & SF1_SUNW_FPKNWN) 1595186690Sobrien ? ", uses frame pointer" 1596186690Sobrien : ", not known to use frame pointer") == -1) 1597186690Sobrien return -1; 1598186690Sobrien } 1599186690Sobrien cap_sf1 &= ~SF1_SUNW_MASK; 1600186690Sobrien if (cap_sf1) 1601186690Sobrien if (file_printf(ms, 1602328874Seadler ", with unknown software capability %#" 1603226048Sobrien INT64_T_FORMAT "x", 1604337827Seadler CAST(unsigned long long, cap_sf1)) == -1) 1605186690Sobrien return -1; 1606186690Sobrien } 1607133359Sobrien return 0; 1608133359Sobrien} 1609133359Sobrien 1610133359Sobrien/* 1611133359Sobrien * Look through the program headers of an executable image, searching 1612133359Sobrien * for a PT_INTERP section; if one is found, it's dynamically linked, 1613133359Sobrien * otherwise it's statically linked. 1614133359Sobrien */ 1615133359Sobrienprivate int 1616186690Sobriendophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 1617276577Sdelphij int num, size_t size, off_t fsize, int sh_num, int *flags, 1618276577Sdelphij uint16_t *notecount) 1619133359Sobrien{ 1620133359Sobrien Elf32_Phdr ph32; 1621133359Sobrien Elf64_Phdr ph64; 1622133359Sobrien const char *linking_style = "statically"; 1623133359Sobrien unsigned char nbuf[BUFSIZ]; 1624276577Sdelphij char ibuf[BUFSIZ]; 1625337827Seadler char interp[BUFSIZ]; 1626226048Sobrien ssize_t bufsize; 1627267843Sdelphij size_t offset, align, len; 1628354939Sdelphij 1629354939Sdelphij if (num == 0) { 1630354939Sdelphij if (file_printf(ms, ", no program header") == -1) 1631354939Sdelphij return -1; 1632354939Sdelphij return 0; 1633354939Sdelphij } 1634159764Sobrien if (size != xph_sizeof) { 1635133359Sobrien if (file_printf(ms, ", corrupted program header size") == -1) 1636186690Sobrien return -1; 1637133359Sobrien return 0; 1638133359Sobrien } 1639169942Sobrien 1640337827Seadler interp[0] = '\0'; 1641133359Sobrien for ( ; num; num--) { 1642337827Seadler int doread; 1643354939Sdelphij if (pread(fd, xph_addr, xph_sizeof, off) < 1644337827Seadler CAST(ssize_t, xph_sizeof)) { 1645267843Sdelphij file_badread(ms); 1646133359Sobrien return -1; 1647133359Sobrien } 1648169942Sobrien 1649226048Sobrien off += size; 1650276577Sdelphij bufsize = 0; 1651276577Sdelphij align = 4; 1652169942Sobrien 1653226048Sobrien /* Things we can determine before we seek */ 1654159764Sobrien switch (xph_type) { 1655133359Sobrien case PT_DYNAMIC: 1656337827Seadler doread = 1; 1657362844Sdelphij linking_style = "dynamically"; 1658133359Sobrien break; 1659276577Sdelphij case PT_NOTE: 1660276577Sdelphij if (sh_num) /* Did this through section headers */ 1661276577Sdelphij continue; 1662276577Sdelphij if (((align = xph_align) & 0x80000000UL) != 0 || 1663276577Sdelphij align < 4) { 1664354939Sdelphij if (file_printf(ms, 1665328874Seadler ", invalid note alignment %#lx", 1666337827Seadler CAST(unsigned long, align)) == -1) 1667276577Sdelphij return -1; 1668276577Sdelphij align = 4; 1669276577Sdelphij } 1670276577Sdelphij /*FALLTHROUGH*/ 1671133359Sobrien case PT_INTERP: 1672337827Seadler doread = 1; 1673133359Sobrien break; 1674226048Sobrien default: 1675337827Seadler doread = 0; 1676275698Sdelphij if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 1677226048Sobrien /* Maybe warn here? */ 1678226048Sobrien continue; 1679226048Sobrien } 1680226048Sobrien break; 1681226048Sobrien } 1682226048Sobrien 1683337827Seadler if (doread) { 1684337827Seadler len = xph_filesz < sizeof(nbuf) ? xph_filesz 1685337827Seadler : sizeof(nbuf); 1686337827Seadler bufsize = pread(fd, nbuf, len, xph_offset); 1687337827Seadler if (bufsize == -1) { 1688337827Seadler file_badread(ms); 1689337827Seadler return -1; 1690337827Seadler } 1691337827Seadler } else 1692337827Seadler len = 0; 1693337827Seadler 1694226048Sobrien /* Things we can determine when we seek */ 1695226048Sobrien switch (xph_type) { 1696337827Seadler case PT_DYNAMIC: 1697337827Seadler offset = 0; 1698354939Sdelphij // Let DF_1 determine if we are PIE or not. 1699354939Sdelphij ms->mode &= ~0111; 1700337827Seadler for (;;) { 1701354939Sdelphij if (offset >= CAST(size_t, bufsize)) 1702337827Seadler break; 1703337827Seadler offset = dodynamic(ms, nbuf, offset, 1704337827Seadler CAST(size_t, bufsize), clazz, swap); 1705337827Seadler if (offset == 0) 1706337827Seadler break; 1707337827Seadler } 1708362844Sdelphij if (ms->flags & MAGIC_MIME) 1709362844Sdelphij continue; 1710337827Seadler break; 1711337827Seadler 1712276577Sdelphij case PT_INTERP: 1713362844Sdelphij if (ms->flags & MAGIC_MIME) 1714362844Sdelphij continue; 1715276577Sdelphij if (bufsize && nbuf[0]) { 1716276577Sdelphij nbuf[bufsize - 1] = '\0'; 1717354939Sdelphij memcpy(interp, nbuf, CAST(size_t, bufsize)); 1718276577Sdelphij } else 1719337827Seadler strlcpy(interp, "*empty*", sizeof(interp)); 1720276577Sdelphij break; 1721133359Sobrien case PT_NOTE: 1722362844Sdelphij if (ms->flags & MAGIC_MIME) 1723362844Sdelphij return 0; 1724133359Sobrien /* 1725133359Sobrien * This is a PT_NOTE section; loop through all the notes 1726133359Sobrien * in the section. 1727133359Sobrien */ 1728133359Sobrien offset = 0; 1729133359Sobrien for (;;) { 1730354939Sdelphij if (offset >= CAST(size_t, bufsize)) 1731133359Sobrien break; 1732133359Sobrien offset = donote(ms, nbuf, offset, 1733337827Seadler CAST(size_t, bufsize), clazz, swap, align, 1734298192Sdelphij flags, notecount, fd, 0, 0, 0); 1735133359Sobrien if (offset == 0) 1736133359Sobrien break; 1737133359Sobrien } 1738133359Sobrien break; 1739175296Sobrien default: 1740362844Sdelphij if (ms->flags & MAGIC_MIME) 1741362844Sdelphij continue; 1742175296Sobrien break; 1743133359Sobrien } 1744133359Sobrien } 1745362844Sdelphij if (ms->flags & MAGIC_MIME) 1746362844Sdelphij return 0; 1747276577Sdelphij if (file_printf(ms, ", %s linked", linking_style) 1748133359Sobrien == -1) 1749276577Sdelphij return -1; 1750276577Sdelphij if (interp[0]) 1751276577Sdelphij if (file_printf(ms, ", interpreter %s", 1752354939Sdelphij file_printable(ibuf, sizeof(ibuf), interp, sizeof(interp))) 1753354939Sdelphij == -1) 1754276577Sdelphij return -1; 1755133359Sobrien return 0; 1756133359Sobrien} 1757133359Sobrien 1758133359Sobrien 1759133359Sobrienprotected int 1760337827Seadlerfile_tryelf(struct magic_set *ms, const struct buffer *b) 1761133359Sobrien{ 1762337827Seadler int fd = b->fd; 1763354939Sdelphij const unsigned char *buf = CAST(const unsigned char *, b->fbuf); 1764337827Seadler size_t nbytes = b->flen; 176568349Sobrien union { 1766103373Sobrien int32_t l; 1767337827Seadler char c[sizeof(int32_t)]; 176868349Sobrien } u; 1769186690Sobrien int clazz; 177068349Sobrien int swap; 1771169942Sobrien struct stat st; 1772354939Sdelphij const struct stat *stp; 1773169942Sobrien off_t fsize; 1774169942Sobrien int flags = 0; 1775186690Sobrien Elf32_Ehdr elf32hdr; 1776186690Sobrien Elf64_Ehdr elf64hdr; 1777276577Sdelphij uint16_t type, phnum, shnum, notecount; 177868349Sobrien 1779362844Sdelphij if (ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) 1780186690Sobrien return 0; 178168349Sobrien /* 178268349Sobrien * ELF executables have multiple section headers in arbitrary 178368349Sobrien * file locations and thus file(1) cannot determine it from easily. 178468349Sobrien * Instead we traverse thru all section headers until a symbol table 178568349Sobrien * one is found or else the binary is stripped. 1786354939Sdelphij * Return immediately if it's not ELF (so we avoid pipe2file unless 1787354939Sdelphij * needed). 178868349Sobrien */ 178968349Sobrien if (buf[EI_MAG0] != ELFMAG0 179068349Sobrien || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) 179168349Sobrien || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) 1792186690Sobrien return 0; 179368349Sobrien 1794186690Sobrien /* 1795186690Sobrien * If we cannot seek, it must be a pipe, socket or fifo. 1796186690Sobrien */ 1797337827Seadler if((lseek(fd, CAST(off_t, 0), SEEK_SET) == CAST(off_t, -1)) 1798337827Seadler && (errno == ESPIPE)) 1799186690Sobrien fd = file_pipe2file(ms, fd, buf, nbytes); 180068349Sobrien 1801354939Sdelphij if (fd == -1) { 1802354939Sdelphij file_badread(ms); 1803186690Sobrien return -1; 180468349Sobrien } 1805354939Sdelphij 1806354939Sdelphij stp = &b->st; 1807354939Sdelphij /* 1808354939Sdelphij * b->st.st_size != 0 if previous fstat() succeeded, 1809354939Sdelphij * which is likely, we can avoid extra stat() call. 1810354939Sdelphij */ 1811354939Sdelphij if (b->st.st_size == 0) { 1812354939Sdelphij stp = &st; 1813354939Sdelphij if (fstat(fd, &st) == -1) { 1814354939Sdelphij file_badread(ms); 1815354939Sdelphij return -1; 1816354939Sdelphij } 1817354939Sdelphij } 1818354939Sdelphij if (S_ISREG(stp->st_mode) || stp->st_size != 0) 1819354939Sdelphij fsize = stp->st_size; 1820275698Sdelphij else 1821275698Sdelphij fsize = SIZE_UNKNOWN; 182268349Sobrien 1823186690Sobrien clazz = buf[EI_CLASS]; 182468349Sobrien 1825186690Sobrien switch (clazz) { 1826186690Sobrien case ELFCLASS32: 1827186690Sobrien#undef elf_getu 1828186690Sobrien#define elf_getu(a, b) elf_getu32(a, b) 1829186690Sobrien#undef elfhdr 1830186690Sobrien#define elfhdr elf32hdr 1831186690Sobrien#include "elfclass.h" 1832186690Sobrien case ELFCLASS64: 1833186690Sobrien#undef elf_getu 1834186690Sobrien#define elf_getu(a, b) elf_getu64(a, b) 1835186690Sobrien#undef elfhdr 1836186690Sobrien#define elfhdr elf64hdr 1837186690Sobrien#include "elfclass.h" 1838186690Sobrien default: 1839186690Sobrien if (file_printf(ms, ", unknown class %d", clazz) == -1) 1840186690Sobrien return -1; 1841186690Sobrien break; 184268349Sobrien } 1843133359Sobrien return 0; 184468349Sobrien} 184568349Sobrien#endif 1846