readelf.c revision 1.20
1/* $NetBSD: readelf.c,v 1.20 2018/10/19 00:32:47 christos Exp $ */ 2 3/* 4 * Copyright (c) Christos Zoulas 2003. 5 * All Rights Reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice immediately at the beginning of the file, without modification, 12 * this list of conditions, and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29#include "file.h" 30 31#ifndef lint 32#if 0 33FILE_RCSID("@(#)$File: readelf.c,v 1.154 2018/10/15 16:29:16 christos Exp $") 34#else 35__RCSID("$NetBSD: readelf.c,v 1.20 2018/10/19 00:32:47 christos Exp $"); 36#endif 37#endif 38 39#ifdef BUILTIN_ELF 40#include <string.h> 41#include <ctype.h> 42#include <stdlib.h> 43#ifdef HAVE_UNISTD_H 44#include <unistd.h> 45#endif 46 47#include "readelf.h" 48#include "magic.h" 49 50#ifdef ELFCORE 51private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t, 52 off_t, int *, uint16_t *); 53#endif 54private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t, 55 off_t, int, int *, uint16_t *); 56private int doshn(struct magic_set *, int, int, int, off_t, int, size_t, 57 off_t, int, int, int *, uint16_t *); 58private size_t donote(struct magic_set *, void *, size_t, size_t, int, 59 int, size_t, int *, uint16_t *, int, off_t, int, off_t); 60 61#define ELF_ALIGN(a) ((((a) + align - 1) / align) * align) 62 63#define isquote(c) (strchr("'\"`", (c)) != NULL) 64 65private uint16_t getu16(int, uint16_t); 66private uint32_t getu32(int, uint32_t); 67private uint64_t getu64(int, uint64_t); 68 69#define MAX_PHNUM 128 70#define MAX_SHNUM 32768 71#define SIZE_UNKNOWN CAST(off_t, -1) 72 73private int 74toomany(struct magic_set *ms, const char *name, uint16_t num) 75{ 76 if (file_printf(ms, ", too many %s (%u)", name, num) == -1) 77 return -1; 78 return 1; 79} 80 81private uint16_t 82getu16(int swap, uint16_t value) 83{ 84 union { 85 uint16_t ui; 86 char c[2]; 87 } retval, tmpval; 88 89 if (swap) { 90 tmpval.ui = value; 91 92 retval.c[0] = tmpval.c[1]; 93 retval.c[1] = tmpval.c[0]; 94 95 return retval.ui; 96 } else 97 return value; 98} 99 100private uint32_t 101getu32(int swap, uint32_t value) 102{ 103 union { 104 uint32_t ui; 105 char c[4]; 106 } retval, tmpval; 107 108 if (swap) { 109 tmpval.ui = value; 110 111 retval.c[0] = tmpval.c[3]; 112 retval.c[1] = tmpval.c[2]; 113 retval.c[2] = tmpval.c[1]; 114 retval.c[3] = tmpval.c[0]; 115 116 return retval.ui; 117 } else 118 return value; 119} 120 121private uint64_t 122getu64(int swap, uint64_t value) 123{ 124 union { 125 uint64_t ui; 126 char c[8]; 127 } retval, tmpval; 128 129 if (swap) { 130 tmpval.ui = value; 131 132 retval.c[0] = tmpval.c[7]; 133 retval.c[1] = tmpval.c[6]; 134 retval.c[2] = tmpval.c[5]; 135 retval.c[3] = tmpval.c[4]; 136 retval.c[4] = tmpval.c[3]; 137 retval.c[5] = tmpval.c[2]; 138 retval.c[6] = tmpval.c[1]; 139 retval.c[7] = tmpval.c[0]; 140 141 return retval.ui; 142 } else 143 return value; 144} 145 146#define elf_getu16(swap, value) getu16(swap, value) 147#define elf_getu32(swap, value) getu32(swap, value) 148#define elf_getu64(swap, value) getu64(swap, value) 149 150#define xsh_addr (clazz == ELFCLASS32 \ 151 ? CAST(void *, &sh32) \ 152 : CAST(void *, &sh64)) 153#define xsh_sizeof (clazz == ELFCLASS32 \ 154 ? sizeof(sh32) \ 155 : sizeof(sh64)) 156#define xsh_size CAST(size_t, (clazz == ELFCLASS32 \ 157 ? elf_getu32(swap, sh32.sh_size) \ 158 : elf_getu64(swap, sh64.sh_size))) 159#define xsh_offset CAST(off_t, (clazz == ELFCLASS32 \ 160 ? elf_getu32(swap, sh32.sh_offset) \ 161 : elf_getu64(swap, sh64.sh_offset))) 162#define xsh_type (clazz == ELFCLASS32 \ 163 ? elf_getu32(swap, sh32.sh_type) \ 164 : elf_getu32(swap, sh64.sh_type)) 165#define xsh_name (clazz == ELFCLASS32 \ 166 ? elf_getu32(swap, sh32.sh_name) \ 167 : elf_getu32(swap, sh64.sh_name)) 168 169#define xph_addr (clazz == ELFCLASS32 \ 170 ? CAST(void *, &ph32) \ 171 : CAST(void *, &ph64)) 172#define xph_sizeof (clazz == ELFCLASS32 \ 173 ? sizeof(ph32) \ 174 : sizeof(ph64)) 175#define xph_type (clazz == ELFCLASS32 \ 176 ? elf_getu32(swap, ph32.p_type) \ 177 : elf_getu32(swap, ph64.p_type)) 178#define xph_offset CAST(off_t, (clazz == ELFCLASS32 \ 179 ? elf_getu32(swap, ph32.p_offset) \ 180 : elf_getu64(swap, ph64.p_offset))) 181#define xph_align CAST(size_t, (clazz == ELFCLASS32 \ 182 ? CAST(off_t, (ph32.p_align ? \ 183 elf_getu32(swap, ph32.p_align) : 4))\ 184 : CAST(off_t, (ph64.p_align ? \ 185 elf_getu64(swap, ph64.p_align) : 4)))) 186#define xph_vaddr CAST(size_t, (clazz == ELFCLASS32 \ 187 ? CAST(off_t, (ph32.p_vaddr ? \ 188 elf_getu32(swap, ph32.p_vaddr) : 4))\ 189 : CAST(off_t, (ph64.p_vaddr ? \ 190 elf_getu64(swap, ph64.p_vaddr) : 4)))) 191#define xph_filesz CAST(size_t, (clazz == ELFCLASS32 \ 192 ? elf_getu32(swap, ph32.p_filesz) \ 193 : elf_getu64(swap, ph64.p_filesz))) 194#define xph_memsz CAST(size_t, ((clazz == ELFCLASS32 \ 195 ? elf_getu32(swap, ph32.p_memsz) \ 196 : elf_getu64(swap, ph64.p_memsz)))) 197#define xnh_addr (clazz == ELFCLASS32 \ 198 ? CAST(void *, &nh32) \ 199 : CAST(void *, &nh64)) 200#define xnh_sizeof (clazz == ELFCLASS32 \ 201 ? sizeof(nh32) \ 202 : sizeof(nh64)) 203#define xnh_type (clazz == ELFCLASS32 \ 204 ? elf_getu32(swap, nh32.n_type) \ 205 : elf_getu32(swap, nh64.n_type)) 206#define xnh_namesz (clazz == ELFCLASS32 \ 207 ? elf_getu32(swap, nh32.n_namesz) \ 208 : elf_getu32(swap, nh64.n_namesz)) 209#define xnh_descsz (clazz == ELFCLASS32 \ 210 ? elf_getu32(swap, nh32.n_descsz) \ 211 : elf_getu32(swap, nh64.n_descsz)) 212 213#define xdh_addr (clazz == ELFCLASS32 \ 214 ? CAST(void *, &dh32) \ 215 : CAST(void *, &dh64)) 216#define xdh_sizeof (clazz == ELFCLASS32 \ 217 ? sizeof(dh32) \ 218 : sizeof(dh64)) 219#define xdh_tag (clazz == ELFCLASS32 \ 220 ? elf_getu32(swap, dh32.d_tag) \ 221 : elf_getu64(swap, dh64.d_tag)) 222#define xdh_val (clazz == ELFCLASS32 \ 223 ? elf_getu32(swap, dh32.d_un.d_val) \ 224 : elf_getu64(swap, dh64.d_un.d_val)) 225 226#define xcap_addr (clazz == ELFCLASS32 \ 227 ? CAST(void *, &cap32) \ 228 : CAST(void *, &cap64)) 229#define xcap_sizeof (clazz == ELFCLASS32 \ 230 ? sizeof(cap32) \ 231 : sizeof(cap64)) 232#define xcap_tag (clazz == ELFCLASS32 \ 233 ? elf_getu32(swap, cap32.c_tag) \ 234 : elf_getu64(swap, cap64.c_tag)) 235#define xcap_val (clazz == ELFCLASS32 \ 236 ? elf_getu32(swap, cap32.c_un.c_val) \ 237 : elf_getu64(swap, cap64.c_un.c_val)) 238 239#define xauxv_addr (clazz == ELFCLASS32 \ 240 ? CAST(void *, &auxv32) \ 241 : CAST(void *, &auxv64)) 242#define xauxv_sizeof (clazz == ELFCLASS32 \ 243 ? sizeof(auxv32) \ 244 : sizeof(auxv64)) 245#define xauxv_type (clazz == ELFCLASS32 \ 246 ? elf_getu32(swap, auxv32.a_type) \ 247 : elf_getu64(swap, auxv64.a_type)) 248#define xauxv_val (clazz == ELFCLASS32 \ 249 ? elf_getu32(swap, auxv32.a_v) \ 250 : elf_getu64(swap, auxv64.a_v)) 251 252#define prpsoffsets(i) (clazz == ELFCLASS32 \ 253 ? prpsoffsets32[i] \ 254 : prpsoffsets64[i]) 255 256#ifdef ELFCORE 257/* 258 * Try larger offsets first to avoid false matches 259 * from earlier data that happen to look like strings. 260 */ 261static const size_t prpsoffsets32[] = { 262#ifdef USE_NT_PSINFO 263 104, /* SunOS 5.x (command line) */ 264 88, /* SunOS 5.x (short name) */ 265#endif /* USE_NT_PSINFO */ 266 267 100, /* SunOS 5.x (command line) */ 268 84, /* SunOS 5.x (short name) */ 269 270 44, /* Linux (command line) */ 271 28, /* Linux 2.0.36 (short name) */ 272 273 8, /* FreeBSD */ 274}; 275 276static const size_t prpsoffsets64[] = { 277#ifdef USE_NT_PSINFO 278 152, /* SunOS 5.x (command line) */ 279 136, /* SunOS 5.x (short name) */ 280#endif /* USE_NT_PSINFO */ 281 282 136, /* SunOS 5.x, 64-bit (command line) */ 283 120, /* SunOS 5.x, 64-bit (short name) */ 284 285 56, /* Linux (command line) */ 286 40, /* Linux (tested on core from 2.4.x, short name) */ 287 288 16, /* FreeBSD, 64-bit */ 289}; 290 291#define NOFFSETS32 (sizeof(prpsoffsets32) / sizeof(prpsoffsets32[0])) 292#define NOFFSETS64 (sizeof(prpsoffsets64) / sizeof(prpsoffsets64[0])) 293 294#define NOFFSETS (clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64) 295 296/* 297 * Look through the program headers of an executable image, searching 298 * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or 299 * "FreeBSD"; if one is found, try looking in various places in its 300 * contents for a 16-character string containing only printable 301 * characters - if found, that string should be the name of the program 302 * that dropped core. Note: right after that 16-character string is, 303 * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and 304 * Linux, a longer string (80 characters, in 5.x, probably other 305 * SVR4-flavored systems, and Linux) containing the start of the 306 * command line for that program. 307 * 308 * SunOS 5.x core files contain two PT_NOTE sections, with the types 309 * NT_PRPSINFO (old) and NT_PSINFO (new). These structs contain the 310 * same info about the command name and command line, so it probably 311 * isn't worthwhile to look for NT_PSINFO, but the offsets are provided 312 * above (see USE_NT_PSINFO), in case we ever decide to do so. The 313 * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent; 314 * the SunOS 5.x file command relies on this (and prefers the latter). 315 * 316 * The signal number probably appears in a section of type NT_PRSTATUS, 317 * but that's also rather OS-dependent, in ways that are harder to 318 * dissect with heuristics, so I'm not bothering with the signal number. 319 * (I suppose the signal number could be of interest in situations where 320 * you don't have the binary of the program that dropped core; if you 321 * *do* have that binary, the debugger will probably tell you what 322 * signal it was.) 323 */ 324 325#define OS_STYLE_SVR4 0 326#define OS_STYLE_FREEBSD 1 327#define OS_STYLE_NETBSD 2 328 329private const char os_style_names[][8] = { 330 "SVR4", 331 "FreeBSD", 332 "NetBSD", 333}; 334 335#define FLAGS_CORE_STYLE 0x0003 336 337#define FLAGS_DID_CORE 0x0004 338#define FLAGS_DID_OS_NOTE 0x0008 339#define FLAGS_DID_BUILD_ID 0x0010 340#define FLAGS_DID_CORE_STYLE 0x0020 341#define FLAGS_DID_NETBSD_PAX 0x0040 342#define FLAGS_DID_NETBSD_MARCH 0x0080 343#define FLAGS_DID_NETBSD_CMODEL 0x0100 344#define FLAGS_DID_NETBSD_EMULATION 0x0200 345#define FLAGS_DID_NETBSD_UNKNOWN 0x0400 346#define FLAGS_IS_CORE 0x0800 347#define FLAGS_DID_AUXV 0x1000 348 349private int 350dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 351 int num, size_t size, off_t fsize, int *flags, uint16_t *notecount) 352{ 353 Elf32_Phdr ph32; 354 Elf64_Phdr ph64; 355 size_t offset, len; 356 unsigned char nbuf[BUFSIZ]; 357 ssize_t bufsize; 358 off_t ph_off = off; 359 int ph_num = num; 360 361 if (num == 0) { 362 if (file_printf(ms, ", no program header") == -1) 363 return -1; 364 return 0; 365 } 366 if (size != xph_sizeof) { 367 if (file_printf(ms, ", corrupted program header size") == -1) 368 return -1; 369 return 0; 370 } 371 372 /* 373 * Loop through all the program headers. 374 */ 375 for ( ; num; num--) { 376 if (pread(fd, xph_addr, xph_sizeof, off) < 377 CAST(ssize_t, xph_sizeof)) { 378 file_badread(ms); 379 return -1; 380 } 381 off += size; 382 383 if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 384 /* Perhaps warn here */ 385 continue; 386 } 387 388 if (xph_type != PT_NOTE) 389 continue; 390 391 /* 392 * This is a PT_NOTE section; loop through all the notes 393 * in the section. 394 */ 395 len = xph_filesz < sizeof(nbuf) ? xph_filesz : sizeof(nbuf); 396 if ((bufsize = pread(fd, nbuf, len, xph_offset)) == -1) { 397 file_badread(ms); 398 return -1; 399 } 400 offset = 0; 401 for (;;) { 402 if (offset >= (size_t)bufsize) 403 break; 404 offset = donote(ms, nbuf, offset, (size_t)bufsize, 405 clazz, swap, 4, flags, notecount, fd, ph_off, 406 ph_num, fsize); 407 if (offset == 0) 408 break; 409 410 } 411 } 412 return 0; 413} 414#endif 415 416static void 417do_note_netbsd_version(struct magic_set *ms, int swap, void *v) 418{ 419 uint32_t desc; 420 memcpy(&desc, v, sizeof(desc)); 421 desc = elf_getu32(swap, desc); 422 423 if (file_printf(ms, ", for NetBSD") == -1) 424 return; 425 /* 426 * The version number used to be stuck as 199905, and was thus 427 * basically content-free. Newer versions of NetBSD have fixed 428 * this and now use the encoding of __NetBSD_Version__: 429 * 430 * MMmmrrpp00 431 * 432 * M = major version 433 * m = minor version 434 * r = release ["",A-Z,Z[A-Z] but numeric] 435 * p = patchlevel 436 */ 437 if (desc > 100000000U) { 438 uint32_t ver_patch = (desc / 100) % 100; 439 uint32_t ver_rel = (desc / 10000) % 100; 440 uint32_t ver_min = (desc / 1000000) % 100; 441 uint32_t ver_maj = desc / 100000000; 442 443 if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) 444 return; 445 if (ver_rel == 0 && ver_patch != 0) { 446 if (file_printf(ms, ".%u", ver_patch) == -1) 447 return; 448 } else if (ver_rel != 0) { 449 while (ver_rel > 26) { 450 if (file_printf(ms, "Z") == -1) 451 return; 452 ver_rel -= 26; 453 } 454 if (file_printf(ms, "%c", 'A' + ver_rel - 1) 455 == -1) 456 return; 457 } 458 } 459} 460 461static void 462do_note_freebsd_version(struct magic_set *ms, int swap, void *v) 463{ 464 uint32_t desc; 465 466 memcpy(&desc, v, sizeof(desc)); 467 desc = elf_getu32(swap, desc); 468 if (file_printf(ms, ", for FreeBSD") == -1) 469 return; 470 471 /* 472 * Contents is __FreeBSD_version, whose relation to OS 473 * versions is defined by a huge table in the Porter's 474 * Handbook. This is the general scheme: 475 * 476 * Releases: 477 * Mmp000 (before 4.10) 478 * Mmi0p0 (before 5.0) 479 * Mmm0p0 480 * 481 * Development branches: 482 * Mmpxxx (before 4.6) 483 * Mmp1xx (before 4.10) 484 * Mmi1xx (before 5.0) 485 * M000xx (pre-M.0) 486 * Mmm1xx 487 * 488 * M = major version 489 * m = minor version 490 * i = minor version increment (491000 -> 4.10) 491 * p = patchlevel 492 * x = revision 493 * 494 * The first release of FreeBSD to use ELF by default 495 * was version 3.0. 496 */ 497 if (desc == 460002) { 498 if (file_printf(ms, " 4.6.2") == -1) 499 return; 500 } else if (desc < 460100) { 501 if (file_printf(ms, " %d.%d", desc / 100000, 502 desc / 10000 % 10) == -1) 503 return; 504 if (desc / 1000 % 10 > 0) 505 if (file_printf(ms, ".%d", desc / 1000 % 10) == -1) 506 return; 507 if ((desc % 1000 > 0) || (desc % 100000 == 0)) 508 if (file_printf(ms, " (%d)", desc) == -1) 509 return; 510 } else if (desc < 500000) { 511 if (file_printf(ms, " %d.%d", desc / 100000, 512 desc / 10000 % 10 + desc / 1000 % 10) == -1) 513 return; 514 if (desc / 100 % 10 > 0) { 515 if (file_printf(ms, " (%d)", desc) == -1) 516 return; 517 } else if (desc / 10 % 10 > 0) { 518 if (file_printf(ms, ".%d", desc / 10 % 10) == -1) 519 return; 520 } 521 } else { 522 if (file_printf(ms, " %d.%d", desc / 100000, 523 desc / 1000 % 100) == -1) 524 return; 525 if ((desc / 100 % 10 > 0) || 526 (desc % 100000 / 100 == 0)) { 527 if (file_printf(ms, " (%d)", desc) == -1) 528 return; 529 } else if (desc / 10 % 10 > 0) { 530 if (file_printf(ms, ".%d", desc / 10 % 10) == -1) 531 return; 532 } 533 } 534} 535 536private int 537/*ARGSUSED*/ 538do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 539 int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz, 540 size_t noff, size_t doff, int *flags) 541{ 542 if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 543 type == NT_GNU_BUILD_ID && (descsz >= 4 && descsz <= 20)) { 544 uint8_t desc[20]; 545 const char *btype; 546 uint32_t i; 547 *flags |= FLAGS_DID_BUILD_ID; 548 switch (descsz) { 549 case 8: 550 btype = "xxHash"; 551 break; 552 case 16: 553 btype = "md5/uuid"; 554 break; 555 case 20: 556 btype = "sha1"; 557 break; 558 default: 559 btype = "unknown"; 560 break; 561 } 562 if (file_printf(ms, ", BuildID[%s]=", btype) == -1) 563 return 1; 564 memcpy(desc, &nbuf[doff], descsz); 565 for (i = 0; i < descsz; i++) 566 if (file_printf(ms, "%02x", desc[i]) == -1) 567 return 1; 568 return 1; 569 } 570 if (namesz == 4 && strcmp((char *)&nbuf[noff], "Go") == 0 && 571 type == NT_GO_BUILD_ID && descsz < 128) { 572 if (file_printf(ms, ", Go BuildID=%s", 573 (char *)&nbuf[doff]) == -1) 574 return -1; 575 return 1; 576 } 577 return 0; 578} 579 580private int 581do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 582 int swap, uint32_t namesz, uint32_t descsz, 583 size_t noff, size_t doff, int *flags) 584{ 585 if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 && 586 type == NT_GNU_VERSION && descsz == 2) { 587 *flags |= FLAGS_DID_OS_NOTE; 588 if (file_printf(ms, ", for SuSE %d.%d", nbuf[doff], 589 nbuf[doff + 1]) == -1) 590 return -1; 591 return 1; 592 } 593 594 if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 595 type == NT_GNU_VERSION && descsz == 16) { 596 uint32_t desc[4]; 597 memcpy(desc, &nbuf[doff], sizeof(desc)); 598 599 *flags |= FLAGS_DID_OS_NOTE; 600 if (file_printf(ms, ", for GNU/") == -1) 601 return 1; 602 switch (elf_getu32(swap, desc[0])) { 603 case GNU_OS_LINUX: 604 if (file_printf(ms, "Linux") == -1) 605 return 1; 606 break; 607 case GNU_OS_HURD: 608 if (file_printf(ms, "Hurd") == -1) 609 return 1; 610 break; 611 case GNU_OS_SOLARIS: 612 if (file_printf(ms, "Solaris") == -1) 613 return 1; 614 break; 615 case GNU_OS_KFREEBSD: 616 if (file_printf(ms, "kFreeBSD") == -1) 617 return 1; 618 break; 619 case GNU_OS_KNETBSD: 620 if (file_printf(ms, "kNetBSD") == -1) 621 return 1; 622 break; 623 default: 624 if (file_printf(ms, "<unknown>") == -1) 625 return 1; 626 } 627 if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]), 628 elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1) 629 return 1; 630 return 1; 631 } 632 633 if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { 634 if (type == NT_NETBSD_VERSION && descsz == 4) { 635 *flags |= FLAGS_DID_OS_NOTE; 636 do_note_netbsd_version(ms, swap, &nbuf[doff]); 637 return 1; 638 } 639 } 640 641 if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) { 642 if (type == NT_FREEBSD_VERSION && descsz == 4) { 643 *flags |= FLAGS_DID_OS_NOTE; 644 do_note_freebsd_version(ms, swap, &nbuf[doff]); 645 return 1; 646 } 647 } 648 649 if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && 650 type == NT_OPENBSD_VERSION && descsz == 4) { 651 *flags |= FLAGS_DID_OS_NOTE; 652 if (file_printf(ms, ", for OpenBSD") == -1) 653 return 1; 654 /* Content of note is always 0 */ 655 return 1; 656 } 657 658 if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 && 659 type == NT_DRAGONFLY_VERSION && descsz == 4) { 660 uint32_t desc; 661 *flags |= FLAGS_DID_OS_NOTE; 662 if (file_printf(ms, ", for DragonFly") == -1) 663 return 1; 664 memcpy(&desc, &nbuf[doff], sizeof(desc)); 665 desc = elf_getu32(swap, desc); 666 if (file_printf(ms, " %d.%d.%d", desc / 100000, 667 desc / 10000 % 10, desc % 10000) == -1) 668 return 1; 669 return 1; 670 } 671 return 0; 672} 673 674private int 675do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 676 int swap, uint32_t namesz, uint32_t descsz, 677 size_t noff, size_t doff, int *flags) 678{ 679 if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 && 680 type == NT_NETBSD_PAX && descsz == 4) { 681 static const char *pax[] = { 682 "+mprotect", 683 "-mprotect", 684 "+segvguard", 685 "-segvguard", 686 "+ASLR", 687 "-ASLR", 688 }; 689 uint32_t desc; 690 size_t i; 691 int did = 0; 692 693 *flags |= FLAGS_DID_NETBSD_PAX; 694 memcpy(&desc, &nbuf[doff], sizeof(desc)); 695 desc = elf_getu32(swap, desc); 696 697 if (desc && file_printf(ms, ", PaX: ") == -1) 698 return 1; 699 700 for (i = 0; i < __arraycount(pax); i++) { 701 if (((1 << (int)i) & desc) == 0) 702 continue; 703 if (file_printf(ms, "%s%s", did++ ? "," : "", 704 pax[i]) == -1) 705 return 1; 706 } 707 return 1; 708 } 709 return 0; 710} 711 712private int 713do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 714 int swap, uint32_t namesz, uint32_t descsz, 715 size_t noff, size_t doff, int *flags, size_t size, int clazz) 716{ 717#ifdef ELFCORE 718 int os_style = -1; 719 /* 720 * Sigh. The 2.0.36 kernel in Debian 2.1, at 721 * least, doesn't correctly implement name 722 * sections, in core dumps, as specified by 723 * the "Program Linking" section of "UNIX(R) System 724 * V Release 4 Programmer's Guide: ANSI C and 725 * Programming Support Tools", because my copy 726 * clearly says "The first 'namesz' bytes in 'name' 727 * contain a *null-terminated* [emphasis mine] 728 * character representation of the entry's owner 729 * or originator", but the 2.0.36 kernel code 730 * doesn't include the terminating null in the 731 * name.... 732 */ 733 if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) || 734 (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) { 735 os_style = OS_STYLE_SVR4; 736 } 737 738 if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) { 739 os_style = OS_STYLE_FREEBSD; 740 } 741 742 if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11) 743 == 0)) { 744 os_style = OS_STYLE_NETBSD; 745 } 746 747 if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) { 748 if (file_printf(ms, ", %s-style", os_style_names[os_style]) 749 == -1) 750 return 1; 751 *flags |= FLAGS_DID_CORE_STYLE; 752 *flags |= os_style; 753 } 754 755 switch (os_style) { 756 case OS_STYLE_NETBSD: 757 if (type == NT_NETBSD_CORE_PROCINFO) { 758 char sbuf[512]; 759 struct NetBSD_elfcore_procinfo pi; 760 memset(&pi, 0, sizeof(pi)); 761 memcpy(&pi, nbuf + doff, descsz); 762 763 if (file_printf(ms, ", from '%.31s', pid=%u, uid=%u, " 764 "gid=%u, nlwps=%u, lwp=%u (signal %u/code %u)", 765 file_printable(sbuf, sizeof(sbuf), 766 RCAST(char *, pi.cpi_name)), 767 elf_getu32(swap, (uint32_t)pi.cpi_pid), 768 elf_getu32(swap, pi.cpi_euid), 769 elf_getu32(swap, pi.cpi_egid), 770 elf_getu32(swap, pi.cpi_nlwps), 771 elf_getu32(swap, (uint32_t)pi.cpi_siglwp), 772 elf_getu32(swap, pi.cpi_signo), 773 elf_getu32(swap, pi.cpi_sigcode)) == -1) 774 return 1; 775 776 *flags |= FLAGS_DID_CORE; 777 return 1; 778 } 779 break; 780 781 case OS_STYLE_FREEBSD: 782 if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) { 783 size_t argoff, pidoff; 784 785 if (clazz == ELFCLASS32) 786 argoff = 4 + 4 + 17; 787 else 788 argoff = 4 + 4 + 8 + 17; 789 if (file_printf(ms, ", from '%.80s'", nbuf + doff + 790 argoff) == -1) 791 return 1; 792 pidoff = argoff + 81 + 2; 793 if (doff + pidoff + 4 <= size) { 794 if (file_printf(ms, ", pid=%u", 795 elf_getu32(swap, *RCAST(uint32_t *, (nbuf + 796 doff + pidoff)))) == -1) 797 return 1; 798 } 799 *flags |= FLAGS_DID_CORE; 800 } 801 break; 802 803 default: 804 if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) { 805 size_t i, j; 806 unsigned char c; 807 /* 808 * Extract the program name. We assume 809 * it to be 16 characters (that's what it 810 * is in SunOS 5.x and Linux). 811 * 812 * Unfortunately, it's at a different offset 813 * in various OSes, so try multiple offsets. 814 * If the characters aren't all printable, 815 * reject it. 816 */ 817 for (i = 0; i < NOFFSETS; i++) { 818 unsigned char *cname, *cp; 819 size_t reloffset = prpsoffsets(i); 820 size_t noffset = doff + reloffset; 821 size_t k; 822 for (j = 0; j < 16; j++, noffset++, 823 reloffset++) { 824 /* 825 * Make sure we're not past 826 * the end of the buffer; if 827 * we are, just give up. 828 */ 829 if (noffset >= size) 830 goto tryanother; 831 832 /* 833 * Make sure we're not past 834 * the end of the contents; 835 * if we are, this obviously 836 * isn't the right offset. 837 */ 838 if (reloffset >= descsz) 839 goto tryanother; 840 841 c = nbuf[noffset]; 842 if (c == '\0') { 843 /* 844 * A '\0' at the 845 * beginning is 846 * obviously wrong. 847 * Any other '\0' 848 * means we're done. 849 */ 850 if (j == 0) 851 goto tryanother; 852 else 853 break; 854 } else { 855 /* 856 * A nonprintable 857 * character is also 858 * wrong. 859 */ 860 if (!isprint(c) || isquote(c)) 861 goto tryanother; 862 } 863 } 864 /* 865 * Well, that worked. 866 */ 867 868 /* 869 * Try next offsets, in case this match is 870 * in the middle of a string. 871 */ 872 for (k = i + 1 ; k < NOFFSETS; k++) { 873 size_t no; 874 int adjust = 1; 875 if (prpsoffsets(k) >= prpsoffsets(i)) 876 continue; 877 for (no = doff + prpsoffsets(k); 878 no < doff + prpsoffsets(i); no++) 879 adjust = adjust 880 && isprint(nbuf[no]); 881 if (adjust) 882 i = k; 883 } 884 885 cname = (unsigned char *) 886 &nbuf[doff + prpsoffsets(i)]; 887 for (cp = cname; cp < nbuf + size && *cp 888 && isprint(*cp); cp++) 889 continue; 890 /* 891 * Linux apparently appends a space at the end 892 * of the command line: remove it. 893 */ 894 while (cp > cname && isspace(cp[-1])) 895 cp--; 896 if (file_printf(ms, ", from '%.*s'", 897 (int)(cp - cname), cname) == -1) 898 return 1; 899 *flags |= FLAGS_DID_CORE; 900 return 1; 901 902 tryanother: 903 ; 904 } 905 } 906 break; 907 } 908#endif 909 return 0; 910} 911 912private off_t 913get_offset_from_virtaddr(struct magic_set *ms, int swap, int clazz, int fd, 914 off_t off, int num, off_t fsize, uint64_t virtaddr) 915{ 916 Elf32_Phdr ph32; 917 Elf64_Phdr ph64; 918 919 /* 920 * Loop through all the program headers and find the header with 921 * virtual address in which the "virtaddr" belongs to. 922 */ 923 for ( ; num; num--) { 924 if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) { 925 file_badread(ms); 926 return -1; 927 } 928 off += xph_sizeof; 929 930 if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 931 /* Perhaps warn here */ 932 continue; 933 } 934 935 if (virtaddr >= xph_vaddr && virtaddr < xph_vaddr + xph_filesz) 936 return xph_offset + (virtaddr - xph_vaddr); 937 } 938 return 0; 939} 940 941private size_t 942get_string_on_virtaddr(struct magic_set *ms, 943 int swap, int clazz, int fd, off_t ph_off, int ph_num, 944 off_t fsize, uint64_t virtaddr, char *buf, ssize_t buflen) 945{ 946 char *bptr; 947 off_t offset; 948 949 if (buflen == 0) 950 return 0; 951 952 offset = get_offset_from_virtaddr(ms, swap, clazz, fd, ph_off, ph_num, 953 fsize, virtaddr); 954 if (offset < 0 || 955 (buflen = pread(fd, buf, CAST(size_t, buflen), offset)) <= 0) { 956 file_badread(ms); 957 return 0; 958 } 959 960 buf[buflen - 1] = '\0'; 961 962 /* We expect only printable characters, so return if buffer contains 963 * non-printable character before the '\0' or just '\0'. */ 964 for (bptr = buf; *bptr && isprint((unsigned char)*bptr); bptr++) 965 continue; 966 if (*bptr != '\0') 967 return 0; 968 969 return bptr - buf; 970} 971 972 973/*ARGSUSED*/ 974private int 975do_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, 976 int swap, uint32_t namesz __attribute__((__unused__)), 977 uint32_t descsz __attribute__((__unused__)), 978 size_t noff __attribute__((__unused__)), size_t doff, 979 int *flags, size_t size __attribute__((__unused__)), int clazz, 980 int fd, off_t ph_off, int ph_num, off_t fsize) 981{ 982#ifdef ELFCORE 983 Aux32Info auxv32; 984 Aux64Info auxv64; 985 size_t elsize = xauxv_sizeof; 986 const char *tag; 987 int is_string; 988 size_t nval; 989 990 if ((*flags & (FLAGS_IS_CORE|FLAGS_DID_CORE_STYLE)) != 991 (FLAGS_IS_CORE|FLAGS_DID_CORE_STYLE)) 992 return 0; 993 994 switch (*flags & FLAGS_CORE_STYLE) { 995 case OS_STYLE_SVR4: 996 if (type != NT_AUXV) 997 return 0; 998 break; 999#ifdef notyet 1000 case OS_STYLE_NETBSD: 1001 if (type != NT_NETBSD_CORE_AUXV) 1002 return 0; 1003 break; 1004 case OS_STYLE_FREEBSD: 1005 if (type != NT_FREEBSD_PROCSTAT_AUXV) 1006 return 0; 1007 break; 1008#endif 1009 default: 1010 return 0; 1011 } 1012 1013 *flags |= FLAGS_DID_AUXV; 1014 1015 nval = 0; 1016 for (size_t off = 0; off + elsize <= descsz; off += elsize) { 1017 memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof); 1018 /* Limit processing to 50 vector entries to prevent DoS */ 1019 if (nval++ >= 50) { 1020 file_error(ms, 0, "Too many ELF Auxv elements"); 1021 return 1; 1022 } 1023 1024 switch(xauxv_type) { 1025 case AT_LINUX_EXECFN: 1026 is_string = 1; 1027 tag = "execfn"; 1028 break; 1029 case AT_LINUX_PLATFORM: 1030 is_string = 1; 1031 tag = "platform"; 1032 break; 1033 case AT_LINUX_UID: 1034 is_string = 0; 1035 tag = "real uid"; 1036 break; 1037 case AT_LINUX_GID: 1038 is_string = 0; 1039 tag = "real gid"; 1040 break; 1041 case AT_LINUX_EUID: 1042 is_string = 0; 1043 tag = "effective uid"; 1044 break; 1045 case AT_LINUX_EGID: 1046 is_string = 0; 1047 tag = "effective gid"; 1048 break; 1049 default: 1050 is_string = 0; 1051 tag = NULL; 1052 break; 1053 } 1054 1055 if (tag == NULL) 1056 continue; 1057 1058 if (is_string) { 1059 char buf[256]; 1060 ssize_t buflen; 1061 buflen = get_string_on_virtaddr(ms, swap, clazz, fd, 1062 ph_off, ph_num, fsize, xauxv_val, buf, sizeof(buf)); 1063 1064 if (buflen == 0) 1065 continue; 1066 1067 if (file_printf(ms, ", %s: '%s'", tag, buf) == -1) 1068 return 0; 1069 } else { 1070 if (file_printf(ms, ", %s: %d", tag, (int) xauxv_val) 1071 == -1) 1072 return 0; 1073 } 1074 } 1075 return 1; 1076#else 1077 return 0; 1078#endif 1079} 1080 1081private size_t 1082dodynamic(struct magic_set *ms, void *vbuf, size_t offset, size_t size, 1083 int clazz, int swap) 1084{ 1085 Elf32_Dyn dh32; 1086 Elf64_Dyn dh64; 1087 unsigned char *dbuf = CAST(unsigned char *, vbuf); 1088 1089 if (xdh_sizeof + offset > size) { 1090 /* 1091 * We're out of note headers. 1092 */ 1093 return xdh_sizeof + offset; 1094 } 1095 1096 memcpy(xdh_addr, &dbuf[offset], xdh_sizeof); 1097 offset += xdh_sizeof; 1098 1099 switch (xdh_tag) { 1100 case DT_FLAGS_1: 1101 if (xdh_val == DF_1_PIE) 1102 ms->mode |= 0111; 1103 else 1104 ms->mode &= ~0111; 1105 break; 1106 default: 1107 break; 1108 } 1109 return offset; 1110} 1111 1112 1113private size_t 1114donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, 1115 int clazz, int swap, size_t align, int *flags, uint16_t *notecount, 1116 int fd, off_t ph_off, int ph_num, off_t fsize) 1117{ 1118 Elf32_Nhdr nh32; 1119 Elf64_Nhdr nh64; 1120 size_t noff, doff; 1121 uint32_t namesz, descsz; 1122 unsigned char *nbuf = CAST(unsigned char *, vbuf); 1123 1124 if (*notecount == 0) 1125 return 0; 1126 --*notecount; 1127 1128 if (xnh_sizeof + offset > size) { 1129 /* 1130 * We're out of note headers. 1131 */ 1132 return xnh_sizeof + offset; 1133 } 1134 1135 memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); 1136 offset += xnh_sizeof; 1137 1138 namesz = xnh_namesz; 1139 descsz = xnh_descsz; 1140 1141 if ((namesz == 0) && (descsz == 0)) { 1142 /* 1143 * We're out of note headers. 1144 */ 1145 return (offset >= size) ? offset : size; 1146 } 1147 1148 if (namesz & 0x80000000) { 1149 if (file_printf(ms, ", bad note name size %#lx", 1150 CAST(unsigned long, namesz)) == -1) 1151 return 0; 1152 return 0; 1153 } 1154 1155 if (descsz & 0x80000000) { 1156 if (file_printf(ms, ", bad note description size %#lx", 1157 CAST(unsigned long, descsz)) == -1) 1158 return 0; 1159 return 0; 1160 } 1161 1162 noff = offset; 1163 doff = ELF_ALIGN(offset + namesz); 1164 1165 if (offset + namesz > size) { 1166 /* 1167 * We're past the end of the buffer. 1168 */ 1169 return doff; 1170 } 1171 1172 offset = ELF_ALIGN(doff + descsz); 1173 if (doff + descsz > size) { 1174 /* 1175 * We're past the end of the buffer. 1176 */ 1177 return (offset >= size) ? offset : size; 1178 } 1179 1180 1181 if ((*flags & FLAGS_DID_OS_NOTE) == 0) { 1182 if (do_os_note(ms, nbuf, xnh_type, swap, 1183 namesz, descsz, noff, doff, flags)) 1184 return offset; 1185 } 1186 1187 if ((*flags & FLAGS_DID_BUILD_ID) == 0) { 1188 if (do_bid_note(ms, nbuf, xnh_type, swap, 1189 namesz, descsz, noff, doff, flags)) 1190 return offset; 1191 } 1192 1193 if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) { 1194 if (do_pax_note(ms, nbuf, xnh_type, swap, 1195 namesz, descsz, noff, doff, flags)) 1196 return offset; 1197 } 1198 1199 if ((*flags & FLAGS_DID_CORE) == 0) { 1200 if (do_core_note(ms, nbuf, xnh_type, swap, 1201 namesz, descsz, noff, doff, flags, size, clazz)) 1202 return offset; 1203 } 1204 1205 if ((*flags & FLAGS_DID_AUXV) == 0) { 1206 if (do_auxv_note(ms, nbuf, xnh_type, swap, 1207 namesz, descsz, noff, doff, flags, size, clazz, 1208 fd, ph_off, ph_num, fsize)) 1209 return offset; 1210 } 1211 1212 if (namesz == 7 && strcmp(RCAST(char *, &nbuf[noff]), "NetBSD") == 0) { 1213 int descw, flag; 1214 const char *str, *tag; 1215 if (descsz > 100) 1216 descsz = 100; 1217 switch (xnh_type) { 1218 case NT_NETBSD_VERSION: 1219 return offset; 1220 case NT_NETBSD_MARCH: 1221 flag = FLAGS_DID_NETBSD_MARCH; 1222 tag = "compiled for"; 1223 break; 1224 case NT_NETBSD_CMODEL: 1225 flag = FLAGS_DID_NETBSD_CMODEL; 1226 tag = "compiler model"; 1227 break; 1228 case NT_NETBSD_EMULATION: 1229 flag = FLAGS_DID_NETBSD_EMULATION; 1230 tag = "emulation:"; 1231 break; 1232 default: 1233 if (*flags & FLAGS_DID_NETBSD_UNKNOWN) 1234 return offset; 1235 *flags |= FLAGS_DID_NETBSD_UNKNOWN; 1236 if (file_printf(ms, ", note=%u", xnh_type) == -1) 1237 return offset; 1238 return offset; 1239 } 1240 1241 if (*flags & flag) 1242 return offset; 1243 str = RCAST(const char *, &nbuf[doff]); 1244 descw = CAST(int, descsz); 1245 *flags |= flag; 1246 file_printf(ms, ", %s: %.*s", tag, descw, str); 1247 return offset; 1248 } 1249 1250 return offset; 1251} 1252 1253/* SunOS 5.x hardware capability descriptions */ 1254typedef struct cap_desc { 1255 uint64_t cd_mask; 1256 const char *cd_name; 1257} cap_desc_t; 1258 1259static const cap_desc_t cap_desc_sparc[] = { 1260 { AV_SPARC_MUL32, "MUL32" }, 1261 { AV_SPARC_DIV32, "DIV32" }, 1262 { AV_SPARC_FSMULD, "FSMULD" }, 1263 { AV_SPARC_V8PLUS, "V8PLUS" }, 1264 { AV_SPARC_POPC, "POPC" }, 1265 { AV_SPARC_VIS, "VIS" }, 1266 { AV_SPARC_VIS2, "VIS2" }, 1267 { AV_SPARC_ASI_BLK_INIT, "ASI_BLK_INIT" }, 1268 { AV_SPARC_FMAF, "FMAF" }, 1269 { AV_SPARC_FJFMAU, "FJFMAU" }, 1270 { AV_SPARC_IMA, "IMA" }, 1271 { 0, NULL } 1272}; 1273 1274static const cap_desc_t cap_desc_386[] = { 1275 { AV_386_FPU, "FPU" }, 1276 { AV_386_TSC, "TSC" }, 1277 { AV_386_CX8, "CX8" }, 1278 { AV_386_SEP, "SEP" }, 1279 { AV_386_AMD_SYSC, "AMD_SYSC" }, 1280 { AV_386_CMOV, "CMOV" }, 1281 { AV_386_MMX, "MMX" }, 1282 { AV_386_AMD_MMX, "AMD_MMX" }, 1283 { AV_386_AMD_3DNow, "AMD_3DNow" }, 1284 { AV_386_AMD_3DNowx, "AMD_3DNowx" }, 1285 { AV_386_FXSR, "FXSR" }, 1286 { AV_386_SSE, "SSE" }, 1287 { AV_386_SSE2, "SSE2" }, 1288 { AV_386_PAUSE, "PAUSE" }, 1289 { AV_386_SSE3, "SSE3" }, 1290 { AV_386_MON, "MON" }, 1291 { AV_386_CX16, "CX16" }, 1292 { AV_386_AHF, "AHF" }, 1293 { AV_386_TSCP, "TSCP" }, 1294 { AV_386_AMD_SSE4A, "AMD_SSE4A" }, 1295 { AV_386_POPCNT, "POPCNT" }, 1296 { AV_386_AMD_LZCNT, "AMD_LZCNT" }, 1297 { AV_386_SSSE3, "SSSE3" }, 1298 { AV_386_SSE4_1, "SSE4.1" }, 1299 { AV_386_SSE4_2, "SSE4.2" }, 1300 { 0, NULL } 1301}; 1302 1303private int 1304doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, 1305 size_t size, off_t fsize, int mach, int strtab, int *flags, 1306 uint16_t *notecount) 1307{ 1308 Elf32_Shdr sh32; 1309 Elf64_Shdr sh64; 1310 int stripped = 1, has_debug_info = 0; 1311 size_t nbadcap = 0; 1312 void *nbuf; 1313 off_t noff, coff, name_off; 1314 uint64_t cap_hw1 = 0; /* SunOS 5.x hardware capabilities */ 1315 uint64_t cap_sf1 = 0; /* SunOS 5.x software capabilities */ 1316 char name[50]; 1317 ssize_t namesize; 1318 1319 if (num == 0) { 1320 if (file_printf(ms, ", no section header") == -1) 1321 return -1; 1322 return 0; 1323 } 1324 if (size != xsh_sizeof) { 1325 if (file_printf(ms, ", corrupted section header size") == -1) 1326 return -1; 1327 return 0; 1328 } 1329 1330 /* Read offset of name section to be able to read section names later */ 1331 if (pread(fd, xsh_addr, xsh_sizeof, CAST(off_t, (off + size * strtab))) 1332 < CAST(ssize_t, xsh_sizeof)) { 1333 if (file_printf(ms, ", missing section headers") == -1) 1334 return -1; 1335 return 0; 1336 } 1337 name_off = xsh_offset; 1338 1339 for ( ; num; num--) { 1340 /* Read the name of this section. */ 1341 if ((namesize = pread(fd, name, sizeof(name) - 1, 1342 name_off + xsh_name)) == -1) { 1343 file_badread(ms); 1344 return -1; 1345 } 1346 name[namesize] = '\0'; 1347 if (strcmp(name, ".debug_info") == 0) { 1348 has_debug_info = 1; 1349 stripped = 0; 1350 } 1351 1352 if (pread(fd, xsh_addr, xsh_sizeof, off) < 1353 CAST(ssize_t, xsh_sizeof)) { 1354 file_badread(ms); 1355 return -1; 1356 } 1357 off += size; 1358 1359 /* Things we can determine before we seek */ 1360 switch (xsh_type) { 1361 case SHT_SYMTAB: 1362#if 0 1363 case SHT_DYNSYM: 1364#endif 1365 stripped = 0; 1366 break; 1367 default: 1368 if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) { 1369 /* Perhaps warn here */ 1370 continue; 1371 } 1372 break; 1373 } 1374 1375 1376 /* Things we can determine when we seek */ 1377 switch (xsh_type) { 1378 case SHT_NOTE: 1379 if (CAST(uintmax_t, (xsh_size + xsh_offset)) > 1380 CAST(uintmax_t, fsize)) { 1381 if (file_printf(ms, 1382 ", note offset/size %#" INTMAX_T_FORMAT 1383 "x+%#" INTMAX_T_FORMAT "x exceeds" 1384 " file size %#" INTMAX_T_FORMAT "x", 1385 CAST(uintmax_t, xsh_offset), 1386 CAST(uintmax_t, xsh_size), 1387 CAST(uintmax_t, fsize)) == -1) 1388 return -1; 1389 return 0; 1390 } 1391 if ((nbuf = malloc(xsh_size)) == NULL) { 1392 file_error(ms, errno, "Cannot allocate memory" 1393 " for note"); 1394 return -1; 1395 } 1396 if (pread(fd, nbuf, xsh_size, xsh_offset) < 1397 CAST(ssize_t, xsh_size)) { 1398 file_badread(ms); 1399 free(nbuf); 1400 return -1; 1401 } 1402 1403 noff = 0; 1404 for (;;) { 1405 if (noff >= CAST(off_t, xsh_size)) 1406 break; 1407 noff = donote(ms, nbuf, CAST(size_t, noff), 1408 xsh_size, clazz, swap, 4, flags, notecount, 1409 fd, 0, 0, 0); 1410 if (noff == 0) 1411 break; 1412 } 1413 free(nbuf); 1414 break; 1415 case SHT_SUNW_cap: 1416 switch (mach) { 1417 case EM_SPARC: 1418 case EM_SPARCV9: 1419 case EM_IA_64: 1420 case EM_386: 1421 case EM_AMD64: 1422 break; 1423 default: 1424 goto skip; 1425 } 1426 1427 if (nbadcap > 5) 1428 break; 1429 if (lseek(fd, xsh_offset, SEEK_SET) 1430 == CAST(off_t, -1)) { 1431 file_badseek(ms); 1432 return -1; 1433 } 1434 coff = 0; 1435 for (;;) { 1436 Elf32_Cap cap32; 1437 Elf64_Cap cap64; 1438 char cbuf[/*CONSTCOND*/ 1439 MAX(sizeof(cap32), sizeof(cap64))]; 1440 if ((coff += xcap_sizeof) > 1441 CAST(off_t, xsh_size)) 1442 break; 1443 if (read(fd, cbuf, CAST(size_t, xcap_sizeof)) != 1444 CAST(ssize_t, xcap_sizeof)) { 1445 file_badread(ms); 1446 return -1; 1447 } 1448 if (cbuf[0] == 'A') { 1449#ifdef notyet 1450 char *p = cbuf + 1; 1451 uint32_t len, tag; 1452 memcpy(&len, p, sizeof(len)); 1453 p += 4; 1454 len = getu32(swap, len); 1455 if (memcmp("gnu", p, 3) != 0) { 1456 if (file_printf(ms, 1457 ", unknown capability %.3s", p) 1458 == -1) 1459 return -1; 1460 break; 1461 } 1462 p += strlen(p) + 1; 1463 tag = *p++; 1464 memcpy(&len, p, sizeof(len)); 1465 p += 4; 1466 len = getu32(swap, len); 1467 if (tag != 1) { 1468 if (file_printf(ms, ", unknown gnu" 1469 " capability tag %d", tag) 1470 == -1) 1471 return -1; 1472 break; 1473 } 1474 // gnu attributes 1475#endif 1476 break; 1477 } 1478 memcpy(xcap_addr, cbuf, xcap_sizeof); 1479 switch (xcap_tag) { 1480 case CA_SUNW_NULL: 1481 break; 1482 case CA_SUNW_HW_1: 1483 cap_hw1 |= xcap_val; 1484 break; 1485 case CA_SUNW_SF_1: 1486 cap_sf1 |= xcap_val; 1487 break; 1488 default: 1489 if (file_printf(ms, 1490 ", with unknown capability " 1491 "%#" INT64_T_FORMAT "x = %#" 1492 INT64_T_FORMAT "x", 1493 CAST(unsigned long long, xcap_tag), 1494 CAST(unsigned long long, xcap_val)) 1495 == -1) 1496 return -1; 1497 if (nbadcap++ > 2) 1498 coff = xsh_size; 1499 break; 1500 } 1501 } 1502 /*FALLTHROUGH*/ 1503 skip: 1504 default: 1505 break; 1506 } 1507 } 1508 1509 if (has_debug_info) { 1510 if (file_printf(ms, ", with debug_info") == -1) 1511 return -1; 1512 } 1513 if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1) 1514 return -1; 1515 if (cap_hw1) { 1516 const cap_desc_t *cdp; 1517 switch (mach) { 1518 case EM_SPARC: 1519 case EM_SPARC32PLUS: 1520 case EM_SPARCV9: 1521 cdp = cap_desc_sparc; 1522 break; 1523 case EM_386: 1524 case EM_IA_64: 1525 case EM_AMD64: 1526 cdp = cap_desc_386; 1527 break; 1528 default: 1529 cdp = NULL; 1530 break; 1531 } 1532 if (file_printf(ms, ", uses") == -1) 1533 return -1; 1534 if (cdp) { 1535 while (cdp->cd_name) { 1536 if (cap_hw1 & cdp->cd_mask) { 1537 if (file_printf(ms, 1538 " %s", cdp->cd_name) == -1) 1539 return -1; 1540 cap_hw1 &= ~cdp->cd_mask; 1541 } 1542 ++cdp; 1543 } 1544 if (cap_hw1) 1545 if (file_printf(ms, 1546 " unknown hardware capability %#" 1547 INT64_T_FORMAT "x", 1548 CAST(unsigned long long, cap_hw1)) == -1) 1549 return -1; 1550 } else { 1551 if (file_printf(ms, 1552 " hardware capability %#" INT64_T_FORMAT "x", 1553 CAST(unsigned long long, cap_hw1)) == -1) 1554 return -1; 1555 } 1556 } 1557 if (cap_sf1) { 1558 if (cap_sf1 & SF1_SUNW_FPUSED) { 1559 if (file_printf(ms, 1560 (cap_sf1 & SF1_SUNW_FPKNWN) 1561 ? ", uses frame pointer" 1562 : ", not known to use frame pointer") == -1) 1563 return -1; 1564 } 1565 cap_sf1 &= ~SF1_SUNW_MASK; 1566 if (cap_sf1) 1567 if (file_printf(ms, 1568 ", with unknown software capability %#" 1569 INT64_T_FORMAT "x", 1570 CAST(unsigned long long, cap_sf1)) == -1) 1571 return -1; 1572 } 1573 return 0; 1574} 1575 1576/* 1577 * Look through the program headers of an executable image, searching 1578 * for a PT_INTERP section; if one is found, it's dynamically linked, 1579 * otherwise it's statically linked. 1580 */ 1581private int 1582dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 1583 int num, size_t size, off_t fsize, int sh_num, int *flags, 1584 uint16_t *notecount) 1585{ 1586 Elf32_Phdr ph32; 1587 Elf64_Phdr ph64; 1588 const char *linking_style = "statically"; 1589 unsigned char nbuf[BUFSIZ]; 1590 char ibuf[BUFSIZ]; 1591 char interp[BUFSIZ]; 1592 ssize_t bufsize; 1593 size_t offset, align, len; 1594 1595 if (num == 0) { 1596 if (file_printf(ms, ", no program header") == -1) 1597 return -1; 1598 return 0; 1599 } 1600 if (size != xph_sizeof) { 1601 if (file_printf(ms, ", corrupted program header size") == -1) 1602 return -1; 1603 return 0; 1604 } 1605 1606 interp[0] = '\0'; 1607 for ( ; num; num--) { 1608 int doread; 1609 if (pread(fd, xph_addr, xph_sizeof, off) < 1610 CAST(ssize_t, xph_sizeof)) { 1611 file_badread(ms); 1612 return -1; 1613 } 1614 1615 off += size; 1616 bufsize = 0; 1617 align = 4; 1618 1619 /* Things we can determine before we seek */ 1620 switch (xph_type) { 1621 case PT_DYNAMIC: 1622 linking_style = "dynamically"; 1623 doread = 1; 1624 break; 1625 case PT_NOTE: 1626 if (sh_num) /* Did this through section headers */ 1627 continue; 1628 if (((align = xph_align) & 0x80000000UL) != 0 || 1629 align < 4) { 1630 if (file_printf(ms, 1631 ", invalid note alignment %#lx", 1632 CAST(unsigned long, align)) == -1) 1633 return -1; 1634 align = 4; 1635 } 1636 /*FALLTHROUGH*/ 1637 case PT_INTERP: 1638 doread = 1; 1639 break; 1640 default: 1641 doread = 0; 1642 if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { 1643 /* Maybe warn here? */ 1644 continue; 1645 } 1646 break; 1647 } 1648 1649 if (doread) { 1650 len = xph_filesz < sizeof(nbuf) ? xph_filesz 1651 : sizeof(nbuf); 1652 bufsize = pread(fd, nbuf, len, xph_offset); 1653 if (bufsize == -1) { 1654 file_badread(ms); 1655 return -1; 1656 } 1657 } else 1658 len = 0; 1659 1660 /* Things we can determine when we seek */ 1661 switch (xph_type) { 1662 case PT_DYNAMIC: 1663 offset = 0; 1664 for (;;) { 1665 if (offset >= (size_t)bufsize) 1666 break; 1667 offset = dodynamic(ms, nbuf, offset, 1668 CAST(size_t, bufsize), clazz, swap); 1669 if (offset == 0) 1670 break; 1671 } 1672 break; 1673 1674 case PT_INTERP: 1675 if (bufsize && nbuf[0]) { 1676 nbuf[bufsize - 1] = '\0'; 1677 memcpy(interp, nbuf, (size_t)bufsize); 1678 } else 1679 strlcpy(interp, "*empty*", sizeof(interp)); 1680 break; 1681 case PT_NOTE: 1682 /* 1683 * This is a PT_NOTE section; loop through all the notes 1684 * in the section. 1685 */ 1686 offset = 0; 1687 for (;;) { 1688 if (offset >= (size_t)bufsize) 1689 break; 1690 offset = donote(ms, nbuf, offset, 1691 CAST(size_t, bufsize), clazz, swap, align, 1692 flags, notecount, fd, 0, 0, 0); 1693 if (offset == 0) 1694 break; 1695 } 1696 break; 1697 default: 1698 break; 1699 } 1700 } 1701 if (file_printf(ms, ", %s linked", linking_style) 1702 == -1) 1703 return -1; 1704 if (interp[0]) 1705 if (file_printf(ms, ", interpreter %s", 1706 file_printable(ibuf, sizeof(ibuf), interp)) == -1) 1707 return -1; 1708 return 0; 1709} 1710 1711 1712protected int 1713file_tryelf(struct magic_set *ms, const struct buffer *b) 1714{ 1715 int fd = b->fd; 1716 const unsigned char *buf = CAST(const unsigned char *, b->fbuf); 1717 size_t nbytes = b->flen; 1718 union { 1719 int32_t l; 1720 char c[sizeof(int32_t)]; 1721 } u; 1722 int clazz; 1723 int swap; 1724 struct stat st; 1725 off_t fsize; 1726 int flags = 0; 1727 Elf32_Ehdr elf32hdr; 1728 Elf64_Ehdr elf64hdr; 1729 uint16_t type, phnum, shnum, notecount; 1730 1731 if (ms->flags & (MAGIC_MIME|MAGIC_APPLE|MAGIC_EXTENSION)) 1732 return 0; 1733 /* 1734 * ELF executables have multiple section headers in arbitrary 1735 * file locations and thus file(1) cannot determine it from easily. 1736 * Instead we traverse thru all section headers until a symbol table 1737 * one is found or else the binary is stripped. 1738 * Return immediately if it's not ELF (so we avoid pipe2file unless 1739 * needed). 1740 */ 1741 if (buf[EI_MAG0] != ELFMAG0 1742 || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) 1743 || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) 1744 return 0; 1745 1746 /* 1747 * If we cannot seek, it must be a pipe, socket or fifo. 1748 */ 1749 if((lseek(fd, CAST(off_t, 0), SEEK_SET) == CAST(off_t, -1)) 1750 && (errno == ESPIPE)) 1751 fd = file_pipe2file(ms, fd, buf, nbytes); 1752 1753 if (fd == -1 || fstat(fd, &st) == -1) { 1754 file_badread(ms); 1755 return -1; 1756 } 1757 if (S_ISREG(st.st_mode) || st.st_size != 0) 1758 fsize = st.st_size; 1759 else 1760 fsize = SIZE_UNKNOWN; 1761 1762 clazz = buf[EI_CLASS]; 1763 1764 switch (clazz) { 1765 case ELFCLASS32: 1766#undef elf_getu 1767#define elf_getu(a, b) elf_getu32(a, b) 1768#undef elfhdr 1769#define elfhdr elf32hdr 1770#include "elfclass.h" 1771 case ELFCLASS64: 1772#undef elf_getu 1773#define elf_getu(a, b) elf_getu64(a, b) 1774#undef elfhdr 1775#define elfhdr elf64hdr 1776#include "elfclass.h" 1777 default: 1778 if (file_printf(ms, ", unknown class %d", clazz) == -1) 1779 return -1; 1780 break; 1781 } 1782 return 0; 1783} 1784#endif 1785