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