Back to index

php5  5.3.10
readelf.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) Christos Zoulas 2003.
00003  * All Rights Reserved.
00004  * 
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice immediately at the beginning of the file, without modification,
00010  *    this list of conditions, and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  *  
00015  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00016  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
00019  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00020  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00021  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00022  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00023  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00024  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00025  * SUCH DAMAGE.
00026  */
00027 #include "file.h"
00028 
00029 #ifndef lint
00030 FILE_RCSID("@(#)$File: readelf.c,v 1.81 2008/11/04 16:38:28 christos Exp $")
00031 #endif
00032 
00033 #ifdef BUILTIN_ELF
00034 #include <string.h>
00035 #include <ctype.h>
00036 #include <stdlib.h>
00037 #ifdef HAVE_UNISTD_H
00038 #include <unistd.h>
00039 #endif
00040 
00041 #include "readelf.h"
00042 #include "magic.h"
00043 
00044 #ifdef ELFCORE
00045 private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t,
00046     off_t, int *);
00047 #endif
00048 private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t,
00049     off_t, int *, int);
00050 private int doshn(struct magic_set *, int, int, int, off_t, int, size_t, int *,
00051     int);
00052 private size_t donote(struct magic_set *, unsigned char *, size_t, size_t, int,
00053     int, size_t, int *);
00054 
00055 #define       ELF_ALIGN(a)  ((((a) + align - 1) / align) * align)
00056 
00057 #define isquote(c) (strchr("'\"`", (c)) != NULL)
00058 
00059 private uint16_t getu16(int, uint16_t);
00060 private uint32_t getu32(int, uint32_t);
00061 private uint64_t getu64(int, uint64_t);
00062 
00063 private uint16_t
00064 getu16(int swap, uint16_t value)
00065 {
00066        union {
00067               uint16_t ui;
00068               char c[2];
00069        } retval, tmpval;
00070 
00071        if (swap) {
00072               tmpval.ui = value;
00073 
00074               retval.c[0] = tmpval.c[1];
00075               retval.c[1] = tmpval.c[0];
00076               
00077               return retval.ui;
00078        } else
00079               return value;
00080 }
00081 
00082 private uint32_t
00083 getu32(int swap, uint32_t value)
00084 {
00085        union {
00086               uint32_t ui;
00087               char c[4];
00088        } retval, tmpval;
00089 
00090        if (swap) {
00091               tmpval.ui = value;
00092 
00093               retval.c[0] = tmpval.c[3];
00094               retval.c[1] = tmpval.c[2];
00095               retval.c[2] = tmpval.c[1];
00096               retval.c[3] = tmpval.c[0];
00097               
00098               return retval.ui;
00099        } else
00100               return value;
00101 }
00102 
00103 private uint64_t
00104 getu64(int swap, uint64_t value)
00105 {
00106        union {
00107               uint64_t ui;
00108               char c[8];
00109        } retval, tmpval;
00110 
00111        if (swap) {
00112               tmpval.ui = value;
00113 
00114               retval.c[0] = tmpval.c[7];
00115               retval.c[1] = tmpval.c[6];
00116               retval.c[2] = tmpval.c[5];
00117               retval.c[3] = tmpval.c[4];
00118               retval.c[4] = tmpval.c[3];
00119               retval.c[5] = tmpval.c[2];
00120               retval.c[6] = tmpval.c[1];
00121               retval.c[7] = tmpval.c[0];
00122               
00123               return retval.ui;
00124        } else
00125               return value;
00126 }
00127 
00128 #define elf_getu16(swap, value) getu16(swap, value)
00129 #define elf_getu32(swap, value) getu32(swap, value)
00130 #ifdef USE_ARRAY_FOR_64BIT_TYPES
00131 # define elf_getu64(swap, array) \
00132        ((swap ? ((uint64_t)elf_getu32(swap, array[0])) << 32 : elf_getu32(swap, array[0])) + \
00133         (swap ? elf_getu32(swap, array[1]) : ((uint64_t)elf_getu32(swap, array[1]) << 32)))
00134 #else
00135 # define elf_getu64(swap, value) getu64(swap, value)
00136 #endif
00137 
00138 #define xsh_addr     (clazz == ELFCLASS32               \
00139                       ? (void *) &sh32                  \
00140                       : (void *) &sh64)
00141 #define xsh_sizeof   (clazz == ELFCLASS32               \
00142                       ? sizeof sh32                            \
00143                       : sizeof sh64)
00144 #define xsh_size     (clazz == ELFCLASS32               \
00145                       ? elf_getu32(swap, sh32.sh_size)  \
00146                       : elf_getu64(swap, sh64.sh_size))
00147 #define xsh_offset   (clazz == ELFCLASS32               \
00148                       ? elf_getu32(swap, sh32.sh_offset)       \
00149                       : elf_getu64(swap, sh64.sh_offset))
00150 #define xsh_type     (clazz == ELFCLASS32               \
00151                       ? elf_getu32(swap, sh32.sh_type)  \
00152                       : elf_getu32(swap, sh64.sh_type))
00153 #define xph_addr     (clazz == ELFCLASS32               \
00154                       ? (void *) &ph32                  \
00155                       : (void *) &ph64)
00156 #define xph_sizeof   (clazz == ELFCLASS32               \
00157                       ? sizeof ph32                            \
00158                       : sizeof ph64)
00159 #define xph_type     (clazz == ELFCLASS32               \
00160                       ? elf_getu32(swap, ph32.p_type)   \
00161                       : elf_getu32(swap, ph64.p_type))
00162 #define xph_offset   (off_t)(clazz == ELFCLASS32        \
00163                       ? elf_getu32(swap, ph32.p_offset) \
00164                       : elf_getu64(swap, ph64.p_offset))
00165 #define xph_align    (size_t)((clazz == ELFCLASS32             \
00166                       ? (off_t) (ph32.p_align ?         \
00167                          elf_getu32(swap, ph32.p_align) : 4) \
00168                       : (off_t) (ph64.p_align ?         \
00169                          elf_getu64(swap, ph64.p_align) : 4)))
00170 #define xph_filesz   (size_t)((clazz == ELFCLASS32             \
00171                       ? elf_getu32(swap, ph32.p_filesz) \
00172                       : elf_getu64(swap, ph64.p_filesz)))
00173 #define xnh_addr     (clazz == ELFCLASS32               \
00174                       ? (void *) &nh32                  \
00175                       : (void *) &nh64)
00176 #define xph_memsz    (size_t)((clazz == ELFCLASS32             \
00177                       ? elf_getu32(swap, ph32.p_memsz)  \
00178                       : elf_getu64(swap, ph64.p_memsz)))
00179 #define xnh_sizeof   (clazz == ELFCLASS32               \
00180                       ? sizeof nh32                            \
00181                       : sizeof nh64)
00182 #define xnh_type     (clazz == ELFCLASS32               \
00183                       ? elf_getu32(swap, nh32.n_type)   \
00184                       : elf_getu32(swap, nh64.n_type))
00185 #define xnh_namesz   (clazz == ELFCLASS32               \
00186                       ? elf_getu32(swap, nh32.n_namesz) \
00187                       : elf_getu32(swap, nh64.n_namesz))
00188 #define xnh_descsz   (clazz == ELFCLASS32               \
00189                       ? elf_getu32(swap, nh32.n_descsz) \
00190                       : elf_getu32(swap, nh64.n_descsz))
00191 #define prpsoffsets(i)      (clazz == ELFCLASS32               \
00192                       ? prpsoffsets32[i]                \
00193                       : prpsoffsets64[i])
00194 #define xcap_addr    (clazz == ELFCLASS32               \
00195                       ? (void *) &cap32                 \
00196                       : (void *) &cap64)
00197 #define xcap_sizeof  (clazz == ELFCLASS32               \
00198                       ? sizeof cap32                           \
00199                       : sizeof cap64)
00200 #define xcap_tag     (clazz == ELFCLASS32               \
00201                       ? elf_getu32(swap, cap32.c_tag)   \
00202                       : elf_getu64(swap, cap64.c_tag))
00203 #define xcap_val     (clazz == ELFCLASS32               \
00204                       ? elf_getu32(swap, cap32.c_un.c_val)     \
00205                       : elf_getu64(swap, cap64.c_un.c_val))
00206 
00207 #ifdef ELFCORE
00208 /*
00209  * Try larger offsets first to avoid false matches
00210  * from earlier data that happen to look like strings.
00211  */
00212 static const size_t  prpsoffsets32[] = {
00213 #ifdef USE_NT_PSINFO
00214        104,          /* SunOS 5.x (command line) */
00215        88,           /* SunOS 5.x (short name) */
00216 #endif /* USE_NT_PSINFO */
00217 
00218        100,          /* SunOS 5.x (command line) */
00219        84,           /* SunOS 5.x (short name) */
00220 
00221        44,           /* Linux (command line) */
00222        28,           /* Linux 2.0.36 (short name) */
00223 
00224        8,            /* FreeBSD */
00225 };
00226 
00227 static const size_t  prpsoffsets64[] = {
00228 #ifdef USE_NT_PSINFO
00229        152,          /* SunOS 5.x (command line) */
00230        136,          /* SunOS 5.x (short name) */
00231 #endif /* USE_NT_PSINFO */
00232 
00233        136,          /* SunOS 5.x, 64-bit (command line) */
00234        120,          /* SunOS 5.x, 64-bit (short name) */
00235 
00236        56,           /* Linux (command line) */
00237        40,             /* Linux (tested on core from 2.4.x, short name) */
00238 
00239        16,           /* FreeBSD, 64-bit */
00240 };
00241 
00242 #define       NOFFSETS32    (sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
00243 #define NOFFSETS64   (sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
00244 
00245 #define NOFFSETS     (clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
00246 
00247 /*
00248  * Look through the program headers of an executable image, searching
00249  * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or
00250  * "FreeBSD"; if one is found, try looking in various places in its
00251  * contents for a 16-character string containing only printable
00252  * characters - if found, that string should be the name of the program
00253  * that dropped core.  Note: right after that 16-character string is,
00254  * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and
00255  * Linux, a longer string (80 characters, in 5.x, probably other
00256  * SVR4-flavored systems, and Linux) containing the start of the
00257  * command line for that program.
00258  *
00259  * SunOS 5.x core files contain two PT_NOTE sections, with the types
00260  * NT_PRPSINFO (old) and NT_PSINFO (new).  These structs contain the
00261  * same info about the command name and command line, so it probably
00262  * isn't worthwhile to look for NT_PSINFO, but the offsets are provided
00263  * above (see USE_NT_PSINFO), in case we ever decide to do so.  The
00264  * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent;
00265  * the SunOS 5.x file command relies on this (and prefers the latter).
00266  *
00267  * The signal number probably appears in a section of type NT_PRSTATUS,
00268  * but that's also rather OS-dependent, in ways that are harder to
00269  * dissect with heuristics, so I'm not bothering with the signal number.
00270  * (I suppose the signal number could be of interest in situations where
00271  * you don't have the binary of the program that dropped core; if you
00272  * *do* have that binary, the debugger will probably tell you what
00273  * signal it was.)
00274  */
00275 
00276 #define       OS_STYLE_SVR4        0
00277 #define       OS_STYLE_FREEBSD     1
00278 #define       OS_STYLE_NETBSD             2
00279 
00280 private const char os_style_names[][8] = {
00281        "SVR4",
00282        "FreeBSD",
00283        "NetBSD",
00284 };
00285 
00286 #define FLAGS_DID_CORE             1
00287 #define FLAGS_DID_NOTE             2
00288 #define FLAGS_DID_CORE_STYLE       4
00289 
00290 private int
00291 dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
00292     int num, size_t size, off_t fsize, int *flags)
00293 {
00294        Elf32_Phdr ph32;
00295        Elf64_Phdr ph64;
00296        size_t offset;
00297        unsigned char nbuf[BUFSIZ];
00298        ssize_t bufsize;
00299        off_t savedoffset;
00300        struct stat st;
00301 
00302        if (fstat(fd, &st) < 0) {
00303               file_badread(ms);
00304               return -1;
00305        }
00306 
00307        if (size != xph_sizeof) {
00308               if (file_printf(ms, ", corrupted program header size") == -1)
00309                      return -1;
00310               return 0;
00311        }
00312 
00313        /*
00314         * Loop through all the program headers.
00315         */
00316        for ( ; num; num--) {
00317               if ((savedoffset = lseek(fd, off, SEEK_SET)) == (off_t)-1) {
00318                      file_badseek(ms);
00319                      return -1;
00320               }
00321               if (read(fd, xph_addr, xph_sizeof) == -1) {
00322                      file_badread(ms);
00323                      return -1;
00324               }
00325               if (xph_offset > fsize) {
00326                      if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
00327                             file_badseek(ms);
00328                             return -1;
00329                      }
00330                      continue;
00331               }
00332 
00333               off += size;
00334               if (xph_type != PT_NOTE)
00335                      continue;
00336 
00337               /*
00338                * This is a PT_NOTE section; loop through all the notes
00339                * in the section.
00340                */
00341               if (lseek(fd, xph_offset, SEEK_SET) == (off_t)-1) {
00342                      file_badseek(ms);
00343                      return -1;
00344               }
00345               bufsize = read(fd, nbuf,
00346                   ((xph_filesz < sizeof(nbuf)) ? xph_filesz : sizeof(nbuf)));
00347               if (bufsize == -1) {
00348                      file_badread(ms);
00349                      return -1;
00350               }
00351               offset = 0;
00352               for (;;) {
00353                      if (offset >= (size_t)bufsize)
00354                             break;
00355                      offset = donote(ms, nbuf, offset, (size_t)bufsize,
00356                          clazz, swap, 4, flags);
00357                      if (offset == 0)
00358                             break;
00359 
00360               }
00361        }
00362        return 0;
00363 }
00364 #endif
00365 
00366 private size_t
00367 donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size,
00368     int clazz, int swap, size_t align, int *flags)
00369 {
00370        Elf32_Nhdr nh32;
00371        Elf64_Nhdr nh64;
00372        size_t noff, doff;
00373 #ifdef ELFCORE
00374        int os_style = -1;
00375 #endif
00376        uint32_t namesz, descsz;
00377 
00378        (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
00379        offset += xnh_sizeof;
00380 
00381        namesz = xnh_namesz;
00382        descsz = xnh_descsz;
00383        if ((namesz == 0) && (descsz == 0)) {
00384               /*
00385                * We're out of note headers.
00386                */
00387               return (offset >= size) ? offset : size;
00388        }
00389 
00390        if (namesz & 0x80000000) {
00391            (void)file_printf(ms, ", bad note name size 0x%lx",
00392               (unsigned long)namesz);
00393            return offset;
00394        }
00395 
00396        if (descsz & 0x80000000) {
00397            (void)file_printf(ms, ", bad note description size 0x%lx",
00398               (unsigned long)descsz);
00399            return offset;
00400        }
00401 
00402 
00403        noff = offset;
00404        doff = ELF_ALIGN(offset + namesz);
00405 
00406        if (offset + namesz > size) {
00407               /*
00408                * We're past the end of the buffer.
00409                */
00410               return doff;
00411        }
00412 
00413        offset = ELF_ALIGN(doff + descsz);
00414        if (doff + descsz > size) {
00415               /*
00416                * We're past the end of the buffer.
00417                */
00418               return (offset >= size) ? offset : size;
00419        }
00420 
00421        if (*flags & FLAGS_DID_NOTE)
00422               goto core;
00423 
00424        if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
00425            xnh_type == NT_GNU_VERSION && descsz == 16) {
00426               uint32_t desc[4];
00427               (void)memcpy(desc, &nbuf[doff], sizeof(desc));
00428 
00429               if (file_printf(ms, ", for GNU/") == -1)
00430                      return size;
00431               switch (elf_getu32(swap, desc[0])) {
00432               case GNU_OS_LINUX:
00433                      if (file_printf(ms, "Linux") == -1)
00434                             return size;
00435                      break;
00436               case GNU_OS_HURD:
00437                      if (file_printf(ms, "Hurd") == -1)
00438                             return size;
00439                      break;
00440               case GNU_OS_SOLARIS:
00441                      if (file_printf(ms, "Solaris") == -1)
00442                             return size;
00443                      break;
00444               case GNU_OS_KFREEBSD:
00445                      if (file_printf(ms, "kFreeBSD") == -1)
00446                             return size;
00447                      break;
00448               case GNU_OS_KNETBSD:
00449                      if (file_printf(ms, "kNetBSD") == -1)
00450                             return size;
00451                      break;
00452               default:
00453                      if (file_printf(ms, "<unknown>") == -1)
00454                             return size; 
00455               }
00456               if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
00457                   elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1)
00458                      return size;
00459               *flags |= FLAGS_DID_NOTE;
00460               return size;
00461        }
00462 
00463        if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 &&
00464            xnh_type == NT_NETBSD_VERSION && descsz == 4) {
00465               uint32_t desc;
00466               (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
00467               desc = elf_getu32(swap, desc);
00468 
00469               if (file_printf(ms, ", for NetBSD") == -1)
00470                      return size;
00471               /*
00472                * The version number used to be stuck as 199905, and was thus
00473                * basically content-free.  Newer versions of NetBSD have fixed
00474                * this and now use the encoding of __NetBSD_Version__:
00475                *
00476                *     MMmmrrpp00
00477                *
00478                * M = major version
00479                * m = minor version
00480                * r = release ["",A-Z,Z[A-Z] but numeric]
00481                * p = patchlevel
00482                */
00483               if (desc > 100000000U) {
00484                      uint32_t ver_patch = (desc / 100) % 100;
00485                      uint32_t ver_rel = (desc / 10000) % 100;
00486                      uint32_t ver_min = (desc / 1000000) % 100;
00487                      uint32_t ver_maj = desc / 100000000;
00488 
00489                      if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1)
00490                             return size;
00491                      if (ver_rel == 0 && ver_patch != 0) {
00492                             if (file_printf(ms, ".%u", ver_patch) == -1)
00493                                    return size;
00494                      } else if (ver_rel != 0) {
00495                             while (ver_rel > 26) {
00496                                    if (file_printf(ms, "Z") == -1)
00497                                           return size;
00498                                    ver_rel -= 26;
00499                             }
00500                             if (file_printf(ms, "%c", 'A' + ver_rel - 1)
00501                                 == -1)
00502                                    return size;
00503                      }
00504               }
00505               *flags |= FLAGS_DID_NOTE;
00506               return size;
00507        }
00508 
00509        if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0 &&
00510            xnh_type == NT_FREEBSD_VERSION && descsz == 4) {
00511               uint32_t desc;
00512               (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
00513               desc = elf_getu32(swap, desc);
00514               if (file_printf(ms, ", for FreeBSD") == -1)
00515                      return size;
00516 
00517               /*
00518                * Contents is __FreeBSD_version, whose relation to OS
00519                * versions is defined by a huge table in the Porter's
00520                * Handbook.  This is the general scheme:
00521                * 
00522                * Releases:
00523                *     Mmp000 (before 4.10)
00524                *     Mmi0p0 (before 5.0)
00525                *     Mmm0p0
00526                * 
00527                * Development branches:
00528                *     Mmpxxx (before 4.6)
00529                *     Mmp1xx (before 4.10)
00530                *     Mmi1xx (before 5.0)
00531                *     M000xx (pre-M.0)
00532                *     Mmm1xx
00533                * 
00534                * M = major version
00535                * m = minor version
00536                * i = minor version increment (491000 -> 4.10)
00537                * p = patchlevel
00538                * x = revision
00539                * 
00540                * The first release of FreeBSD to use ELF by default
00541                * was version 3.0.
00542                */
00543               if (desc == 460002) {
00544                      if (file_printf(ms, " 4.6.2") == -1)
00545                             return size;
00546               } else if (desc < 460100) {
00547                      if (file_printf(ms, " %d.%d", desc / 100000,
00548                          desc / 10000 % 10) == -1)
00549                             return size;
00550                      if (desc / 1000 % 10 > 0)
00551                             if (file_printf(ms, ".%d", desc / 1000 % 10)
00552                                 == -1)
00553                                    return size;
00554                      if ((desc % 1000 > 0) || (desc % 100000 == 0))
00555                             if (file_printf(ms, " (%d)", desc) == -1)
00556                                    return size;
00557               } else if (desc < 500000) {
00558                      if (file_printf(ms, " %d.%d", desc / 100000,
00559                          desc / 10000 % 10 + desc / 1000 % 10) == -1)
00560                             return size;
00561                      if (desc / 100 % 10 > 0) {
00562                             if (file_printf(ms, " (%d)", desc) == -1)
00563                                    return size;
00564                      } else if (desc / 10 % 10 > 0) {
00565                             if (file_printf(ms, ".%d", desc / 10 % 10)
00566                                 == -1)
00567                                    return size;
00568                      }
00569               } else {
00570                      if (file_printf(ms, " %d.%d", desc / 100000,
00571                          desc / 1000 % 100) == -1)
00572                             return size;
00573                      if ((desc / 100 % 10 > 0) ||
00574                          (desc % 100000 / 100 == 0)) {
00575                             if (file_printf(ms, " (%d)", desc) == -1)
00576                                    return size;
00577                      } else if (desc / 10 % 10 > 0) {
00578                             if (file_printf(ms, ".%d", desc / 10 % 10)
00579                                 == -1)
00580                                    return size;
00581                      }
00582               }
00583               *flags |= FLAGS_DID_NOTE;
00584               return size;
00585        }
00586 
00587        if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
00588            xnh_type == NT_OPENBSD_VERSION && descsz == 4) {
00589               if (file_printf(ms, ", for OpenBSD") == -1)
00590                      return size;
00591               /* Content of note is always 0 */
00592               *flags |= FLAGS_DID_NOTE;
00593               return size;
00594        }
00595 
00596        if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
00597            xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) {
00598               uint32_t desc;
00599               if (file_printf(ms, ", for DragonFly") == -1)
00600                      return size;
00601               (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
00602               desc = elf_getu32(swap, desc);
00603               if (file_printf(ms, " %d.%d.%d", desc / 100000,
00604                   desc / 10000 % 10, desc % 10000) == -1)
00605                      return size;
00606               *flags |= FLAGS_DID_NOTE;
00607               return size;
00608        }
00609 
00610 core:
00611        /*
00612         * Sigh.  The 2.0.36 kernel in Debian 2.1, at
00613         * least, doesn't correctly implement name
00614         * sections, in core dumps, as specified by
00615         * the "Program Linking" section of "UNIX(R) System
00616         * V Release 4 Programmer's Guide: ANSI C and
00617         * Programming Support Tools", because my copy
00618         * clearly says "The first 'namesz' bytes in 'name'
00619         * contain a *null-terminated* [emphasis mine]
00620         * character representation of the entry's owner
00621         * or originator", but the 2.0.36 kernel code
00622         * doesn't include the terminating null in the
00623         * name....
00624         */
00625        if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) ||
00626            (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) {
00627               os_style = OS_STYLE_SVR4;
00628        } 
00629 
00630        if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) {
00631               os_style = OS_STYLE_FREEBSD;
00632        }
00633 
00634        if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11)
00635            == 0)) {
00636               os_style = OS_STYLE_NETBSD;
00637        }
00638 
00639 #ifdef ELFCORE
00640        if ((*flags & FLAGS_DID_CORE) != 0)
00641               return size;
00642 
00643        if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
00644               if (file_printf(ms, ", %s-style", os_style_names[os_style])
00645                   == -1)
00646                      return size;
00647               *flags |= FLAGS_DID_CORE_STYLE;
00648        }
00649 
00650        switch (os_style) {
00651        case OS_STYLE_NETBSD:
00652               if (xnh_type == NT_NETBSD_CORE_PROCINFO) {
00653                      uint32_t signo;
00654                      /*
00655                       * Extract the program name.  It is at
00656                       * offset 0x7c, and is up to 32-bytes,
00657                       * including the terminating NUL.
00658                       */
00659                      if (file_printf(ms, ", from '%.31s'",
00660                          &nbuf[doff + 0x7c]) == -1)
00661                             return size;
00662                      
00663                      /*
00664                       * Extract the signal number.  It is at
00665                       * offset 0x08.
00666                       */
00667                      (void)memcpy(&signo, &nbuf[doff + 0x08],
00668                          sizeof(signo));
00669                      if (file_printf(ms, " (signal %u)",
00670                          elf_getu32(swap, signo)) == -1)
00671                             return size;
00672                      *flags |= FLAGS_DID_CORE;
00673                      return size;
00674               }
00675               break;
00676 
00677        default:
00678               if (xnh_type == NT_PRPSINFO) {
00679                      size_t i, j;
00680                      unsigned char c;
00681                      /*
00682                       * Extract the program name.  We assume
00683                       * it to be 16 characters (that's what it
00684                       * is in SunOS 5.x and Linux).
00685                       *
00686                       * Unfortunately, it's at a different offset
00687                       * in various OSes, so try multiple offsets.
00688                       * If the characters aren't all printable,
00689                       * reject it.
00690                       */
00691                      for (i = 0; i < NOFFSETS; i++) {
00692                             unsigned char *cname, *cp;
00693                             size_t reloffset = prpsoffsets(i);
00694                             size_t noffset = doff + reloffset;
00695                             for (j = 0; j < 16; j++, noffset++,
00696                                 reloffset++) {
00697                                    /*
00698                                     * Make sure we're not past
00699                                     * the end of the buffer; if
00700                                     * we are, just give up.
00701                                     */
00702                                    if (noffset >= size)
00703                                           goto tryanother;
00704 
00705                                    /*
00706                                     * Make sure we're not past
00707                                     * the end of the contents;
00708                                     * if we are, this obviously
00709                                     * isn't the right offset.
00710                                     */
00711                                    if (reloffset >= descsz)
00712                                           goto tryanother;
00713 
00714                                    c = nbuf[noffset];
00715                                    if (c == '\0') {
00716                                           /*
00717                                            * A '\0' at the
00718                                            * beginning is
00719                                            * obviously wrong.
00720                                            * Any other '\0'
00721                                            * means we're done.
00722                                            */
00723                                           if (j == 0)
00724                                                  goto tryanother;
00725                                           else
00726                                                  break;
00727                                    } else {
00728                                           /*
00729                                            * A nonprintable
00730                                            * character is also
00731                                            * wrong.
00732                                            */
00733                                           if (!isprint(c) || isquote(c))
00734                                                  goto tryanother;
00735                                    }
00736                             }
00737                             /*
00738                              * Well, that worked.
00739                              */
00740                             cname = (unsigned char *)
00741                                 &nbuf[doff + prpsoffsets(i)];
00742                             for (cp = cname; *cp && isprint(*cp); cp++)
00743                                    continue;
00744                             /*
00745                              * Linux apparently appends a space at the end
00746                              * of the command line: remove it.
00747                              */
00748                             while (cp > cname && isspace(cp[-1]))
00749                                    cp--;
00750                             if (file_printf(ms, ", from '%.*s'",
00751                                 (int)(cp - cname), cname) == -1)
00752                                    return size;
00753                             *flags |= FLAGS_DID_CORE;
00754                             return size;
00755 
00756                      tryanother:
00757                             ;
00758                      }
00759               }
00760               break;
00761        }
00762 #endif
00763        return offset;
00764 }
00765 
00766 /* SunOS 5.x hardware capability descriptions */
00767 typedef struct cap_desc {
00768        uint64_t cd_mask;
00769        const char *cd_name;
00770 } cap_desc_t;
00771 
00772 static const cap_desc_t cap_desc_sparc[] = {
00773        { AV_SPARC_MUL32,           "MUL32" },
00774        { AV_SPARC_DIV32,           "DIV32" },
00775        { AV_SPARC_FSMULD,          "FSMULD" },
00776        { AV_SPARC_V8PLUS,          "V8PLUS" },
00777        { AV_SPARC_POPC,            "POPC" },
00778        { AV_SPARC_VIS,                    "VIS" },
00779        { AV_SPARC_VIS2,            "VIS2" },
00780        { AV_SPARC_ASI_BLK_INIT,    "ASI_BLK_INIT" },
00781        { AV_SPARC_FMAF,            "FMAF" },
00782        { AV_SPARC_FJFMAU,          "FJFMAU" },
00783        { AV_SPARC_IMA,                    "IMA" },
00784        { 0, NULL }
00785 };
00786 
00787 static const cap_desc_t cap_desc_386[] = {
00788        { AV_386_FPU,               "FPU" },
00789        { AV_386_TSC,               "TSC" },
00790        { AV_386_CX8,               "CX8" },
00791        { AV_386_SEP,               "SEP" },
00792        { AV_386_AMD_SYSC,          "AMD_SYSC" },
00793        { AV_386_CMOV,                     "CMOV" },
00794        { AV_386_MMX,               "MMX" },
00795        { AV_386_AMD_MMX,           "AMD_MMX" },
00796        { AV_386_AMD_3DNow,         "AMD_3DNow" },
00797        { AV_386_AMD_3DNowx,        "AMD_3DNowx" },
00798        { AV_386_FXSR,                     "FXSR" },
00799        { AV_386_SSE,               "SSE" },
00800        { AV_386_SSE2,                     "SSE2" },
00801        { AV_386_PAUSE,                    "PAUSE" },
00802        { AV_386_SSE3,                     "SSE3" },
00803        { AV_386_MON,               "MON" },
00804        { AV_386_CX16,                     "CX16" },
00805        { AV_386_AHF,               "AHF" },
00806        { AV_386_TSCP,                     "TSCP" },
00807        { AV_386_AMD_SSE4A,         "AMD_SSE4A" },
00808        { AV_386_POPCNT,            "POPCNT" },
00809        { AV_386_AMD_LZCNT,         "AMD_LZCNT" },
00810        { AV_386_SSSE3,                    "SSSE3" },
00811        { AV_386_SSE4_1,            "SSE4.1" },
00812        { AV_386_SSE4_2,            "SSE4.2" },
00813        { 0, NULL }
00814 };
00815 
00816 private int
00817 doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
00818     size_t size, int *flags, int mach)
00819 {
00820        Elf32_Shdr sh32;
00821        Elf64_Shdr sh64;
00822        int stripped = 1;
00823        void *nbuf;
00824        off_t noff;
00825        uint64_t cap_hw1 = 0;       /* SunOS 5.x hardware capabilites */
00826        uint64_t cap_sf1 = 0;       /* SunOS 5.x software capabilites */
00827 
00828        if (size != xsh_sizeof) {
00829               if (file_printf(ms, ", corrupted section header size") == -1)
00830                      return -1;
00831               return 0;
00832        }
00833 
00834        if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
00835               file_badseek(ms);
00836               return -1;
00837        }
00838 
00839        for ( ; num; num--) {
00840               if (read(fd, xsh_addr, xsh_sizeof) == -1) {
00841                      file_badread(ms);
00842                      return -1;
00843               }
00844               switch (xsh_type) {
00845               case SHT_SYMTAB:
00846 #if 0
00847               case SHT_DYNSYM:
00848 #endif
00849                      stripped = 0;
00850                      break;
00851               case SHT_NOTE:
00852                      if ((off = lseek(fd, (off_t)0, SEEK_CUR)) ==
00853                          (off_t)-1) {
00854                             file_badread(ms);
00855                             return -1;
00856                      }
00857                      nbuf = emalloc((size_t)xsh_size);
00858                      if ((noff = lseek(fd, (off_t)xsh_offset, SEEK_SET)) ==
00859                          (off_t)-1) {
00860                             file_badread(ms);
00861                             efree(nbuf);
00862                             return -1;
00863                      }
00864                      if (read(fd, nbuf, (size_t)xsh_size) !=
00865                          (ssize_t)xsh_size) {
00866                             efree(nbuf);
00867                             file_badread(ms);
00868                             return -1;
00869                      }
00870 
00871                      noff = 0;
00872                      for (;;) {
00873                             if (noff >= (off_t)xsh_size)
00874                                    break;
00875                             noff = donote(ms, nbuf, (size_t)noff,
00876                                 (size_t)xsh_size, clazz, swap, 4,
00877                                 flags);
00878                             if (noff == 0)
00879                                    break;
00880                      }
00881                      if ((lseek(fd, off, SEEK_SET)) == (off_t)-1) {
00882                             efree(nbuf);
00883                             file_badread(ms);
00884                             return -1;
00885                      }
00886                      efree(nbuf);
00887                      break;
00888               case SHT_SUNW_cap:
00889                   {
00890                      off_t coff;
00891                      if ((off = lseek(fd, (off_t)0, SEEK_CUR)) ==
00892                          (off_t)-1) {
00893                             file_badread(ms);
00894                             return -1;
00895                      }
00896                      if (lseek(fd, (off_t)xsh_offset, SEEK_SET) ==
00897                          (off_t)-1) {
00898                             file_badread(ms);
00899                             return -1;
00900                      }
00901                      coff = 0;
00902                      for (;;) {
00903                             Elf32_Cap cap32;
00904                             Elf64_Cap cap64;
00905                             char cbuf[/*CONSTCOND*/
00906                                 MAX(sizeof cap32, sizeof cap64)];
00907                             if ((coff += xcap_sizeof) >= (off_t)xsh_size)
00908                                    break;
00909                             if (read(fd, cbuf, (size_t)xcap_sizeof) !=
00910                                 (ssize_t)xcap_sizeof) {
00911                                    file_badread(ms);
00912                                    return -1;
00913                             }
00914                             (void)memcpy(xcap_addr, cbuf, xcap_sizeof);
00915                             switch (xcap_tag) {
00916                             case CA_SUNW_NULL:
00917                                    break;
00918                             case CA_SUNW_HW_1:
00919                                    cap_hw1 |= xcap_val;
00920                                    break;
00921                             case CA_SUNW_SF_1:
00922                                    cap_sf1 |= xcap_val;
00923                                    break;
00924                             default:
00925                                    if (file_printf(ms,
00926                                        ", with unknown capability "
00927                                        "0x%llx = 0x%llx",
00928                                        (unsigned long long)xcap_tag,
00929                                        (unsigned long long)xcap_val) == -1)
00930                                           return -1;
00931                                    break;
00932                             }
00933                      }
00934                      if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
00935                             file_badread(ms);
00936                             return -1;
00937                      }
00938                      break;
00939                   }
00940               }
00941        }
00942        if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
00943               return -1;
00944        if (cap_hw1) {
00945               const cap_desc_t *cdp;
00946               switch (mach) {
00947               case EM_SPARC:
00948               case EM_SPARC32PLUS:
00949               case EM_SPARCV9:
00950                      cdp = cap_desc_sparc;
00951                      break;
00952               case EM_386:
00953               case EM_IA_64:
00954               case EM_AMD64:
00955                      cdp = cap_desc_386;
00956                      break;
00957               default:
00958                      cdp = NULL;
00959                      break;
00960               }
00961               if (file_printf(ms, ", uses") == -1)
00962                      return -1;
00963               if (cdp) {
00964                      while (cdp->cd_name) {
00965                             if (cap_hw1 & cdp->cd_mask) {
00966                                    if (file_printf(ms,
00967                                        " %s", cdp->cd_name) == -1)
00968                                           return -1;
00969                                    cap_hw1 &= ~cdp->cd_mask;
00970                             }
00971                             ++cdp;
00972                      }
00973                      if (cap_hw1)
00974                             if (file_printf(ms,
00975                                 " unknown hardware capability 0x%llx",
00976                                 (unsigned long long)cap_hw1) == -1)
00977                                    return -1;
00978               } else {
00979                      if (file_printf(ms,
00980                          " hardware capability 0x%llx",
00981                          (unsigned long long)cap_hw1) == -1)
00982                             return -1;
00983               }
00984        }
00985        if (cap_sf1) {
00986               if (cap_sf1 & SF1_SUNW_FPUSED) {
00987                      if (file_printf(ms,
00988                          (cap_sf1 & SF1_SUNW_FPKNWN)
00989                          ? ", uses frame pointer"
00990                          : ", not known to use frame pointer") == -1)
00991                             return -1;
00992               }
00993               cap_sf1 &= ~SF1_SUNW_MASK;
00994               if (cap_sf1)
00995                      if (file_printf(ms,
00996                          ", with unknown software capability 0x%llx",
00997                          (unsigned long long)cap_sf1) == -1)
00998                             return -1;
00999        }
01000        return 0;
01001 }
01002 
01003 /*
01004  * Look through the program headers of an executable image, searching
01005  * for a PT_INTERP section; if one is found, it's dynamically linked,
01006  * otherwise it's statically linked.
01007  */
01008 private int
01009 dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
01010     int num, size_t size, off_t fsize, int *flags, int sh_num)
01011 {
01012        Elf32_Phdr ph32;
01013        Elf64_Phdr ph64;
01014        const char *linking_style = "statically";
01015        const char *shared_libraries = "";
01016        unsigned char nbuf[BUFSIZ];
01017        int bufsize;
01018        size_t offset, align;
01019        off_t savedoffset = (off_t)-1;
01020        struct stat st;
01021 
01022        if (fstat(fd, &st) < 0) {
01023               file_badread(ms);
01024               return -1;
01025        }
01026        
01027        if (size != xph_sizeof) {
01028               if (file_printf(ms, ", corrupted program header size") == -1)
01029                      return -1;
01030               return 0;
01031        }
01032 
01033        if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
01034               file_badseek(ms);
01035               return -1;
01036        }
01037 
01038        for ( ; num; num--) {
01039               if (read(fd, xph_addr, xph_sizeof) == -1) {
01040                      file_badread(ms);
01041                      return -1;
01042               }
01043               if (xph_offset > st.st_size && savedoffset != (off_t)-1) {
01044                      if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
01045                             file_badseek(ms);
01046                             return -1;
01047                      }
01048                      continue;
01049               }
01050 
01051               if ((savedoffset = lseek(fd, (off_t)0, SEEK_CUR)) == (off_t)-1) {
01052                      file_badseek(ms);
01053                      return -1;
01054               }
01055 
01056               if (xph_offset > fsize) {
01057                      if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
01058                             file_badseek(ms);
01059                             return -1;
01060                      }
01061                      continue;
01062               }
01063 
01064               switch (xph_type) {
01065               case PT_DYNAMIC:
01066                      linking_style = "dynamically";
01067                      break;
01068               case PT_INTERP:
01069                      shared_libraries = " (uses shared libs)";
01070                      break;
01071               case PT_NOTE:
01072                      if ((align = xph_align) & 0x80000000) {
01073                             if (file_printf(ms, 
01074                                 ", invalid note alignment 0x%lx",
01075                                 (unsigned long)align) == -1)
01076                                    return -1;
01077                             align = 4;
01078                      }
01079                      if (sh_num)
01080                             break;
01081                      /*
01082                       * This is a PT_NOTE section; loop through all the notes
01083                       * in the section.
01084                       */
01085                      if (lseek(fd, xph_offset, SEEK_SET)
01086                          == (off_t)-1) {
01087                             file_badseek(ms);
01088                             return -1;
01089                      }
01090                      bufsize = read(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ?
01091                          xph_filesz : sizeof(nbuf)));
01092                      if (bufsize == -1) {
01093                             file_badread(ms);
01094                             return -1;
01095                      }
01096                      offset = 0;
01097                      for (;;) {
01098                             if (offset >= (size_t)bufsize)
01099                                    break;
01100                             offset = donote(ms, nbuf, offset,
01101                                 (size_t)bufsize, clazz, swap, align,
01102                                 flags);
01103                             if (offset == 0)
01104                                    break;
01105                      }
01106                      if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
01107                             file_badseek(ms);
01108                             return -1;
01109                      }
01110                      break;
01111               default:
01112                      break;
01113               }
01114        }
01115        if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries)
01116            == -1)
01117            return -1;
01118        return 0;
01119 }
01120 
01121 
01122 protected int
01123 file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
01124     size_t nbytes)
01125 {
01126        union {
01127               int32_t l;
01128               char c[sizeof (int32_t)];
01129        } u;
01130        int clazz;
01131        int swap;
01132        struct stat st;
01133        off_t fsize;
01134        int flags = 0;
01135        Elf32_Ehdr elf32hdr;
01136        Elf64_Ehdr elf64hdr;
01137        uint16_t type;
01138 
01139        if (ms->flags & (MAGIC_MIME|MAGIC_APPLE))
01140               return 0;
01141        /*
01142         * ELF executables have multiple section headers in arbitrary
01143         * file locations and thus file(1) cannot determine it from easily.
01144         * Instead we traverse thru all section headers until a symbol table
01145         * one is found or else the binary is stripped.
01146         * Return immediately if it's not ELF (so we avoid pipe2file unless needed).
01147         */
01148        if (buf[EI_MAG0] != ELFMAG0
01149            || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
01150            || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
01151               return 0;
01152 
01153        /*
01154         * If we cannot seek, it must be a pipe, socket or fifo.
01155         */
01156        if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE))
01157               fd = file_pipe2file(ms, fd, buf, nbytes);
01158 
01159        if (fstat(fd, &st) == -1) {
01160               file_badread(ms);
01161               return -1;
01162        }
01163        fsize = st.st_size;
01164 
01165        clazz = buf[EI_CLASS];
01166 
01167        switch (clazz) {
01168        case ELFCLASS32:
01169 #undef elf_getu
01170 #define elf_getu(a, b)      elf_getu32(a, b)
01171 #undef elfhdr
01172 #define elfhdr elf32hdr
01173 #include "elfclass.h"
01174        case ELFCLASS64:
01175 #undef elf_getu
01176 #define elf_getu(a, b)      elf_getu64(a, b)
01177 #undef elfhdr
01178 #define elfhdr elf64hdr
01179 #include "elfclass.h"
01180        default:
01181            if (file_printf(ms, ", unknown class %d", clazz) == -1)
01182                   return -1;
01183            break;
01184        }
01185        return 0;
01186 }
01187 #endif