readelf.c revision 169942
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("@(#)$Id: readelf.c,v 1.61 2006/11/15 15:53:23 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 (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 28, /* Linux 2.0.36 (short name) */ 195 44, /* Linux (path name) */ 196 84, /* SunOS 5.x */ 197}; 198 199size_t prpsoffsets64[] = { 200 16, /* FreeBSD, 64-bit */ 201 40, /* Linux (tested on core from 2.4.x, short name) */ 202 56, /* Linux (path 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 245private int 246dophn_core(struct magic_set *ms, int class, int swap, int fd, off_t off, 247 int num, size_t size, off_t fsize, int *flags) 248{ 249 Elf32_Phdr ph32; 250 Elf64_Phdr ph64; 251 size_t offset; 252 unsigned char nbuf[BUFSIZ]; 253 ssize_t bufsize; 254 off_t savedoffset; 255 struct stat st; 256 257 if (fstat(fd, &st) < 0) { 258 file_badread(ms); 259 return -1; 260 } 261 262 if (size != xph_sizeof) { 263 if (file_printf(ms, ", corrupted program header size") == -1) 264 return -1; 265 return 0; 266 } 267 268 /* 269 * Loop through all the program headers. 270 */ 271 for ( ; num; num--) { 272 if ((savedoffset = lseek(fd, off, SEEK_SET)) == (off_t)-1) { 273 file_badseek(ms); 274 return -1; 275 } 276 if (read(fd, xph_addr, xph_sizeof) == -1) { 277 file_badread(ms); 278 return -1; 279 } 280 if (xph_offset > fsize) { 281 if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) { 282 file_badseek(ms); 283 return -1; 284 } 285 continue; 286 } 287 288 off += size; 289 if (xph_type != PT_NOTE) 290 continue; 291 292 /* 293 * This is a PT_NOTE section; loop through all the notes 294 * in the section. 295 */ 296 if (lseek(fd, (off_t)xph_offset, SEEK_SET) == (off_t)-1) { 297 file_badseek(ms); 298 return -1; 299 } 300 bufsize = read(fd, nbuf, 301 ((xph_filesz < sizeof(nbuf)) ? xph_filesz : sizeof(nbuf))); 302 if (bufsize == -1) { 303 file_badread(ms); 304 return -1; 305 } 306 offset = 0; 307 for (;;) { 308 if (offset >= (size_t)bufsize) 309 break; 310 offset = donote(ms, nbuf, offset, (size_t)bufsize, 311 class, swap, 4, flags); 312 if (offset == 0) 313 break; 314 315 } 316 } 317 return 0; 318} 319#endif 320 321private size_t 322donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size, 323 int class, int swap, size_t align, int *flags) 324{ 325 Elf32_Nhdr nh32; 326 Elf64_Nhdr nh64; 327 size_t noff, doff; 328#ifdef ELFCORE 329 int os_style = -1; 330#endif 331 uint32_t namesz, descsz; 332 333 (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); 334 offset += xnh_sizeof; 335 336 namesz = xnh_namesz; 337 descsz = xnh_descsz; 338 if ((namesz == 0) && (descsz == 0)) { 339 /* 340 * We're out of note headers. 341 */ 342 return (offset >= size) ? offset : size; 343 } 344 345 if (namesz & 0x80000000) { 346 (void)file_printf(ms, ", bad note name size 0x%lx", 347 (unsigned long)namesz); 348 return offset; 349 } 350 351 if (descsz & 0x80000000) { 352 (void)file_printf(ms, ", bad note description size 0x%lx", 353 (unsigned long)descsz); 354 return offset; 355 } 356 357 358 noff = offset; 359 doff = ELF_ALIGN(offset + namesz); 360 361 if (offset + namesz > size) { 362 /* 363 * We're past the end of the buffer. 364 */ 365 return doff; 366 } 367 368 offset = ELF_ALIGN(doff + descsz); 369 if (doff + descsz > size) { 370 /* 371 * We're past the end of the buffer. 372 */ 373 return (offset >= size) ? offset : size; 374 } 375 376 if (*flags & FLAGS_DID_NOTE) 377 goto core; 378 379 if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 380 xnh_type == NT_GNU_VERSION && descsz == 16) { 381 uint32_t desc[4]; 382 (void)memcpy(desc, &nbuf[doff], sizeof(desc)); 383 384 if (file_printf(ms, ", for GNU/") == -1) 385 return size; 386 switch (getu32(swap, desc[0])) { 387 case GNU_OS_LINUX: 388 if (file_printf(ms, "Linux") == -1) 389 return size; 390 break; 391 case GNU_OS_HURD: 392 if (file_printf(ms, "Hurd") == -1) 393 return size; 394 break; 395 case GNU_OS_SOLARIS: 396 if (file_printf(ms, "Solaris") == -1) 397 return size; 398 break; 399 default: 400 if (file_printf(ms, "<unknown>") == -1) 401 return size; 402 } 403 if (file_printf(ms, " %d.%d.%d", getu32(swap, desc[1]), 404 getu32(swap, desc[2]), getu32(swap, desc[3])) == -1) 405 return size; 406 *flags |= FLAGS_DID_NOTE; 407 return size; 408 } 409 410 if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 && 411 xnh_type == NT_NETBSD_VERSION && descsz == 4) { 412 uint32_t desc; 413 (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 414 desc = getu32(swap, desc); 415 416 if (file_printf(ms, ", for NetBSD") == -1) 417 return size; 418 /* 419 * The version number used to be stuck as 199905, and was thus 420 * basically content-free. Newer versions of NetBSD have fixed 421 * this and now use the encoding of __NetBSD_Version__: 422 * 423 * MMmmrrpp00 424 * 425 * M = major version 426 * m = minor version 427 * r = release ["",A-Z,Z[A-Z] but numeric] 428 * p = patchlevel 429 */ 430 if (desc > 100000000U) { 431 uint32_t ver_patch = (desc / 100) % 100; 432 uint32_t ver_rel = (desc / 10000) % 100; 433 uint32_t ver_min = (desc / 1000000) % 100; 434 uint32_t ver_maj = desc / 100000000; 435 436 if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) 437 return size; 438 if (ver_rel == 0 && ver_patch != 0) { 439 if (file_printf(ms, ".%u", ver_patch) == -1) 440 return size; 441 } else if (ver_rel != 0) { 442 while (ver_rel > 26) { 443 if (file_printf(ms, "Z") == -1) 444 return size; 445 ver_rel -= 26; 446 } 447 if (file_printf(ms, "%c", 'A' + ver_rel - 1) 448 == -1) 449 return size; 450 } 451 } 452 *flags |= FLAGS_DID_NOTE; 453 return size; 454 } 455 456 if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0 && 457 xnh_type == NT_FREEBSD_VERSION && descsz == 4) { 458 uint32_t desc; 459 (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 460 desc = getu32(swap, desc); 461 if (file_printf(ms, ", for FreeBSD") == -1) 462 return size; 463 464 /* 465 * Contents is __FreeBSD_version, whose relation to OS 466 * versions is defined by a huge table in the Porter's 467 * Handbook. This is the general scheme: 468 * 469 * Releases: 470 * Mmp000 (before 4.10) 471 * Mmi0p0 (before 5.0) 472 * Mmm0p0 473 * 474 * Development branches: 475 * Mmpxxx (before 4.6) 476 * Mmp1xx (before 4.10) 477 * Mmi1xx (before 5.0) 478 * M000xx (pre-M.0) 479 * Mmm1xx 480 * 481 * M = major version 482 * m = minor version 483 * i = minor version increment (491000 -> 4.10) 484 * p = patchlevel 485 * x = revision 486 * 487 * The first release of FreeBSD to use ELF by default 488 * was version 3.0. 489 */ 490 if (desc == 460002) { 491 if (file_printf(ms, " 4.6.2") == -1) 492 return size; 493 } else if (desc < 460100) { 494 if (file_printf(ms, " %d.%d", desc / 100000, 495 desc / 10000 % 10) == -1) 496 return size; 497 if (desc / 1000 % 10 > 0) 498 if (file_printf(ms, ".%d", desc / 1000 % 10) 499 == -1) 500 return size; 501 if ((desc % 1000 > 0) || (desc % 100000 == 0)) 502 if (file_printf(ms, " (%d)", desc) == -1) 503 return size; 504 } else if (desc < 500000) { 505 if (file_printf(ms, " %d.%d", desc / 100000, 506 desc / 10000 % 10 + desc / 1000 % 10) == -1) 507 return size; 508 if (desc / 100 % 10 > 0) { 509 if (file_printf(ms, " (%d)", desc) == -1) 510 return size; 511 } else if (desc / 10 % 10 > 0) { 512 if (file_printf(ms, ".%d", desc / 10 % 10) 513 == -1) 514 return size; 515 } 516 } else { 517 if (file_printf(ms, " %d.%d", desc / 100000, 518 desc / 1000 % 100) == -1) 519 return size; 520 if ((desc / 100 % 10 > 0) || 521 (desc % 100000 / 100 == 0)) { 522 if (file_printf(ms, " (%d)", desc) == -1) 523 return size; 524 } else if (desc / 10 % 10 > 0) { 525 if (file_printf(ms, ".%d", desc / 10 % 10) 526 == -1) 527 return size; 528 } 529 } 530 *flags |= FLAGS_DID_NOTE; 531 return size; 532 } 533 534 if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && 535 xnh_type == NT_OPENBSD_VERSION && descsz == 4) { 536 if (file_printf(ms, ", for OpenBSD") == -1) 537 return size; 538 /* Content of note is always 0 */ 539 *flags |= FLAGS_DID_NOTE; 540 return size; 541 } 542 543 if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 && 544 xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) { 545 uint32_t desc; 546 if (file_printf(ms, ", for DragonFly") == -1) 547 return size; 548 (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 549 desc = getu32(swap, desc); 550 if (file_printf(ms, " %d.%d.%d", desc / 100000, 551 desc / 10000 % 10, desc % 10000) == -1) 552 return size; 553 *flags |= FLAGS_DID_NOTE; 554 return size; 555 } 556 557core: 558 /* 559 * Sigh. The 2.0.36 kernel in Debian 2.1, at 560 * least, doesn't correctly implement name 561 * sections, in core dumps, as specified by 562 * the "Program Linking" section of "UNIX(R) System 563 * V Release 4 Programmer's Guide: ANSI C and 564 * Programming Support Tools", because my copy 565 * clearly says "The first 'namesz' bytes in 'name' 566 * contain a *null-terminated* [emphasis mine] 567 * character representation of the entry's owner 568 * or originator", but the 2.0.36 kernel code 569 * doesn't include the terminating null in the 570 * name.... 571 */ 572 if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) || 573 (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) { 574 os_style = OS_STYLE_SVR4; 575 } 576 577 if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) { 578 os_style = OS_STYLE_FREEBSD; 579 } 580 581 if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11) 582 == 0)) { 583 os_style = OS_STYLE_NETBSD; 584 } 585 586#ifdef ELFCORE 587 if ((*flags & FLAGS_DID_CORE) != 0) 588 return size; 589 590 if (os_style != -1) { 591 if (file_printf(ms, ", %s-style", os_style_names[os_style]) 592 == -1) 593 return size; 594 } 595 596 switch (os_style) { 597 case OS_STYLE_NETBSD: 598 if (xnh_type == NT_NETBSD_CORE_PROCINFO) { 599 uint32_t signo; 600 /* 601 * Extract the program name. It is at 602 * offset 0x7c, and is up to 32-bytes, 603 * including the terminating NUL. 604 */ 605 if (file_printf(ms, ", from '%.31s'", 606 &nbuf[doff + 0x7c]) == -1) 607 return size; 608 609 /* 610 * Extract the signal number. It is at 611 * offset 0x08. 612 */ 613 (void)memcpy(&signo, &nbuf[doff + 0x08], 614 sizeof(signo)); 615 if (file_printf(ms, " (signal %u)", 616 getu32(swap, signo)) == -1) 617 return size; 618 return size; 619 } 620 break; 621 622 default: 623 if (xnh_type == NT_PRPSINFO) { 624 size_t i, j; 625 unsigned char c; 626 /* 627 * Extract the program name. We assume 628 * it to be 16 characters (that's what it 629 * is in SunOS 5.x and Linux). 630 * 631 * Unfortunately, it's at a different offset 632 * in varous OSes, so try multiple offsets. 633 * If the characters aren't all printable, 634 * reject it. 635 */ 636 for (i = 0; i < NOFFSETS; i++) { 637 size_t reloffset = prpsoffsets(i); 638 size_t noffset = doff + reloffset; 639 for (j = 0; j < 16; j++, noffset++, 640 reloffset++) { 641 /* 642 * Make sure we're not past 643 * the end of the buffer; if 644 * we are, just give up. 645 */ 646 if (noffset >= size) 647 goto tryanother; 648 649 /* 650 * Make sure we're not past 651 * the end of the contents; 652 * if we are, this obviously 653 * isn't the right offset. 654 */ 655 if (reloffset >= descsz) 656 goto tryanother; 657 658 c = nbuf[noffset]; 659 if (c == '\0') { 660 /* 661 * A '\0' at the 662 * beginning is 663 * obviously wrong. 664 * Any other '\0' 665 * means we're done. 666 */ 667 if (j == 0) 668 goto tryanother; 669 else 670 break; 671 } else { 672 /* 673 * A nonprintable 674 * character is also 675 * wrong. 676 */ 677 if (!isprint(c) || isquote(c)) 678 goto tryanother; 679 } 680 } 681 /* 682 * Well, that worked. 683 */ 684 if (file_printf(ms, ", from '%.16s'", 685 &nbuf[doff + prpsoffsets(i)]) == -1) 686 return size; 687 return size; 688 689 tryanother: 690 ; 691 } 692 } 693 break; 694 } 695#endif 696 *flags |= FLAGS_DID_CORE; 697 return offset; 698} 699 700private int 701doshn(struct magic_set *ms, int class, int swap, int fd, off_t off, int num, 702 size_t size, int *flags) 703{ 704 Elf32_Shdr sh32; 705 Elf64_Shdr sh64; 706 int stripped = 1; 707 void *nbuf; 708 off_t noff; 709 710 if (size != xsh_sizeof) { 711 if (file_printf(ms, ", corrupted section header size") == -1) 712 return -1; 713 return 0; 714 } 715 716 if (lseek(fd, off, SEEK_SET) == (off_t)-1) { 717 file_badseek(ms); 718 return -1; 719 } 720 721 for ( ; num; num--) { 722 if (read(fd, xsh_addr, xsh_sizeof) == -1) { 723 file_badread(ms); 724 return -1; 725 } 726 switch (xsh_type) { 727 case SHT_SYMTAB: 728#if 0 729 case SHT_DYNSYM: 730#endif 731 stripped = 0; 732 break; 733 case SHT_NOTE: 734 if ((off = lseek(fd, (off_t)0, SEEK_CUR)) == 735 (off_t)-1) { 736 file_badread(ms); 737 return -1; 738 } 739 if ((nbuf = malloc((size_t)xsh_size)) == NULL) { 740 file_error(ms, errno, "Cannot allocate memory" 741 " for note"); 742 return -1; 743 } 744 if ((noff = lseek(fd, (off_t)xsh_offset, SEEK_SET)) == 745 (off_t)-1) { 746 file_badread(ms); 747 free(nbuf); 748 return -1; 749 } 750 if (read(fd, nbuf, (size_t)xsh_size) != 751 (ssize_t)xsh_size) { 752 free(nbuf); 753 file_badread(ms); 754 return -1; 755 } 756 757 noff = 0; 758 for (;;) { 759 if (noff >= (size_t)xsh_size) 760 break; 761 noff = donote(ms, nbuf, (size_t)noff, 762 (size_t)xsh_size, class, swap, 4, 763 flags); 764 if (noff == 0) 765 break; 766 } 767 if ((lseek(fd, off, SEEK_SET)) == (off_t)-1) { 768 free(nbuf); 769 file_badread(ms); 770 return -1; 771 } 772 free(nbuf); 773 break; 774 } 775 } 776 if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1) 777 return -1; 778 return 0; 779} 780 781/* 782 * Look through the program headers of an executable image, searching 783 * for a PT_INTERP section; if one is found, it's dynamically linked, 784 * otherwise it's statically linked. 785 */ 786private int 787dophn_exec(struct magic_set *ms, int class, int swap, int fd, off_t off, 788 int num, size_t size, off_t fsize, int *flags) 789{ 790 Elf32_Phdr ph32; 791 Elf64_Phdr ph64; 792 const char *linking_style = "statically"; 793 const char *shared_libraries = ""; 794 unsigned char nbuf[BUFSIZ]; 795 int bufsize; 796 size_t offset, align; 797 off_t savedoffset = (off_t)-1; 798 struct stat st; 799 800 if (fstat(fd, &st) < 0) { 801 file_badread(ms); 802 return -1; 803 } 804 805 if (size != xph_sizeof) { 806 if (file_printf(ms, ", corrupted program header size") == -1) 807 return -1; 808 return 0; 809 } 810 811 if (lseek(fd, off, SEEK_SET) == (off_t)-1) { 812 file_badseek(ms); 813 return -1; 814 } 815 816 for ( ; num; num--) { 817 if (read(fd, xph_addr, xph_sizeof) == -1) { 818 file_badread(ms); 819 return -1; 820 } 821 if (xph_offset > st.st_size && savedoffset != (off_t)-1) { 822 if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) { 823 file_badseek(ms); 824 return -1; 825 } 826 continue; 827 } 828 829 if ((savedoffset = lseek(fd, (off_t)0, SEEK_CUR)) == (off_t)-1) { 830 file_badseek(ms); 831 return -1; 832 } 833 834 if (xph_offset > fsize) { 835 if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) { 836 file_badseek(ms); 837 return -1; 838 } 839 continue; 840 } 841 842 switch (xph_type) { 843 case PT_DYNAMIC: 844 linking_style = "dynamically"; 845 break; 846 case PT_INTERP: 847 shared_libraries = " (uses shared libs)"; 848 break; 849 case PT_NOTE: 850 if ((align = xph_align) & 0x80000000) { 851 if (file_printf(ms, 852 ", invalid note alignment 0x%lx", 853 (unsigned long)align) == -1) 854 return -1; 855 align = 4; 856 } 857 /* 858 * This is a PT_NOTE section; loop through all the notes 859 * in the section. 860 */ 861 if (lseek(fd, (off_t)xph_offset, SEEK_SET) 862 == (off_t)-1) { 863 file_badseek(ms); 864 return -1; 865 } 866 bufsize = read(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ? 867 xph_filesz : sizeof(nbuf))); 868 if (bufsize == -1) { 869 file_badread(ms); 870 return -1; 871 } 872 offset = 0; 873 for (;;) { 874 if (offset >= (size_t)bufsize) 875 break; 876 offset = donote(ms, nbuf, offset, 877 (size_t)bufsize, class, swap, align, 878 flags); 879 if (offset == 0) 880 break; 881 } 882 if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) { 883 file_badseek(ms); 884 return -1; 885 } 886 break; 887 } 888 } 889 if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries) 890 == -1) 891 return -1; 892 return 0; 893} 894 895 896protected int 897file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, 898 size_t nbytes) 899{ 900 union { 901 int32_t l; 902 char c[sizeof (int32_t)]; 903 } u; 904 int class; 905 int swap; 906 struct stat st; 907 off_t fsize; 908 int flags = 0; 909 910 /* 911 * If we cannot seek, it must be a pipe, socket or fifo. 912 */ 913 if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) 914 fd = file_pipe2file(ms, fd, buf, nbytes); 915 916 if (fstat(fd, &st) == -1) { 917 file_badread(ms); 918 return -1; 919 } 920 fsize = st.st_size; 921 922 /* 923 * ELF executables have multiple section headers in arbitrary 924 * file locations and thus file(1) cannot determine it from easily. 925 * Instead we traverse thru all section headers until a symbol table 926 * one is found or else the binary is stripped. 927 */ 928 if (buf[EI_MAG0] != ELFMAG0 929 || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) 930 || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) 931 return 0; 932 933 934 class = buf[EI_CLASS]; 935 936 if (class == ELFCLASS32) { 937 Elf32_Ehdr elfhdr; 938 if (nbytes <= sizeof (Elf32_Ehdr)) 939 return 0; 940 941 942 u.l = 1; 943 (void) memcpy(&elfhdr, buf, sizeof elfhdr); 944 swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA]; 945 946 if (getu16(swap, elfhdr.e_type) == ET_CORE) { 947#ifdef ELFCORE 948 if (dophn_core(ms, class, swap, fd, 949 (off_t)getu32(swap, elfhdr.e_phoff), 950 getu16(swap, elfhdr.e_phnum), 951 (size_t)getu16(swap, elfhdr.e_phentsize), 952 fsize, &flags) == -1) 953 return -1; 954#else 955 ; 956#endif 957 } else { 958 if (getu16(swap, elfhdr.e_type) == ET_EXEC) { 959 if (dophn_exec(ms, class, swap, 960 fd, (off_t)getu32(swap, elfhdr.e_phoff), 961 getu16(swap, elfhdr.e_phnum), 962 (size_t)getu16(swap, elfhdr.e_phentsize), 963 fsize, &flags) 964 == -1) 965 return -1; 966 } 967 if (doshn(ms, class, swap, fd, 968 (off_t)getu32(swap, elfhdr.e_shoff), 969 getu16(swap, elfhdr.e_shnum), 970 (size_t)getu16(swap, elfhdr.e_shentsize), 971 &flags) == -1) 972 return -1; 973 } 974 return 1; 975 } 976 977 if (class == ELFCLASS64) { 978 Elf64_Ehdr elfhdr; 979 if (nbytes <= sizeof (Elf64_Ehdr)) 980 return 0; 981 982 983 u.l = 1; 984 (void) memcpy(&elfhdr, buf, sizeof elfhdr); 985 swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA]; 986 987 if (getu16(swap, elfhdr.e_type) == ET_CORE) { 988#ifdef ELFCORE 989 if (dophn_core(ms, class, swap, fd, 990 (off_t)elf_getu64(swap, elfhdr.e_phoff), 991 getu16(swap, elfhdr.e_phnum), 992 (size_t)getu16(swap, elfhdr.e_phentsize), 993 fsize, &flags) == -1) 994 return -1; 995#else 996 ; 997#endif 998 } else { 999 if (getu16(swap, elfhdr.e_type) == ET_EXEC) { 1000 if (dophn_exec(ms, class, swap, fd, 1001 (off_t)elf_getu64(swap, elfhdr.e_phoff), 1002 getu16(swap, elfhdr.e_phnum), 1003 (size_t)getu16(swap, elfhdr.e_phentsize), 1004 fsize, &flags) == -1) 1005 return -1; 1006 } 1007 if (doshn(ms, class, swap, fd, 1008 (off_t)elf_getu64(swap, elfhdr.e_shoff), 1009 getu16(swap, elfhdr.e_shnum), 1010 (size_t)getu16(swap, elfhdr.e_shentsize), &flags) 1011 == -1) 1012 return -1; 1013 } 1014 return 1; 1015 } 1016 return 0; 1017} 1018#endif 1019