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