readelf.c revision 1.1.1.3
1/* $NetBSD: readelf.c,v 1.1.1.3 2011/09/16 20:37:38 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.90 2011/08/23 08:01:12 christos Exp $") 34#else 35__RCSID("$NetBSD: readelf.c,v 1.1.1.3 2011/09/16 20:37:38 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 *); 53#endif 54private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t, 55 off_t, int *, int); 56private int doshn(struct magic_set *, int, int, int, off_t, int, size_t, 57 off_t, int *, int); 58private size_t donote(struct magic_set *, void *, size_t, size_t, int, 59 int, size_t, int *); 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 69private uint16_t 70getu16(int swap, uint16_t value) 71{ 72 union { 73 uint16_t ui; 74 char c[2]; 75 } retval, tmpval; 76 77 if (swap) { 78 tmpval.ui = value; 79 80 retval.c[0] = tmpval.c[1]; 81 retval.c[1] = tmpval.c[0]; 82 83 return retval.ui; 84 } else 85 return value; 86} 87 88private uint32_t 89getu32(int swap, uint32_t value) 90{ 91 union { 92 uint32_t ui; 93 char c[4]; 94 } retval, tmpval; 95 96 if (swap) { 97 tmpval.ui = value; 98 99 retval.c[0] = tmpval.c[3]; 100 retval.c[1] = tmpval.c[2]; 101 retval.c[2] = tmpval.c[1]; 102 retval.c[3] = tmpval.c[0]; 103 104 return retval.ui; 105 } else 106 return value; 107} 108 109private uint64_t 110getu64(int swap, uint64_t value) 111{ 112 union { 113 uint64_t ui; 114 char c[8]; 115 } retval, tmpval; 116 117 if (swap) { 118 tmpval.ui = value; 119 120 retval.c[0] = tmpval.c[7]; 121 retval.c[1] = tmpval.c[6]; 122 retval.c[2] = tmpval.c[5]; 123 retval.c[3] = tmpval.c[4]; 124 retval.c[4] = tmpval.c[3]; 125 retval.c[5] = tmpval.c[2]; 126 retval.c[6] = tmpval.c[1]; 127 retval.c[7] = tmpval.c[0]; 128 129 return retval.ui; 130 } else 131 return value; 132} 133 134#define elf_getu16(swap, value) getu16(swap, value) 135#define elf_getu32(swap, value) getu32(swap, value) 136#ifdef USE_ARRAY_FOR_64BIT_TYPES 137# define elf_getu64(swap, array) \ 138 ((swap ? ((uint64_t)elf_getu32(swap, array[0])) << 32 : elf_getu32(swap, array[0])) + \ 139 (swap ? elf_getu32(swap, array[1]) : ((uint64_t)elf_getu32(swap, array[1]) << 32))) 140#else 141# define elf_getu64(swap, value) getu64(swap, value) 142#endif 143 144#define xsh_addr (clazz == ELFCLASS32 \ 145 ? (void *) &sh32 \ 146 : (void *) &sh64) 147#define xsh_sizeof (clazz == ELFCLASS32 \ 148 ? sizeof sh32 \ 149 : sizeof sh64) 150#define xsh_size (clazz == ELFCLASS32 \ 151 ? elf_getu32(swap, sh32.sh_size) \ 152 : elf_getu64(swap, sh64.sh_size)) 153#define xsh_offset (off_t)(clazz == ELFCLASS32 \ 154 ? elf_getu32(swap, sh32.sh_offset) \ 155 : elf_getu64(swap, sh64.sh_offset)) 156#define xsh_type (clazz == ELFCLASS32 \ 157 ? elf_getu32(swap, sh32.sh_type) \ 158 : elf_getu32(swap, sh64.sh_type)) 159#define xph_addr (clazz == ELFCLASS32 \ 160 ? (void *) &ph32 \ 161 : (void *) &ph64) 162#define xph_sizeof (clazz == ELFCLASS32 \ 163 ? sizeof ph32 \ 164 : sizeof ph64) 165#define xph_type (clazz == ELFCLASS32 \ 166 ? elf_getu32(swap, ph32.p_type) \ 167 : elf_getu32(swap, ph64.p_type)) 168#define xph_offset (off_t)(clazz == ELFCLASS32 \ 169 ? elf_getu32(swap, ph32.p_offset) \ 170 : elf_getu64(swap, ph64.p_offset)) 171#define xph_align (size_t)((clazz == ELFCLASS32 \ 172 ? (off_t) (ph32.p_align ? \ 173 elf_getu32(swap, ph32.p_align) : 4) \ 174 : (off_t) (ph64.p_align ? \ 175 elf_getu64(swap, ph64.p_align) : 4))) 176#define xph_filesz (size_t)((clazz == ELFCLASS32 \ 177 ? elf_getu32(swap, ph32.p_filesz) \ 178 : elf_getu64(swap, ph64.p_filesz))) 179#define xnh_addr (clazz == ELFCLASS32 \ 180 ? (void *) &nh32 \ 181 : (void *) &nh64) 182#define xph_memsz (size_t)((clazz == ELFCLASS32 \ 183 ? elf_getu32(swap, ph32.p_memsz) \ 184 : elf_getu64(swap, ph64.p_memsz))) 185#define xnh_sizeof (clazz == ELFCLASS32 \ 186 ? sizeof nh32 \ 187 : sizeof nh64) 188#define xnh_type (clazz == ELFCLASS32 \ 189 ? elf_getu32(swap, nh32.n_type) \ 190 : elf_getu32(swap, nh64.n_type)) 191#define xnh_namesz (clazz == ELFCLASS32 \ 192 ? elf_getu32(swap, nh32.n_namesz) \ 193 : elf_getu32(swap, nh64.n_namesz)) 194#define xnh_descsz (clazz == ELFCLASS32 \ 195 ? elf_getu32(swap, nh32.n_descsz) \ 196 : elf_getu32(swap, nh64.n_descsz)) 197#define prpsoffsets(i) (clazz == ELFCLASS32 \ 198 ? prpsoffsets32[i] \ 199 : prpsoffsets64[i]) 200#define xcap_addr (clazz == ELFCLASS32 \ 201 ? (void *) &cap32 \ 202 : (void *) &cap64) 203#define xcap_sizeof (clazz == ELFCLASS32 \ 204 ? sizeof cap32 \ 205 : sizeof cap64) 206#define xcap_tag (clazz == ELFCLASS32 \ 207 ? elf_getu32(swap, cap32.c_tag) \ 208 : elf_getu64(swap, cap64.c_tag)) 209#define xcap_val (clazz == ELFCLASS32 \ 210 ? elf_getu32(swap, cap32.c_un.c_val) \ 211 : elf_getu64(swap, cap64.c_un.c_val)) 212 213#ifdef ELFCORE 214/* 215 * Try larger offsets first to avoid false matches 216 * from earlier data that happen to look like strings. 217 */ 218static const size_t prpsoffsets32[] = { 219#ifdef USE_NT_PSINFO 220 104, /* SunOS 5.x (command line) */ 221 88, /* SunOS 5.x (short name) */ 222#endif /* USE_NT_PSINFO */ 223 224 100, /* SunOS 5.x (command line) */ 225 84, /* SunOS 5.x (short name) */ 226 227 44, /* Linux (command line) */ 228 28, /* Linux 2.0.36 (short name) */ 229 230 8, /* FreeBSD */ 231}; 232 233static const size_t prpsoffsets64[] = { 234#ifdef USE_NT_PSINFO 235 152, /* SunOS 5.x (command line) */ 236 136, /* SunOS 5.x (short name) */ 237#endif /* USE_NT_PSINFO */ 238 239 136, /* SunOS 5.x, 64-bit (command line) */ 240 120, /* SunOS 5.x, 64-bit (short name) */ 241 242 56, /* Linux (command line) */ 243 40, /* Linux (tested on core from 2.4.x, short name) */ 244 245 16, /* FreeBSD, 64-bit */ 246}; 247 248#define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0]) 249#define NOFFSETS64 (sizeof prpsoffsets64 / sizeof prpsoffsets64[0]) 250 251#define NOFFSETS (clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64) 252 253/* 254 * Look through the program headers of an executable image, searching 255 * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or 256 * "FreeBSD"; if one is found, try looking in various places in its 257 * contents for a 16-character string containing only printable 258 * characters - if found, that string should be the name of the program 259 * that dropped core. Note: right after that 16-character string is, 260 * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and 261 * Linux, a longer string (80 characters, in 5.x, probably other 262 * SVR4-flavored systems, and Linux) containing the start of the 263 * command line for that program. 264 * 265 * SunOS 5.x core files contain two PT_NOTE sections, with the types 266 * NT_PRPSINFO (old) and NT_PSINFO (new). These structs contain the 267 * same info about the command name and command line, so it probably 268 * isn't worthwhile to look for NT_PSINFO, but the offsets are provided 269 * above (see USE_NT_PSINFO), in case we ever decide to do so. The 270 * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent; 271 * the SunOS 5.x file command relies on this (and prefers the latter). 272 * 273 * The signal number probably appears in a section of type NT_PRSTATUS, 274 * but that's also rather OS-dependent, in ways that are harder to 275 * dissect with heuristics, so I'm not bothering with the signal number. 276 * (I suppose the signal number could be of interest in situations where 277 * you don't have the binary of the program that dropped core; if you 278 * *do* have that binary, the debugger will probably tell you what 279 * signal it was.) 280 */ 281 282#define OS_STYLE_SVR4 0 283#define OS_STYLE_FREEBSD 1 284#define OS_STYLE_NETBSD 2 285 286private const char os_style_names[][8] = { 287 "SVR4", 288 "FreeBSD", 289 "NetBSD", 290}; 291 292#define FLAGS_DID_CORE 0x01 293#define FLAGS_DID_NOTE 0x02 294#define FLAGS_DID_BUILD_ID 0x04 295#define FLAGS_DID_CORE_STYLE 0x08 296#define FLAGS_IS_CORE 0x10 297 298private int 299dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 300 int num, size_t size, off_t fsize, int *flags) 301{ 302 Elf32_Phdr ph32; 303 Elf64_Phdr ph64; 304 size_t offset; 305 unsigned char nbuf[BUFSIZ]; 306 ssize_t bufsize; 307 308 if (size != xph_sizeof) { 309 if (file_printf(ms, ", corrupted program header size") == -1) 310 return -1; 311 return 0; 312 } 313 314 /* 315 * Loop through all the program headers. 316 */ 317 for ( ; num; num--) { 318 if (lseek(fd, off, SEEK_SET) == (off_t)-1) { 319 file_badseek(ms); 320 return -1; 321 } 322 if (read(fd, xph_addr, xph_sizeof) == -1) { 323 file_badread(ms); 324 return -1; 325 } 326 off += size; 327 328 if (xph_offset > fsize) { 329 /* Perhaps warn here */ 330 continue; 331 } 332 333 if (xph_type != PT_NOTE) 334 continue; 335 336 /* 337 * This is a PT_NOTE section; loop through all the notes 338 * in the section. 339 */ 340 if (lseek(fd, xph_offset, SEEK_SET) == (off_t)-1) { 341 file_badseek(ms); 342 return -1; 343 } 344 bufsize = read(fd, nbuf, 345 ((xph_filesz < sizeof(nbuf)) ? xph_filesz : sizeof(nbuf))); 346 if (bufsize == -1) { 347 file_badread(ms); 348 return -1; 349 } 350 offset = 0; 351 for (;;) { 352 if (offset >= (size_t)bufsize) 353 break; 354 offset = donote(ms, nbuf, offset, (size_t)bufsize, 355 clazz, swap, 4, flags); 356 if (offset == 0) 357 break; 358 359 } 360 } 361 return 0; 362} 363#endif 364 365private size_t 366donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, 367 int clazz, int swap, size_t align, int *flags) 368{ 369 Elf32_Nhdr nh32; 370 Elf64_Nhdr nh64; 371 size_t noff, doff; 372#ifdef ELFCORE 373 int os_style = -1; 374#endif 375 uint32_t namesz, descsz; 376 unsigned char *nbuf = CAST(unsigned char *, vbuf); 377 378 (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); 379 offset += xnh_sizeof; 380 381 namesz = xnh_namesz; 382 descsz = xnh_descsz; 383 if ((namesz == 0) && (descsz == 0)) { 384 /* 385 * We're out of note headers. 386 */ 387 return (offset >= size) ? offset : size; 388 } 389 390 if (namesz & 0x80000000) { 391 (void)file_printf(ms, ", bad note name size 0x%lx", 392 (unsigned long)namesz); 393 return offset; 394 } 395 396 if (descsz & 0x80000000) { 397 (void)file_printf(ms, ", bad note description size 0x%lx", 398 (unsigned long)descsz); 399 return offset; 400 } 401 402 403 noff = offset; 404 doff = ELF_ALIGN(offset + namesz); 405 406 if (offset + namesz > size) { 407 /* 408 * We're past the end of the buffer. 409 */ 410 return doff; 411 } 412 413 offset = ELF_ALIGN(doff + descsz); 414 if (doff + descsz > size) { 415 /* 416 * We're past the end of the buffer. 417 */ 418 return (offset >= size) ? offset : size; 419 } 420 421 if ((*flags & (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) == 422 (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) 423 goto core; 424 425 if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 426 xnh_type == NT_GNU_VERSION && descsz == 16) { 427 uint32_t desc[4]; 428 (void)memcpy(desc, &nbuf[doff], sizeof(desc)); 429 430 if (file_printf(ms, ", for GNU/") == -1) 431 return size; 432 switch (elf_getu32(swap, desc[0])) { 433 case GNU_OS_LINUX: 434 if (file_printf(ms, "Linux") == -1) 435 return size; 436 break; 437 case GNU_OS_HURD: 438 if (file_printf(ms, "Hurd") == -1) 439 return size; 440 break; 441 case GNU_OS_SOLARIS: 442 if (file_printf(ms, "Solaris") == -1) 443 return size; 444 break; 445 case GNU_OS_KFREEBSD: 446 if (file_printf(ms, "kFreeBSD") == -1) 447 return size; 448 break; 449 case GNU_OS_KNETBSD: 450 if (file_printf(ms, "kNetBSD") == -1) 451 return size; 452 break; 453 default: 454 if (file_printf(ms, "<unknown>") == -1) 455 return size; 456 } 457 if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]), 458 elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1) 459 return size; 460 *flags |= FLAGS_DID_NOTE; 461 return size; 462 } 463 464 if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 465 xnh_type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) { 466 uint32_t desc[5], i; 467 if (file_printf(ms, ", BuildID[%s]=0x", descsz == 16 ? "md5/uuid" : 468 "sha1") == -1) 469 return size; 470 (void)memcpy(desc, &nbuf[doff], descsz); 471 for (i = 0; i < descsz >> 2; i++) 472 if (file_printf(ms, "%.8x", desc[i]) == -1) 473 return size; 474 *flags |= FLAGS_DID_BUILD_ID; 475 } 476 477 if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 && 478 xnh_type == NT_NETBSD_VERSION && descsz == 4) { 479 uint32_t desc; 480 (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 481 desc = elf_getu32(swap, desc); 482 483 if (file_printf(ms, ", for NetBSD") == -1) 484 return size; 485 /* 486 * The version number used to be stuck as 199905, and was thus 487 * basically content-free. Newer versions of NetBSD have fixed 488 * this and now use the encoding of __NetBSD_Version__: 489 * 490 * MMmmrrpp00 491 * 492 * M = major version 493 * m = minor version 494 * r = release ["",A-Z,Z[A-Z] but numeric] 495 * p = patchlevel 496 */ 497 if (desc > 100000000U) { 498 uint32_t ver_patch = (desc / 100) % 100; 499 uint32_t ver_rel = (desc / 10000) % 100; 500 uint32_t ver_min = (desc / 1000000) % 100; 501 uint32_t ver_maj = desc / 100000000; 502 503 if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) 504 return size; 505 if (ver_rel == 0 && ver_patch != 0) { 506 if (file_printf(ms, ".%u", ver_patch) == -1) 507 return size; 508 } else if (ver_rel != 0) { 509 while (ver_rel > 26) { 510 if (file_printf(ms, "Z") == -1) 511 return size; 512 ver_rel -= 26; 513 } 514 if (file_printf(ms, "%c", 'A' + ver_rel - 1) 515 == -1) 516 return size; 517 } 518 } 519 *flags |= FLAGS_DID_NOTE; 520 return size; 521 } 522 523 if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0 && 524 xnh_type == NT_FREEBSD_VERSION && descsz == 4) { 525 uint32_t desc; 526 (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 527 desc = elf_getu32(swap, desc); 528 if (file_printf(ms, ", for FreeBSD") == -1) 529 return size; 530 531 /* 532 * Contents is __FreeBSD_version, whose relation to OS 533 * versions is defined by a huge table in the Porter's 534 * Handbook. This is the general scheme: 535 * 536 * Releases: 537 * Mmp000 (before 4.10) 538 * Mmi0p0 (before 5.0) 539 * Mmm0p0 540 * 541 * Development branches: 542 * Mmpxxx (before 4.6) 543 * Mmp1xx (before 4.10) 544 * Mmi1xx (before 5.0) 545 * M000xx (pre-M.0) 546 * Mmm1xx 547 * 548 * M = major version 549 * m = minor version 550 * i = minor version increment (491000 -> 4.10) 551 * p = patchlevel 552 * x = revision 553 * 554 * The first release of FreeBSD to use ELF by default 555 * was version 3.0. 556 */ 557 if (desc == 460002) { 558 if (file_printf(ms, " 4.6.2") == -1) 559 return size; 560 } else if (desc < 460100) { 561 if (file_printf(ms, " %d.%d", desc / 100000, 562 desc / 10000 % 10) == -1) 563 return size; 564 if (desc / 1000 % 10 > 0) 565 if (file_printf(ms, ".%d", desc / 1000 % 10) 566 == -1) 567 return size; 568 if ((desc % 1000 > 0) || (desc % 100000 == 0)) 569 if (file_printf(ms, " (%d)", desc) == -1) 570 return size; 571 } else if (desc < 500000) { 572 if (file_printf(ms, " %d.%d", desc / 100000, 573 desc / 10000 % 10 + desc / 1000 % 10) == -1) 574 return size; 575 if (desc / 100 % 10 > 0) { 576 if (file_printf(ms, " (%d)", desc) == -1) 577 return size; 578 } else if (desc / 10 % 10 > 0) { 579 if (file_printf(ms, ".%d", desc / 10 % 10) 580 == -1) 581 return size; 582 } 583 } else { 584 if (file_printf(ms, " %d.%d", desc / 100000, 585 desc / 1000 % 100) == -1) 586 return size; 587 if ((desc / 100 % 10 > 0) || 588 (desc % 100000 / 100 == 0)) { 589 if (file_printf(ms, " (%d)", desc) == -1) 590 return size; 591 } else if (desc / 10 % 10 > 0) { 592 if (file_printf(ms, ".%d", desc / 10 % 10) 593 == -1) 594 return size; 595 } 596 } 597 *flags |= FLAGS_DID_NOTE; 598 return size; 599 } 600 601 if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && 602 xnh_type == NT_OPENBSD_VERSION && descsz == 4) { 603 if (file_printf(ms, ", for OpenBSD") == -1) 604 return size; 605 /* Content of note is always 0 */ 606 *flags |= FLAGS_DID_NOTE; 607 return size; 608 } 609 610 if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 && 611 xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) { 612 uint32_t desc; 613 if (file_printf(ms, ", for DragonFly") == -1) 614 return size; 615 (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 616 desc = elf_getu32(swap, desc); 617 if (file_printf(ms, " %d.%d.%d", desc / 100000, 618 desc / 10000 % 10, desc % 10000) == -1) 619 return size; 620 *flags |= FLAGS_DID_NOTE; 621 return size; 622 } 623 624core: 625 /* 626 * Sigh. The 2.0.36 kernel in Debian 2.1, at 627 * least, doesn't correctly implement name 628 * sections, in core dumps, as specified by 629 * the "Program Linking" section of "UNIX(R) System 630 * V Release 4 Programmer's Guide: ANSI C and 631 * Programming Support Tools", because my copy 632 * clearly says "The first 'namesz' bytes in 'name' 633 * contain a *null-terminated* [emphasis mine] 634 * character representation of the entry's owner 635 * or originator", but the 2.0.36 kernel code 636 * doesn't include the terminating null in the 637 * name.... 638 */ 639 if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) || 640 (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) { 641 os_style = OS_STYLE_SVR4; 642 } 643 644 if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) { 645 os_style = OS_STYLE_FREEBSD; 646 } 647 648 if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11) 649 == 0)) { 650 os_style = OS_STYLE_NETBSD; 651 } 652 653#ifdef ELFCORE 654 if ((*flags & FLAGS_DID_CORE) != 0) 655 return size; 656 657 if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) { 658 if (file_printf(ms, ", %s-style", os_style_names[os_style]) 659 == -1) 660 return size; 661 *flags |= FLAGS_DID_CORE_STYLE; 662 } 663 664 switch (os_style) { 665 case OS_STYLE_NETBSD: 666 if (xnh_type == NT_NETBSD_CORE_PROCINFO) { 667 uint32_t signo; 668 /* 669 * Extract the program name. It is at 670 * offset 0x7c, and is up to 32-bytes, 671 * including the terminating NUL. 672 */ 673 if (file_printf(ms, ", from '%.31s'", 674 &nbuf[doff + 0x7c]) == -1) 675 return size; 676 677 /* 678 * Extract the signal number. It is at 679 * offset 0x08. 680 */ 681 (void)memcpy(&signo, &nbuf[doff + 0x08], 682 sizeof(signo)); 683 if (file_printf(ms, " (signal %u)", 684 elf_getu32(swap, signo)) == -1) 685 return size; 686 *flags |= FLAGS_DID_CORE; 687 return size; 688 } 689 break; 690 691 default: 692 if (xnh_type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) { 693 size_t i, j; 694 unsigned char c; 695 /* 696 * Extract the program name. We assume 697 * it to be 16 characters (that's what it 698 * is in SunOS 5.x and Linux). 699 * 700 * Unfortunately, it's at a different offset 701 * in various OSes, so try multiple offsets. 702 * If the characters aren't all printable, 703 * reject it. 704 */ 705 for (i = 0; i < NOFFSETS; i++) { 706 unsigned char *cname, *cp; 707 size_t reloffset = prpsoffsets(i); 708 size_t noffset = doff + reloffset; 709 size_t k; 710 for (j = 0; j < 16; j++, noffset++, 711 reloffset++) { 712 /* 713 * Make sure we're not past 714 * the end of the buffer; if 715 * we are, just give up. 716 */ 717 if (noffset >= size) 718 goto tryanother; 719 720 /* 721 * Make sure we're not past 722 * the end of the contents; 723 * if we are, this obviously 724 * isn't the right offset. 725 */ 726 if (reloffset >= descsz) 727 goto tryanother; 728 729 c = nbuf[noffset]; 730 if (c == '\0') { 731 /* 732 * A '\0' at the 733 * beginning is 734 * obviously wrong. 735 * Any other '\0' 736 * means we're done. 737 */ 738 if (j == 0) 739 goto tryanother; 740 else 741 break; 742 } else { 743 /* 744 * A nonprintable 745 * character is also 746 * wrong. 747 */ 748 if (!isprint(c) || isquote(c)) 749 goto tryanother; 750 } 751 } 752 /* 753 * Well, that worked. 754 */ 755 756 /* 757 * Try next offsets, in case this match is 758 * in the middle of a string. 759 */ 760 for (k = i + 1 ; k < NOFFSETS ; k++) { 761 size_t no; 762 int adjust = 1; 763 if (prpsoffsets(k) >= prpsoffsets(i)) 764 continue; 765 for (no = doff + prpsoffsets(k); 766 no < doff + prpsoffsets(i); no++) 767 adjust = adjust 768 && isprint(nbuf[no]); 769 if (adjust) 770 i = k; 771 } 772 773 cname = (unsigned char *) 774 &nbuf[doff + prpsoffsets(i)]; 775 for (cp = cname; *cp && isprint(*cp); cp++) 776 continue; 777 /* 778 * Linux apparently appends a space at the end 779 * of the command line: remove it. 780 */ 781 while (cp > cname && isspace(cp[-1])) 782 cp--; 783 if (file_printf(ms, ", from '%.*s'", 784 (int)(cp - cname), cname) == -1) 785 return size; 786 *flags |= FLAGS_DID_CORE; 787 return size; 788 789 tryanother: 790 ; 791 } 792 } 793 break; 794 } 795#endif 796 return offset; 797} 798 799/* SunOS 5.x hardware capability descriptions */ 800typedef struct cap_desc { 801 uint64_t cd_mask; 802 const char *cd_name; 803} cap_desc_t; 804 805static const cap_desc_t cap_desc_sparc[] = { 806 { AV_SPARC_MUL32, "MUL32" }, 807 { AV_SPARC_DIV32, "DIV32" }, 808 { AV_SPARC_FSMULD, "FSMULD" }, 809 { AV_SPARC_V8PLUS, "V8PLUS" }, 810 { AV_SPARC_POPC, "POPC" }, 811 { AV_SPARC_VIS, "VIS" }, 812 { AV_SPARC_VIS2, "VIS2" }, 813 { AV_SPARC_ASI_BLK_INIT, "ASI_BLK_INIT" }, 814 { AV_SPARC_FMAF, "FMAF" }, 815 { AV_SPARC_FJFMAU, "FJFMAU" }, 816 { AV_SPARC_IMA, "IMA" }, 817 { 0, NULL } 818}; 819 820static const cap_desc_t cap_desc_386[] = { 821 { AV_386_FPU, "FPU" }, 822 { AV_386_TSC, "TSC" }, 823 { AV_386_CX8, "CX8" }, 824 { AV_386_SEP, "SEP" }, 825 { AV_386_AMD_SYSC, "AMD_SYSC" }, 826 { AV_386_CMOV, "CMOV" }, 827 { AV_386_MMX, "MMX" }, 828 { AV_386_AMD_MMX, "AMD_MMX" }, 829 { AV_386_AMD_3DNow, "AMD_3DNow" }, 830 { AV_386_AMD_3DNowx, "AMD_3DNowx" }, 831 { AV_386_FXSR, "FXSR" }, 832 { AV_386_SSE, "SSE" }, 833 { AV_386_SSE2, "SSE2" }, 834 { AV_386_PAUSE, "PAUSE" }, 835 { AV_386_SSE3, "SSE3" }, 836 { AV_386_MON, "MON" }, 837 { AV_386_CX16, "CX16" }, 838 { AV_386_AHF, "AHF" }, 839 { AV_386_TSCP, "TSCP" }, 840 { AV_386_AMD_SSE4A, "AMD_SSE4A" }, 841 { AV_386_POPCNT, "POPCNT" }, 842 { AV_386_AMD_LZCNT, "AMD_LZCNT" }, 843 { AV_386_SSSE3, "SSSE3" }, 844 { AV_386_SSE4_1, "SSE4.1" }, 845 { AV_386_SSE4_2, "SSE4.2" }, 846 { 0, NULL } 847}; 848 849private int 850doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, 851 size_t size, off_t fsize, int *flags, int mach) 852{ 853 Elf32_Shdr sh32; 854 Elf64_Shdr sh64; 855 int stripped = 1; 856 void *nbuf; 857 off_t noff, coff; 858 uint64_t cap_hw1 = 0; /* SunOS 5.x hardware capabilites */ 859 uint64_t cap_sf1 = 0; /* SunOS 5.x software capabilites */ 860 861 if (size != xsh_sizeof) { 862 if (file_printf(ms, ", corrupted section header size") == -1) 863 return -1; 864 return 0; 865 } 866 867 for ( ; num; num--) { 868 if (lseek(fd, off, SEEK_SET) == (off_t)-1) { 869 file_badseek(ms); 870 return -1; 871 } 872 if (read(fd, xsh_addr, xsh_sizeof) == -1) { 873 file_badread(ms); 874 return -1; 875 } 876 off += size; 877 878 /* Things we can determine before we seek */ 879 switch (xsh_type) { 880 case SHT_SYMTAB: 881#if 0 882 case SHT_DYNSYM: 883#endif 884 stripped = 0; 885 break; 886 default: 887 if (xsh_offset > fsize) { 888 /* Perhaps warn here */ 889 continue; 890 } 891 break; 892 } 893 894 /* Things we can determine when we seek */ 895 switch (xsh_type) { 896 case SHT_NOTE: 897 if ((nbuf = malloc((size_t)xsh_size)) == NULL) { 898 file_error(ms, errno, "Cannot allocate memory" 899 " for note"); 900 return -1; 901 } 902 if ((noff = lseek(fd, (off_t)xsh_offset, SEEK_SET)) == 903 (off_t)-1) { 904 file_badread(ms); 905 free(nbuf); 906 return -1; 907 } 908 if (read(fd, nbuf, (size_t)xsh_size) != 909 (ssize_t)xsh_size) { 910 free(nbuf); 911 file_badread(ms); 912 return -1; 913 } 914 915 noff = 0; 916 for (;;) { 917 if (noff >= (off_t)xsh_size) 918 break; 919 noff = donote(ms, nbuf, (size_t)noff, 920 (size_t)xsh_size, clazz, swap, 4, 921 flags); 922 if (noff == 0) 923 break; 924 } 925 free(nbuf); 926 break; 927 case SHT_SUNW_cap: 928 if (lseek(fd, (off_t)xsh_offset, SEEK_SET) == 929 (off_t)-1) { 930 file_badseek(ms); 931 return -1; 932 } 933 coff = 0; 934 for (;;) { 935 Elf32_Cap cap32; 936 Elf64_Cap cap64; 937 char cbuf[/*CONSTCOND*/ 938 MAX(sizeof cap32, sizeof cap64)]; 939 if ((coff += xcap_sizeof) > (off_t)xsh_size) 940 break; 941 if (read(fd, cbuf, (size_t)xcap_sizeof) != 942 (ssize_t)xcap_sizeof) { 943 file_badread(ms); 944 return -1; 945 } 946 (void)memcpy(xcap_addr, cbuf, xcap_sizeof); 947 switch (xcap_tag) { 948 case CA_SUNW_NULL: 949 break; 950 case CA_SUNW_HW_1: 951 cap_hw1 |= xcap_val; 952 break; 953 case CA_SUNW_SF_1: 954 cap_sf1 |= xcap_val; 955 break; 956 default: 957 if (file_printf(ms, 958 ", with unknown capability " 959 "0x%" INT64_T_FORMAT "x = 0x%" 960 INT64_T_FORMAT "x", 961 (unsigned long long)xcap_tag, 962 (unsigned long long)xcap_val) == -1) 963 return -1; 964 break; 965 } 966 } 967 break; 968 969 default: 970 break; 971 } 972 } 973 if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1) 974 return -1; 975 if (cap_hw1) { 976 const cap_desc_t *cdp; 977 switch (mach) { 978 case EM_SPARC: 979 case EM_SPARC32PLUS: 980 case EM_SPARCV9: 981 cdp = cap_desc_sparc; 982 break; 983 case EM_386: 984 case EM_IA_64: 985 case EM_AMD64: 986 cdp = cap_desc_386; 987 break; 988 default: 989 cdp = NULL; 990 break; 991 } 992 if (file_printf(ms, ", uses") == -1) 993 return -1; 994 if (cdp) { 995 while (cdp->cd_name) { 996 if (cap_hw1 & cdp->cd_mask) { 997 if (file_printf(ms, 998 " %s", cdp->cd_name) == -1) 999 return -1; 1000 cap_hw1 &= ~cdp->cd_mask; 1001 } 1002 ++cdp; 1003 } 1004 if (cap_hw1) 1005 if (file_printf(ms, 1006 " unknown hardware capability 0x%" 1007 INT64_T_FORMAT "x", 1008 (unsigned long long)cap_hw1) == -1) 1009 return -1; 1010 } else { 1011 if (file_printf(ms, 1012 " hardware capability 0x%" INT64_T_FORMAT "x", 1013 (unsigned long long)cap_hw1) == -1) 1014 return -1; 1015 } 1016 } 1017 if (cap_sf1) { 1018 if (cap_sf1 & SF1_SUNW_FPUSED) { 1019 if (file_printf(ms, 1020 (cap_sf1 & SF1_SUNW_FPKNWN) 1021 ? ", uses frame pointer" 1022 : ", not known to use frame pointer") == -1) 1023 return -1; 1024 } 1025 cap_sf1 &= ~SF1_SUNW_MASK; 1026 if (cap_sf1) 1027 if (file_printf(ms, 1028 ", with unknown software capability 0x%" 1029 INT64_T_FORMAT "x", 1030 (unsigned long long)cap_sf1) == -1) 1031 return -1; 1032 } 1033 return 0; 1034} 1035 1036/* 1037 * Look through the program headers of an executable image, searching 1038 * for a PT_INTERP section; if one is found, it's dynamically linked, 1039 * otherwise it's statically linked. 1040 */ 1041private int 1042dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 1043 int num, size_t size, off_t fsize, int *flags, int sh_num) 1044{ 1045 Elf32_Phdr ph32; 1046 Elf64_Phdr ph64; 1047 const char *linking_style = "statically"; 1048 const char *shared_libraries = ""; 1049 unsigned char nbuf[BUFSIZ]; 1050 ssize_t bufsize; 1051 size_t offset, align; 1052 1053 if (size != xph_sizeof) { 1054 if (file_printf(ms, ", corrupted program header size") == -1) 1055 return -1; 1056 return 0; 1057 } 1058 1059 for ( ; num; num--) { 1060 if (lseek(fd, off, SEEK_SET) == (off_t)-1) { 1061 file_badseek(ms); 1062 return -1; 1063 } 1064 1065 if (read(fd, xph_addr, xph_sizeof) == -1) { 1066 file_badread(ms); 1067 return -1; 1068 } 1069 1070 off += size; 1071 1072 /* Things we can determine before we seek */ 1073 switch (xph_type) { 1074 case PT_DYNAMIC: 1075 linking_style = "dynamically"; 1076 break; 1077 case PT_INTERP: 1078 shared_libraries = " (uses shared libs)"; 1079 break; 1080 default: 1081 if (xph_offset > fsize) { 1082 /* Maybe warn here? */ 1083 continue; 1084 } 1085 break; 1086 } 1087 1088 /* Things we can determine when we seek */ 1089 switch (xph_type) { 1090 case PT_NOTE: 1091 if ((align = xph_align) & 0x80000000UL) { 1092 if (file_printf(ms, 1093 ", invalid note alignment 0x%lx", 1094 (unsigned long)align) == -1) 1095 return -1; 1096 align = 4; 1097 } 1098 if (sh_num) 1099 break; 1100 /* 1101 * This is a PT_NOTE section; loop through all the notes 1102 * in the section. 1103 */ 1104 if (lseek(fd, xph_offset, SEEK_SET) == (off_t)-1) { 1105 file_badseek(ms); 1106 return -1; 1107 } 1108 bufsize = read(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ? 1109 xph_filesz : sizeof(nbuf))); 1110 if (bufsize == -1) { 1111 file_badread(ms); 1112 return -1; 1113 } 1114 offset = 0; 1115 for (;;) { 1116 if (offset >= (size_t)bufsize) 1117 break; 1118 offset = donote(ms, nbuf, offset, 1119 (size_t)bufsize, clazz, swap, align, 1120 flags); 1121 if (offset == 0) 1122 break; 1123 } 1124 break; 1125 default: 1126 break; 1127 } 1128 } 1129 if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries) 1130 == -1) 1131 return -1; 1132 return 0; 1133} 1134 1135 1136protected int 1137file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, 1138 size_t nbytes) 1139{ 1140 union { 1141 int32_t l; 1142 char c[sizeof (int32_t)]; 1143 } u; 1144 int clazz; 1145 int swap; 1146 struct stat st; 1147 off_t fsize; 1148 int flags = 0; 1149 Elf32_Ehdr elf32hdr; 1150 Elf64_Ehdr elf64hdr; 1151 uint16_t type; 1152 1153 if (ms->flags & (MAGIC_MIME|MAGIC_APPLE)) 1154 return 0; 1155 /* 1156 * ELF executables have multiple section headers in arbitrary 1157 * file locations and thus file(1) cannot determine it from easily. 1158 * Instead we traverse thru all section headers until a symbol table 1159 * one is found or else the binary is stripped. 1160 * Return immediately if it's not ELF (so we avoid pipe2file unless needed). 1161 */ 1162 if (buf[EI_MAG0] != ELFMAG0 1163 || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) 1164 || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) 1165 return 0; 1166 1167 /* 1168 * If we cannot seek, it must be a pipe, socket or fifo. 1169 */ 1170 if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) 1171 fd = file_pipe2file(ms, fd, buf, nbytes); 1172 1173 if (fstat(fd, &st) == -1) { 1174 file_badread(ms); 1175 return -1; 1176 } 1177 fsize = st.st_size; 1178 1179 clazz = buf[EI_CLASS]; 1180 1181 switch (clazz) { 1182 case ELFCLASS32: 1183#undef elf_getu 1184#define elf_getu(a, b) elf_getu32(a, b) 1185#undef elfhdr 1186#define elfhdr elf32hdr 1187#include "elfclass.h" 1188 case ELFCLASS64: 1189#undef elf_getu 1190#define elf_getu(a, b) elf_getu64(a, b) 1191#undef elfhdr 1192#define elfhdr elf64hdr 1193#include "elfclass.h" 1194 default: 1195 if (file_printf(ms, ", unknown class %d", clazz) == -1) 1196 return -1; 1197 break; 1198 } 1199 return 0; 1200} 1201#endif 1202