readelf.c revision 175296
1/* 2 * Copyright (c) Christos Zoulas 2003. 3 * All Rights Reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice immediately at the beginning of the file, without modification, 10 * this list of conditions, and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27#include "file.h" 28 29#ifdef BUILTIN_ELF 30#include <string.h> 31#include <ctype.h> 32#include <stdlib.h> 33#ifdef HAVE_UNISTD_H 34#include <unistd.h> 35#endif 36 37#include "readelf.h" 38 39#ifndef lint 40FILE_RCSID("@(#)$File: readelf.c,v 1.68 2007/12/27 16:13:26 christos Exp $") 41#endif 42 43#ifdef ELFCORE 44private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t, 45 off_t, int *); 46#endif 47private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t, 48 off_t, int *); 49private int doshn(struct magic_set *, int, int, int, off_t, int, size_t, int *); 50private size_t donote(struct magic_set *, unsigned char *, size_t, size_t, int, 51 int, size_t, int *); 52 53#define ELF_ALIGN(a) ((((a) + align - 1) / align) * align) 54 55#define isquote(c) (strchr("'\"`", (c)) != NULL) 56 57private uint16_t getu16(int, uint16_t); 58private uint32_t getu32(int, uint32_t); 59private uint64_t getu64(int, uint64_t); 60 61private uint16_t 62getu16(int swap, uint16_t value) 63{ 64 union { 65 uint16_t ui; 66 char c[2]; 67 } retval, tmpval; 68 69 if (swap) { 70 tmpval.ui = value; 71 72 retval.c[0] = tmpval.c[1]; 73 retval.c[1] = tmpval.c[0]; 74 75 return retval.ui; 76 } else 77 return value; 78} 79 80private uint32_t 81getu32(int swap, uint32_t value) 82{ 83 union { 84 uint32_t ui; 85 char c[4]; 86 } retval, tmpval; 87 88 if (swap) { 89 tmpval.ui = value; 90 91 retval.c[0] = tmpval.c[3]; 92 retval.c[1] = tmpval.c[2]; 93 retval.c[2] = tmpval.c[1]; 94 retval.c[3] = tmpval.c[0]; 95 96 return retval.ui; 97 } else 98 return value; 99} 100 101private uint64_t 102getu64(int swap, uint64_t value) 103{ 104 union { 105 uint64_t ui; 106 char c[8]; 107 } retval, tmpval; 108 109 if (swap) { 110 tmpval.ui = value; 111 112 retval.c[0] = tmpval.c[7]; 113 retval.c[1] = tmpval.c[6]; 114 retval.c[2] = tmpval.c[5]; 115 retval.c[3] = tmpval.c[4]; 116 retval.c[4] = tmpval.c[3]; 117 retval.c[5] = tmpval.c[2]; 118 retval.c[6] = tmpval.c[1]; 119 retval.c[7] = tmpval.c[0]; 120 121 return retval.ui; 122 } else 123 return value; 124} 125 126#ifdef USE_ARRAY_FOR_64BIT_TYPES 127# define elf_getu64(swap, array) \ 128 ((swap ? ((uint64_t)getu32(swap, array[0])) << 32 : getu32(swap, array[0])) + \ 129 (swap ? getu32(swap, array[1]) : ((uint64_t)getu32(swap, array[1]) << 32))) 130#else 131# define elf_getu64(swap, value) getu64(swap, value) 132#endif 133 134#define xsh_addr (class == ELFCLASS32 \ 135 ? (void *) &sh32 \ 136 : (void *) &sh64) 137#define xsh_sizeof (class == ELFCLASS32 \ 138 ? sizeof sh32 \ 139 : sizeof sh64) 140#define xsh_size (class == ELFCLASS32 \ 141 ? getu32(swap, sh32.sh_size) \ 142 : getu64(swap, sh64.sh_size)) 143#define xsh_offset (class == ELFCLASS32 \ 144 ? getu32(swap, sh32.sh_offset) \ 145 : getu64(swap, sh64.sh_offset)) 146#define xsh_type (class == ELFCLASS32 \ 147 ? getu32(swap, sh32.sh_type) \ 148 : getu32(swap, sh64.sh_type)) 149#define xph_addr (class == ELFCLASS32 \ 150 ? (void *) &ph32 \ 151 : (void *) &ph64) 152#define xph_sizeof (class == ELFCLASS32 \ 153 ? sizeof ph32 \ 154 : sizeof ph64) 155#define xph_type (class == ELFCLASS32 \ 156 ? getu32(swap, ph32.p_type) \ 157 : getu32(swap, ph64.p_type)) 158#define xph_offset (off_t)(class == ELFCLASS32 \ 159 ? getu32(swap, ph32.p_offset) \ 160 : getu64(swap, ph64.p_offset)) 161#define xph_align (size_t)((class == ELFCLASS32 \ 162 ? (off_t) (ph32.p_align ? \ 163 getu32(swap, ph32.p_align) : 4) \ 164 : (off_t) (ph64.p_align ? \ 165 getu64(swap, ph64.p_align) : 4))) 166#define xph_filesz (size_t)((class == ELFCLASS32 \ 167 ? getu32(swap, ph32.p_filesz) \ 168 : getu64(swap, ph64.p_filesz))) 169#define xnh_addr (class == ELFCLASS32 \ 170 ? (void *) &nh32 \ 171 : (void *) &nh64) 172#define xph_memsz (size_t)((class == ELFCLASS32 \ 173 ? getu32(swap, ph32.p_memsz) \ 174 : getu64(swap, ph64.p_memsz))) 175#define xnh_sizeof (class == ELFCLASS32 \ 176 ? sizeof nh32 \ 177 : sizeof nh64) 178#define xnh_type (class == ELFCLASS32 \ 179 ? getu32(swap, nh32.n_type) \ 180 : getu32(swap, nh64.n_type)) 181#define xnh_namesz (class == ELFCLASS32 \ 182 ? getu32(swap, nh32.n_namesz) \ 183 : getu32(swap, nh64.n_namesz)) 184#define xnh_descsz (class == ELFCLASS32 \ 185 ? getu32(swap, nh32.n_descsz) \ 186 : getu32(swap, nh64.n_descsz)) 187#define prpsoffsets(i) (class == ELFCLASS32 \ 188 ? prpsoffsets32[i] \ 189 : prpsoffsets64[i]) 190 191#ifdef ELFCORE 192size_t prpsoffsets32[] = { 193 8, /* FreeBSD */ 194 44, /* Linux (path name) */ 195 28, /* Linux 2.0.36 (short name) */ 196 84, /* SunOS 5.x */ 197}; 198 199size_t prpsoffsets64[] = { 200 16, /* FreeBSD, 64-bit */ 201 56, /* Linux (path name) */ 202 40, /* Linux (tested on core from 2.4.x, short name) */ 203 120, /* SunOS 5.x, 64-bit */ 204}; 205 206#define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0]) 207#define NOFFSETS64 (sizeof prpsoffsets64 / sizeof prpsoffsets64[0]) 208 209#define NOFFSETS (class == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64) 210 211/* 212 * Look through the program headers of an executable image, searching 213 * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or 214 * "FreeBSD"; if one is found, try looking in various places in its 215 * contents for a 16-character string containing only printable 216 * characters - if found, that string should be the name of the program 217 * that dropped core. Note: right after that 16-character string is, 218 * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and 219 * Linux, a longer string (80 characters, in 5.x, probably other 220 * SVR4-flavored systems, and Linux) containing the start of the 221 * command line for that program. 222 * 223 * The signal number probably appears in a section of type NT_PRSTATUS, 224 * but that's also rather OS-dependent, in ways that are harder to 225 * dissect with heuristics, so I'm not bothering with the signal number. 226 * (I suppose the signal number could be of interest in situations where 227 * you don't have the binary of the program that dropped core; if you 228 * *do* have that binary, the debugger will probably tell you what 229 * signal it was.) 230 */ 231 232#define OS_STYLE_SVR4 0 233#define OS_STYLE_FREEBSD 1 234#define OS_STYLE_NETBSD 2 235 236private const char *os_style_names[] = { 237 "SVR4", 238 "FreeBSD", 239 "NetBSD", 240}; 241 242#define FLAGS_DID_CORE 1 243#define FLAGS_DID_NOTE 2 244#define FLAGS_DID_CORE_STYLE 4 245 246private int 247dophn_core(struct magic_set *ms, int class, int swap, int fd, off_t off, 248 int num, size_t size, off_t fsize, int *flags) 249{ 250 Elf32_Phdr ph32; 251 Elf64_Phdr ph64; 252 size_t offset; 253 unsigned char nbuf[BUFSIZ]; 254 ssize_t bufsize; 255 off_t savedoffset; 256 struct stat st; 257 258 if (fstat(fd, &st) < 0) { 259 file_badread(ms); 260 return -1; 261 } 262 263 if (size != xph_sizeof) { 264 if (file_printf(ms, ", corrupted program header size") == -1) 265 return -1; 266 return 0; 267 } 268 269 /* 270 * Loop through all the program headers. 271 */ 272 for ( ; num; num--) { 273 if ((savedoffset = lseek(fd, off, SEEK_SET)) == (off_t)-1) { 274 file_badseek(ms); 275 return -1; 276 } 277 if (read(fd, xph_addr, xph_sizeof) == -1) { 278 file_badread(ms); 279 return -1; 280 } 281 if (xph_offset > fsize) { 282 if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) { 283 file_badseek(ms); 284 return -1; 285 } 286 continue; 287 } 288 289 off += size; 290 if (xph_type != PT_NOTE) 291 continue; 292 293 /* 294 * This is a PT_NOTE section; loop through all the notes 295 * in the section. 296 */ 297 if (lseek(fd, xph_offset, SEEK_SET) == (off_t)-1) { 298 file_badseek(ms); 299 return -1; 300 } 301 bufsize = read(fd, nbuf, 302 ((xph_filesz < sizeof(nbuf)) ? xph_filesz : sizeof(nbuf))); 303 if (bufsize == -1) { 304 file_badread(ms); 305 return -1; 306 } 307 offset = 0; 308 for (;;) { 309 if (offset >= (size_t)bufsize) 310 break; 311 offset = donote(ms, nbuf, offset, (size_t)bufsize, 312 class, swap, 4, flags); 313 if (offset == 0) 314 break; 315 316 } 317 } 318 return 0; 319} 320#endif 321 322private size_t 323donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size, 324 int class, int swap, size_t align, int *flags) 325{ 326 Elf32_Nhdr nh32; 327 Elf64_Nhdr nh64; 328 size_t noff, doff; 329#ifdef ELFCORE 330 int os_style = -1; 331#endif 332 uint32_t namesz, descsz; 333 334 (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); 335 offset += xnh_sizeof; 336 337 namesz = xnh_namesz; 338 descsz = xnh_descsz; 339 if ((namesz == 0) && (descsz == 0)) { 340 /* 341 * We're out of note headers. 342 */ 343 return (offset >= size) ? offset : size; 344 } 345 346 if (namesz & 0x80000000) { 347 (void)file_printf(ms, ", bad note name size 0x%lx", 348 (unsigned long)namesz); 349 return offset; 350 } 351 352 if (descsz & 0x80000000) { 353 (void)file_printf(ms, ", bad note description size 0x%lx", 354 (unsigned long)descsz); 355 return offset; 356 } 357 358 359 noff = offset; 360 doff = ELF_ALIGN(offset + namesz); 361 362 if (offset + namesz > size) { 363 /* 364 * We're past the end of the buffer. 365 */ 366 return doff; 367 } 368 369 offset = ELF_ALIGN(doff + descsz); 370 if (doff + descsz > size) { 371 /* 372 * We're past the end of the buffer. 373 */ 374 return (offset >= size) ? offset : size; 375 } 376 377 if (*flags & FLAGS_DID_NOTE) 378 goto core; 379 380 if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 381 xnh_type == NT_GNU_VERSION && descsz == 16) { 382 uint32_t desc[4]; 383 (void)memcpy(desc, &nbuf[doff], sizeof(desc)); 384 385 if (file_printf(ms, ", for GNU/") == -1) 386 return size; 387 switch (getu32(swap, desc[0])) { 388 case GNU_OS_LINUX: 389 if (file_printf(ms, "Linux") == -1) 390 return size; 391 break; 392 case GNU_OS_HURD: 393 if (file_printf(ms, "Hurd") == -1) 394 return size; 395 break; 396 case GNU_OS_SOLARIS: 397 if (file_printf(ms, "Solaris") == -1) 398 return size; 399 break; 400 default: 401 if (file_printf(ms, "<unknown>") == -1) 402 return size; 403 } 404 if (file_printf(ms, " %d.%d.%d", getu32(swap, desc[1]), 405 getu32(swap, desc[2]), getu32(swap, desc[3])) == -1) 406 return size; 407 *flags |= FLAGS_DID_NOTE; 408 return size; 409 } 410 411 if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 && 412 xnh_type == NT_NETBSD_VERSION && descsz == 4) { 413 uint32_t desc; 414 (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 415 desc = getu32(swap, desc); 416 417 if (file_printf(ms, ", for NetBSD") == -1) 418 return size; 419 /* 420 * The version number used to be stuck as 199905, and was thus 421 * basically content-free. Newer versions of NetBSD have fixed 422 * this and now use the encoding of __NetBSD_Version__: 423 * 424 * MMmmrrpp00 425 * 426 * M = major version 427 * m = minor version 428 * r = release ["",A-Z,Z[A-Z] but numeric] 429 * p = patchlevel 430 */ 431 if (desc > 100000000U) { 432 uint32_t ver_patch = (desc / 100) % 100; 433 uint32_t ver_rel = (desc / 10000) % 100; 434 uint32_t ver_min = (desc / 1000000) % 100; 435 uint32_t ver_maj = desc / 100000000; 436 437 if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) 438 return size; 439 if (ver_rel == 0 && ver_patch != 0) { 440 if (file_printf(ms, ".%u", ver_patch) == -1) 441 return size; 442 } else if (ver_rel != 0) { 443 while (ver_rel > 26) { 444 if (file_printf(ms, "Z") == -1) 445 return size; 446 ver_rel -= 26; 447 } 448 if (file_printf(ms, "%c", 'A' + ver_rel - 1) 449 == -1) 450 return size; 451 } 452 } 453 *flags |= FLAGS_DID_NOTE; 454 return size; 455 } 456 457 if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0 && 458 xnh_type == NT_FREEBSD_VERSION && descsz == 4) { 459 uint32_t desc; 460 (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 461 desc = getu32(swap, desc); 462 if (file_printf(ms, ", for FreeBSD") == -1) 463 return size; 464 465 /* 466 * Contents is __FreeBSD_version, whose relation to OS 467 * versions is defined by a huge table in the Porter's 468 * Handbook. This is the general scheme: 469 * 470 * Releases: 471 * Mmp000 (before 4.10) 472 * Mmi0p0 (before 5.0) 473 * Mmm0p0 474 * 475 * Development branches: 476 * Mmpxxx (before 4.6) 477 * Mmp1xx (before 4.10) 478 * Mmi1xx (before 5.0) 479 * M000xx (pre-M.0) 480 * Mmm1xx 481 * 482 * M = major version 483 * m = minor version 484 * i = minor version increment (491000 -> 4.10) 485 * p = patchlevel 486 * x = revision 487 * 488 * The first release of FreeBSD to use ELF by default 489 * was version 3.0. 490 */ 491 if (desc == 460002) { 492 if (file_printf(ms, " 4.6.2") == -1) 493 return size; 494 } else if (desc < 460100) { 495 if (file_printf(ms, " %d.%d", desc / 100000, 496 desc / 10000 % 10) == -1) 497 return size; 498 if (desc / 1000 % 10 > 0) 499 if (file_printf(ms, ".%d", desc / 1000 % 10) 500 == -1) 501 return size; 502 if ((desc % 1000 > 0) || (desc % 100000 == 0)) 503 if (file_printf(ms, " (%d)", desc) == -1) 504 return size; 505 } else if (desc < 500000) { 506 if (file_printf(ms, " %d.%d", desc / 100000, 507 desc / 10000 % 10 + desc / 1000 % 10) == -1) 508 return size; 509 if (desc / 100 % 10 > 0) { 510 if (file_printf(ms, " (%d)", desc) == -1) 511 return size; 512 } else if (desc / 10 % 10 > 0) { 513 if (file_printf(ms, ".%d", desc / 10 % 10) 514 == -1) 515 return size; 516 } 517 } else { 518 if (file_printf(ms, " %d.%d", desc / 100000, 519 desc / 1000 % 100) == -1) 520 return size; 521 if ((desc / 100 % 10 > 0) || 522 (desc % 100000 / 100 == 0)) { 523 if (file_printf(ms, " (%d)", desc) == -1) 524 return size; 525 } else if (desc / 10 % 10 > 0) { 526 if (file_printf(ms, ".%d", desc / 10 % 10) 527 == -1) 528 return size; 529 } 530 } 531 *flags |= FLAGS_DID_NOTE; 532 return size; 533 } 534 535 if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && 536 xnh_type == NT_OPENBSD_VERSION && descsz == 4) { 537 if (file_printf(ms, ", for OpenBSD") == -1) 538 return size; 539 /* Content of note is always 0 */ 540 *flags |= FLAGS_DID_NOTE; 541 return size; 542 } 543 544 if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 && 545 xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) { 546 uint32_t desc; 547 if (file_printf(ms, ", for DragonFly") == -1) 548 return size; 549 (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 550 desc = getu32(swap, desc); 551 if (file_printf(ms, " %d.%d.%d", desc / 100000, 552 desc / 10000 % 10, desc % 10000) == -1) 553 return size; 554 *flags |= FLAGS_DID_NOTE; 555 return size; 556 } 557 558core: 559 /* 560 * Sigh. The 2.0.36 kernel in Debian 2.1, at 561 * least, doesn't correctly implement name 562 * sections, in core dumps, as specified by 563 * the "Program Linking" section of "UNIX(R) System 564 * V Release 4 Programmer's Guide: ANSI C and 565 * Programming Support Tools", because my copy 566 * clearly says "The first 'namesz' bytes in 'name' 567 * contain a *null-terminated* [emphasis mine] 568 * character representation of the entry's owner 569 * or originator", but the 2.0.36 kernel code 570 * doesn't include the terminating null in the 571 * name.... 572 */ 573 if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) || 574 (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) { 575 os_style = OS_STYLE_SVR4; 576 } 577 578 if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) { 579 os_style = OS_STYLE_FREEBSD; 580 } 581 582 if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11) 583 == 0)) { 584 os_style = OS_STYLE_NETBSD; 585 } 586 587#ifdef ELFCORE 588 if ((*flags & FLAGS_DID_CORE) != 0) 589 return size; 590 591 if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) { 592 if (file_printf(ms, ", %s-style", os_style_names[os_style]) 593 == -1) 594 return size; 595 *flags |= FLAGS_DID_CORE_STYLE; 596 } 597 598 switch (os_style) { 599 case OS_STYLE_NETBSD: 600 if (xnh_type == NT_NETBSD_CORE_PROCINFO) { 601 uint32_t signo; 602 /* 603 * Extract the program name. It is at 604 * offset 0x7c, and is up to 32-bytes, 605 * including the terminating NUL. 606 */ 607 if (file_printf(ms, ", from '%.31s'", 608 &nbuf[doff + 0x7c]) == -1) 609 return size; 610 611 /* 612 * Extract the signal number. It is at 613 * offset 0x08. 614 */ 615 (void)memcpy(&signo, &nbuf[doff + 0x08], 616 sizeof(signo)); 617 if (file_printf(ms, " (signal %u)", 618 getu32(swap, signo)) == -1) 619 return size; 620 *flags |= FLAGS_DID_CORE; 621 return size; 622 } 623 break; 624 625 default: 626 if (xnh_type == NT_PRPSINFO) { 627 size_t i, j; 628 unsigned char c; 629 /* 630 * Extract the program name. We assume 631 * it to be 16 characters (that's what it 632 * is in SunOS 5.x and Linux). 633 * 634 * Unfortunately, it's at a different offset 635 * in various OSes, so try multiple offsets. 636 * If the characters aren't all printable, 637 * reject it. 638 */ 639 for (i = 0; i < NOFFSETS; i++) { 640 unsigned char *cname, *cp; 641 size_t reloffset = prpsoffsets(i); 642 size_t noffset = doff + reloffset; 643 for (j = 0; j < 16; j++, noffset++, 644 reloffset++) { 645 /* 646 * Make sure we're not past 647 * the end of the buffer; if 648 * we are, just give up. 649 */ 650 if (noffset >= size) 651 goto tryanother; 652 653 /* 654 * Make sure we're not past 655 * the end of the contents; 656 * if we are, this obviously 657 * isn't the right offset. 658 */ 659 if (reloffset >= descsz) 660 goto tryanother; 661 662 c = nbuf[noffset]; 663 if (c == '\0') { 664 /* 665 * A '\0' at the 666 * beginning is 667 * obviously wrong. 668 * Any other '\0' 669 * means we're done. 670 */ 671 if (j == 0) 672 goto tryanother; 673 else 674 break; 675 } else { 676 /* 677 * A nonprintable 678 * character is also 679 * wrong. 680 */ 681 if (!isprint(c) || isquote(c)) 682 goto tryanother; 683 } 684 } 685 /* 686 * Well, that worked. 687 */ 688 cname = (unsigned char *) 689 &nbuf[doff + prpsoffsets(i)]; 690 for (cp = cname; *cp && isprint(*cp); cp++) 691 continue; 692 if (cp > cname) 693 cp--; 694 if (file_printf(ms, ", from '%.*s'", 695 (int)(cp - cname), cname) == -1) 696 return size; 697 *flags |= FLAGS_DID_CORE; 698 return size; 699 700 tryanother: 701 ; 702 } 703 } 704 break; 705 } 706#endif 707 return offset; 708} 709 710private int 711doshn(struct magic_set *ms, int class, int swap, int fd, off_t off, int num, 712 size_t size, int *flags) 713{ 714 Elf32_Shdr sh32; 715 Elf64_Shdr sh64; 716 int stripped = 1; 717 void *nbuf; 718 off_t noff; 719 720 if (size != xsh_sizeof) { 721 if (file_printf(ms, ", corrupted section header size") == -1) 722 return -1; 723 return 0; 724 } 725 726 if (lseek(fd, off, SEEK_SET) == (off_t)-1) { 727 file_badseek(ms); 728 return -1; 729 } 730 731 for ( ; num; num--) { 732 if (read(fd, xsh_addr, xsh_sizeof) == -1) { 733 file_badread(ms); 734 return -1; 735 } 736 switch (xsh_type) { 737 case SHT_SYMTAB: 738#if 0 739 case SHT_DYNSYM: 740#endif 741 stripped = 0; 742 break; 743 case SHT_NOTE: 744 if ((off = lseek(fd, (off_t)0, SEEK_CUR)) == 745 (off_t)-1) { 746 file_badread(ms); 747 return -1; 748 } 749 if ((nbuf = malloc((size_t)xsh_size)) == NULL) { 750 file_error(ms, errno, "Cannot allocate memory" 751 " for note"); 752 return -1; 753 } 754 if ((noff = lseek(fd, (off_t)xsh_offset, SEEK_SET)) == 755 (off_t)-1) { 756 file_badread(ms); 757 free(nbuf); 758 return -1; 759 } 760 if (read(fd, nbuf, (size_t)xsh_size) != 761 (ssize_t)xsh_size) { 762 free(nbuf); 763 file_badread(ms); 764 return -1; 765 } 766 767 noff = 0; 768 for (;;) { 769 if (noff >= (size_t)xsh_size) 770 break; 771 noff = donote(ms, nbuf, (size_t)noff, 772 (size_t)xsh_size, class, swap, 4, 773 flags); 774 if (noff == 0) 775 break; 776 } 777 if ((lseek(fd, off, SEEK_SET)) == (off_t)-1) { 778 free(nbuf); 779 file_badread(ms); 780 return -1; 781 } 782 free(nbuf); 783 break; 784 } 785 } 786 if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1) 787 return -1; 788 return 0; 789} 790 791/* 792 * Look through the program headers of an executable image, searching 793 * for a PT_INTERP section; if one is found, it's dynamically linked, 794 * otherwise it's statically linked. 795 */ 796private int 797dophn_exec(struct magic_set *ms, int class, int swap, int fd, off_t off, 798 int num, size_t size, off_t fsize, int *flags) 799{ 800 Elf32_Phdr ph32; 801 Elf64_Phdr ph64; 802 const char *linking_style = "statically"; 803 const char *shared_libraries = ""; 804 unsigned char nbuf[BUFSIZ]; 805 int bufsize; 806 size_t offset, align; 807 off_t savedoffset = (off_t)-1; 808 struct stat st; 809 810 if (fstat(fd, &st) < 0) { 811 file_badread(ms); 812 return -1; 813 } 814 815 if (size != xph_sizeof) { 816 if (file_printf(ms, ", corrupted program header size") == -1) 817 return -1; 818 return 0; 819 } 820 821 if (lseek(fd, off, SEEK_SET) == (off_t)-1) { 822 file_badseek(ms); 823 return -1; 824 } 825 826 for ( ; num; num--) { 827 if (read(fd, xph_addr, xph_sizeof) == -1) { 828 file_badread(ms); 829 return -1; 830 } 831 if (xph_offset > st.st_size && savedoffset != (off_t)-1) { 832 if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) { 833 file_badseek(ms); 834 return -1; 835 } 836 continue; 837 } 838 839 if ((savedoffset = lseek(fd, (off_t)0, SEEK_CUR)) == (off_t)-1) { 840 file_badseek(ms); 841 return -1; 842 } 843 844 if (xph_offset > fsize) { 845 if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) { 846 file_badseek(ms); 847 return -1; 848 } 849 continue; 850 } 851 852 switch (xph_type) { 853 case PT_DYNAMIC: 854 linking_style = "dynamically"; 855 break; 856 case PT_INTERP: 857 shared_libraries = " (uses shared libs)"; 858 break; 859 case PT_NOTE: 860 if ((align = xph_align) & 0x80000000) { 861 if (file_printf(ms, 862 ", invalid note alignment 0x%lx", 863 (unsigned long)align) == -1) 864 return -1; 865 align = 4; 866 } 867 /* 868 * This is a PT_NOTE section; loop through all the notes 869 * in the section. 870 */ 871 if (lseek(fd, xph_offset, SEEK_SET) 872 == (off_t)-1) { 873 file_badseek(ms); 874 return -1; 875 } 876 bufsize = read(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ? 877 xph_filesz : sizeof(nbuf))); 878 if (bufsize == -1) { 879 file_badread(ms); 880 return -1; 881 } 882 offset = 0; 883 for (;;) { 884 if (offset >= (size_t)bufsize) 885 break; 886 offset = donote(ms, nbuf, offset, 887 (size_t)bufsize, class, swap, align, 888 flags); 889 if (offset == 0) 890 break; 891 } 892 if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) { 893 file_badseek(ms); 894 return -1; 895 } 896 break; 897 default: 898 break; 899 } 900 } 901 if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries) 902 == -1) 903 return -1; 904 return 0; 905} 906 907 908protected int 909file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, 910 size_t nbytes) 911{ 912 union { 913 int32_t l; 914 char c[sizeof (int32_t)]; 915 } u; 916 int class; 917 int swap; 918 struct stat st; 919 off_t fsize; 920 int flags = 0; 921 922 /* 923 * If we cannot seek, it must be a pipe, socket or fifo. 924 */ 925 if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) 926 fd = file_pipe2file(ms, fd, buf, nbytes); 927 928 if (fstat(fd, &st) == -1) { 929 file_badread(ms); 930 return -1; 931 } 932 fsize = st.st_size; 933 934 /* 935 * ELF executables have multiple section headers in arbitrary 936 * file locations and thus file(1) cannot determine it from easily. 937 * Instead we traverse thru all section headers until a symbol table 938 * one is found or else the binary is stripped. 939 */ 940 if (buf[EI_MAG0] != ELFMAG0 941 || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) 942 || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) 943 return 0; 944 945 946 class = buf[EI_CLASS]; 947 948 if (class == ELFCLASS32) { 949 Elf32_Ehdr elfhdr; 950 uint16_t type; 951 952 if (nbytes <= sizeof (Elf32_Ehdr)) 953 return 0; 954 955 956 u.l = 1; 957 (void) memcpy(&elfhdr, buf, sizeof elfhdr); 958 swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA]; 959 960 type = getu16(swap, elfhdr.e_type); 961 switch (type) { 962#ifdef ELFCORE 963 case ET_CORE: 964 if (dophn_core(ms, class, swap, fd, 965 (off_t)getu32(swap, elfhdr.e_phoff), 966 getu16(swap, elfhdr.e_phnum), 967 (size_t)getu16(swap, elfhdr.e_phentsize), 968 fsize, &flags) == -1) 969 return -1; 970 break; 971#endif 972 case ET_EXEC: 973 case ET_DYN: 974 if (dophn_exec(ms, class, swap, 975 fd, (off_t)getu32(swap, elfhdr.e_phoff), 976 getu16(swap, elfhdr.e_phnum), 977 (size_t)getu16(swap, elfhdr.e_phentsize), 978 fsize, &flags) == -1) 979 return -1; 980 if (doshn(ms, class, swap, fd, 981 (off_t)getu32(swap, elfhdr.e_shoff), 982 getu16(swap, elfhdr.e_shnum), 983 (size_t)getu16(swap, elfhdr.e_shentsize), 984 &flags) == -1) 985 return -1; 986 break; 987 988 default: 989 break; 990 } 991 return 1; 992 } 993 994 if (class == ELFCLASS64) { 995 Elf64_Ehdr elfhdr; 996 if (nbytes <= sizeof (Elf64_Ehdr)) 997 return 0; 998 999 1000 u.l = 1; 1001 (void) memcpy(&elfhdr, buf, sizeof elfhdr); 1002 swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA]; 1003 1004 if (getu16(swap, elfhdr.e_type) == ET_CORE) { 1005#ifdef ELFCORE 1006 if (dophn_core(ms, class, swap, fd, 1007 (off_t)elf_getu64(swap, elfhdr.e_phoff), 1008 getu16(swap, elfhdr.e_phnum), 1009 (size_t)getu16(swap, elfhdr.e_phentsize), 1010 fsize, &flags) == -1) 1011 return -1; 1012#else 1013 ; 1014#endif 1015 } else { 1016 if (getu16(swap, elfhdr.e_type) == ET_EXEC) { 1017 if (dophn_exec(ms, class, swap, fd, 1018 (off_t)elf_getu64(swap, elfhdr.e_phoff), 1019 getu16(swap, elfhdr.e_phnum), 1020 (size_t)getu16(swap, elfhdr.e_phentsize), 1021 fsize, &flags) == -1) 1022 return -1; 1023 } 1024 if (doshn(ms, class, swap, fd, 1025 (off_t)elf_getu64(swap, elfhdr.e_shoff), 1026 getu16(swap, elfhdr.e_shnum), 1027 (size_t)getu16(swap, elfhdr.e_shentsize), &flags) 1028 == -1) 1029 return -1; 1030 } 1031 return 1; 1032 } 1033 return 0; 1034} 1035#endif 1036