file/src/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 #ifdef BUILTIN_ELF
00030 #include <string.h>
00031 #include <ctype.h>
00032 #include <stdlib.h>
00033 #ifdef HAVE_UNISTD_H
00034 #include <unistd.h>
00035 #endif
00036 
00037 #include "readelf.h"
00038 
00039 #ifndef lint
00040 FILE_RCSID("@(#)$File: readelf.c,v 1.63 2007/01/16 14:56:45 ljt Exp $")
00041 #endif
00042 
00043 #ifdef  ELFCORE
00044 private int dophn_core(struct magic_set *ms, int class, int swap, int fd,
00045     off_t off, int num, size_t size, off_t fsize, int *flags)
00046         /*@modifies ms, *flags @*/;
00047 #endif
00048 private int dophn_exec(struct magic_set *ms, int class, int swap, int fd,
00049     off_t off, int num, size_t size, off_t fsize, int *flags, int sh_num)
00050         /*@modifies ms, *flags @*/;
00051 private int doshn(struct magic_set *ms, int class, int swap, int fd, off_t off,
00052     int num, size_t size, int *flags)
00053         /*@modifies ms, *flags @*/;
00054 private size_t donote(struct magic_set *ms, unsigned char *nbuf, size_t offset,
00055     size_t size, int class, int swap, size_t align, int *flags)
00056         /*@modifies ms, *flags @*/;
00057 
00058 #define ELF_ALIGN(a)    ((((a) + align - 1) / align) * align)
00059 
00060 #define isquote(c) (strchr("'\"`", (c)) != NULL)
00061 
00062 private uint16_t getu16(int, uint16_t)
00063         /*@*/;
00064 private uint32_t getu32(int, uint32_t)
00065         /*@*/;
00066 private uint64_t getu64(int, uint64_t)
00067         /*@*/;
00068 
00069 private uint16_t
00070 getu16(int swap, uint16_t value)
00071 {
00072         union {
00073                 uint16_t ui;
00074                 char c[2];
00075         } retval, tmpval;
00076 
00077         if (swap) {
00078                 tmpval.ui = value;
00079 
00080                 retval.c[0] = tmpval.c[1];
00081                 retval.c[1] = tmpval.c[0];
00082                 
00083                 return retval.ui;
00084         } else
00085                 return value;
00086 }
00087 
00088 private uint32_t
00089 getu32(int swap, uint32_t value)
00090 {
00091         union {
00092                 uint32_t ui;
00093                 char c[4];
00094         } retval, tmpval;
00095 
00096         if (swap) {
00097                 tmpval.ui = value;
00098 
00099                 retval.c[0] = tmpval.c[3];
00100                 retval.c[1] = tmpval.c[2];
00101                 retval.c[2] = tmpval.c[1];
00102                 retval.c[3] = tmpval.c[0];
00103                 
00104                 return retval.ui;
00105         } else
00106                 return value;
00107 }
00108 
00109 private uint64_t
00110 getu64(int swap, uint64_t value)
00111 {
00112         union {
00113                 uint64_t ui;
00114                 char c[8];
00115         } retval, tmpval;
00116 
00117         if (swap) {
00118                 tmpval.ui = value;
00119 
00120                 retval.c[0] = tmpval.c[7];
00121                 retval.c[1] = tmpval.c[6];
00122                 retval.c[2] = tmpval.c[5];
00123                 retval.c[3] = tmpval.c[4];
00124                 retval.c[4] = tmpval.c[3];
00125                 retval.c[5] = tmpval.c[2];
00126                 retval.c[6] = tmpval.c[1];
00127                 retval.c[7] = tmpval.c[0];
00128                 
00129                 return retval.ui;
00130         } else
00131                 return value;
00132 }
00133 
00134 #ifdef USE_ARRAY_FOR_64BIT_TYPES
00135 # define elf_getu64(swap, array) \
00136         ((swap ? ((uint64_t)getu32(swap, array[0])) << 32 : getu32(swap, array[0])) + \
00137          (swap ? getu32(swap, array[1]) : ((uint64_t)getu32(swap, array[1]) << 32)))
00138 #else
00139 # define elf_getu64(swap, value) getu64(swap, value)
00140 #endif
00141 
00142 #define xsh_addr        (class == ELFCLASS32            \
00143                          ? (void *) &sh32               \
00144                          : (void *) &sh64)
00145 #define xsh_sizeof      (class == ELFCLASS32            \
00146                          ? sizeof sh32                  \
00147                          : sizeof sh64)
00148 #define xsh_size        (class == ELFCLASS32            \
00149                          ? getu32(swap, sh32.sh_size)   \
00150                          : getu64(swap, sh64.sh_size))
00151 #define xsh_offset      (class == ELFCLASS32            \
00152                          ? getu32(swap, sh32.sh_offset) \
00153                          : getu64(swap, sh64.sh_offset))
00154 #define xsh_type        (class == ELFCLASS32            \
00155                          ? getu32(swap, sh32.sh_type)   \
00156                          : getu32(swap, sh64.sh_type))
00157 #define xph_addr        (class == ELFCLASS32            \
00158                          ? (void *) &ph32               \
00159                          : (void *) &ph64)
00160 #define xph_sizeof      (class == ELFCLASS32            \
00161                          ? sizeof ph32                  \
00162                          : sizeof ph64)
00163 #define xph_type        (class == ELFCLASS32            \
00164                          ? getu32(swap, ph32.p_type)    \
00165                          : getu32(swap, ph64.p_type))
00166 #define xph_offset      (off_t)(class == ELFCLASS32     \
00167                          ? getu32(swap, ph32.p_offset)  \
00168                          : getu64(swap, ph64.p_offset))
00169 #define xph_align       (size_t)((class == ELFCLASS32   \
00170                          ? (off_t) (ph32.p_align ?      \
00171                             getu32(swap, ph32.p_align) : 4) \
00172                          : (off_t) (ph64.p_align ?      \
00173                             getu64(swap, ph64.p_align) : 4)))
00174 #define xph_filesz      (size_t)((class == ELFCLASS32   \
00175                          ? getu32(swap, ph32.p_filesz)  \
00176                          : getu64(swap, ph64.p_filesz)))
00177 #define xnh_addr        (class == ELFCLASS32            \
00178                          ? (void *) &nh32               \
00179                          : (void *) &nh64)
00180 #define xph_memsz       (size_t)((class == ELFCLASS32   \
00181                          ? getu32(swap, ph32.p_memsz)   \
00182                          : getu64(swap, ph64.p_memsz)))
00183 #define xnh_sizeof      (class == ELFCLASS32            \
00184                          ? sizeof nh32                  \
00185                          : sizeof nh64)
00186 #define xnh_type        (class == ELFCLASS32            \
00187                          ? getu32(swap, nh32.n_type)    \
00188                          : getu32(swap, nh64.n_type))
00189 #define xnh_namesz      (class == ELFCLASS32            \
00190                          ? getu32(swap, nh32.n_namesz)  \
00191                          : getu32(swap, nh64.n_namesz))
00192 #define xnh_descsz      (class == ELFCLASS32            \
00193                          ? getu32(swap, nh32.n_descsz)  \
00194                          : getu32(swap, nh64.n_descsz))
00195 #define prpsoffsets(i)  (class == ELFCLASS32            \
00196                          ? prpsoffsets32[i]             \
00197                          : prpsoffsets64[i])
00198 
00199 #ifdef ELFCORE
00200 /*@unchecked@*/ /*@observer@*/
00201 size_t  prpsoffsets32[] = {
00202         8,              /* FreeBSD */
00203         28,             /* Linux 2.0.36 (short name) */
00204         44,             /* Linux (path name) */
00205         84,             /* SunOS 5.x */
00206 };
00207 
00208 /*@unchecked@*/ /*@observer@*/
00209 size_t  prpsoffsets64[] = {
00210         16,             /* FreeBSD, 64-bit */
00211         40,             /* Linux (tested on core from 2.4.x, short name) */
00212         56,             /* Linux (path name) */
00213        120,             /* SunOS 5.x, 64-bit */
00214 };
00215 
00216 #define NOFFSETS32      (sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
00217 #define NOFFSETS64      (sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
00218 
00219 #define NOFFSETS        (class == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
00220 
00221 /*
00222  * Look through the program headers of an executable image, searching
00223  * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or
00224  * "FreeBSD"; if one is found, try looking in various places in its
00225  * contents for a 16-character string containing only printable
00226  * characters - if found, that string should be the name of the program
00227  * that dropped core.  Note: right after that 16-character string is,
00228  * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and
00229  * Linux, a longer string (80 characters, in 5.x, probably other
00230  * SVR4-flavored systems, and Linux) containing the start of the
00231  * command line for that program.
00232  *
00233  * The signal number probably appears in a section of type NT_PRSTATUS,
00234  * but that's also rather OS-dependent, in ways that are harder to
00235  * dissect with heuristics, so I'm not bothering with the signal number.
00236  * (I suppose the signal number could be of interest in situations where
00237  * you don't have the binary of the program that dropped core; if you
00238  * *do* have that binary, the debugger will probably tell you what
00239  * signal it was.)
00240  */
00241 
00242 #define OS_STYLE_SVR4           0
00243 #define OS_STYLE_FREEBSD        1
00244 #define OS_STYLE_NETBSD         2
00245 
00246 /*@unchecked@*/ /*@observer@*/
00247 private const char *os_style_names[] = {
00248         "SVR4",
00249         "FreeBSD",
00250         "NetBSD",
00251 };
00252 
00253 #define FLAGS_DID_CORE          1
00254 #define FLAGS_DID_NOTE          2
00255 
00256 private int
00257 dophn_core(struct magic_set *ms, int class, int swap, int fd, off_t off,
00258     int num, size_t size, off_t fsize, int *flags)
00259 {
00260         Elf32_Phdr ph32;
00261         Elf64_Phdr ph64;
00262         size_t offset;
00263         unsigned char nbuf[BUFSIZ];
00264         ssize_t bufsize;
00265         off_t savedoffset;
00266         struct stat st;
00267 
00268         if (fstat(fd, &st) < 0) {
00269                 file_badread(ms);
00270                 return -1;
00271         }
00272 
00273         if (size != xph_sizeof) {
00274                 if (file_printf(ms, ", corrupted program header size") == -1)
00275                         return -1;
00276                 return 0;
00277         }
00278 
00279         /*
00280          * Loop through all the program headers.
00281          */
00282         for ( ; num; num--) {
00283                 if ((savedoffset = lseek(fd, off, SEEK_SET)) == (off_t)-1) {
00284                         file_badseek(ms);
00285                         return -1;
00286                 }
00287                 if (read(fd, xph_addr, xph_sizeof) == -1) {
00288                         file_badread(ms);
00289                         return -1;
00290                 }
00291                 if (xph_offset > fsize) {
00292                         if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
00293                                 file_badseek(ms);
00294                                 return -1;
00295                         }
00296                         continue;
00297                 }
00298 
00299                 off += size;
00300                 if (xph_type != PT_NOTE)
00301                         continue;
00302 
00303                 /*
00304                  * This is a PT_NOTE section; loop through all the notes
00305                  * in the section.
00306                  */
00307                 if (lseek(fd, xph_offset, SEEK_SET) == (off_t)-1) {
00308                         file_badseek(ms);
00309                         return -1;
00310                 }
00311                 bufsize = read(fd, nbuf,
00312                     ((xph_filesz < sizeof(nbuf)) ? xph_filesz : sizeof(nbuf)));
00313                 if (bufsize == -1) {
00314                         file_badread(ms);
00315                         return -1;
00316                 }
00317                 offset = 0;
00318                 for (;;) {
00319                         if (offset >= (size_t)bufsize)
00320                                 /*@innerbreak@*/ break;
00321                         offset = donote(ms, nbuf, offset, (size_t)bufsize,
00322                             class, swap, 4, flags);
00323                         if (offset == 0)
00324                                 /*@innerbreak@*/ break;
00325 
00326                 }
00327         }
00328         return 0;
00329 }
00330 #endif
00331 
00332 private size_t
00333 donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size,
00334     int class, int swap, size_t align, int *flags)
00335 {
00336         Elf32_Nhdr nh32;
00337         Elf64_Nhdr nh64;
00338         size_t noff, doff;
00339 #ifdef ELFCORE
00340         int os_style = -1;
00341 #endif
00342         uint32_t namesz, descsz;
00343 
00344         (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
00345         offset += xnh_sizeof;
00346 
00347         namesz = xnh_namesz;
00348         descsz = xnh_descsz;
00349         if ((namesz == 0) && (descsz == 0)) {
00350                 /*
00351                  * We're out of note headers.
00352                  */
00353                 return (offset >= size) ? offset : size;
00354         }
00355 
00356         if (namesz & 0x80000000) {
00357             (void)file_printf(ms, ", bad note name size 0x%lx",
00358                 (unsigned long)namesz);
00359             return offset;
00360         }
00361 
00362         if (descsz & 0x80000000) {
00363             (void)file_printf(ms, ", bad note description size 0x%lx",
00364                 (unsigned long)descsz);
00365             return offset;
00366         }
00367 
00368 
00369         noff = offset;
00370         doff = ELF_ALIGN(offset + namesz);
00371 
00372         if (offset + namesz > size) {
00373                 /*
00374                  * We're past the end of the buffer.
00375                  */
00376                 return doff;
00377         }
00378 
00379         offset = ELF_ALIGN(doff + descsz);
00380         if (doff + descsz > size) {
00381                 /*
00382                  * We're past the end of the buffer.
00383                  */
00384                 return (offset >= size) ? offset : size;
00385         }
00386 
00387         if (*flags & FLAGS_DID_NOTE)
00388                 goto core;
00389 
00390         if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
00391             xnh_type == NT_GNU_VERSION && descsz == 16) {
00392                 uint32_t desc[4];
00393                 (void)memcpy(desc, &nbuf[doff], sizeof(desc));
00394 
00395                 if (file_printf(ms, ", for GNU/") == -1)
00396                         return size;
00397                 switch (getu32(swap, desc[0])) {
00398                 case GNU_OS_LINUX:
00399                         if (file_printf(ms, "Linux") == -1)
00400                                 return size;
00401                         break;
00402                 case GNU_OS_HURD:
00403                         if (file_printf(ms, "Hurd") == -1)
00404                                 return size;
00405                         break;
00406                 case GNU_OS_SOLARIS:
00407                         if (file_printf(ms, "Solaris") == -1)
00408                                 return size;
00409                         break;
00410                 default:
00411                         if (file_printf(ms, "<unknown>") == -1)
00412                                 return size; 
00413                 }
00414                 if (file_printf(ms, " %d.%d.%d", getu32(swap, desc[1]),
00415                     getu32(swap, desc[2]), getu32(swap, desc[3])) == -1)
00416                         return size;
00417                 *flags |= FLAGS_DID_NOTE;
00418                 return size;
00419         }
00420 
00421         if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 &&
00422             xnh_type == NT_NETBSD_VERSION && descsz == 4) {
00423                 uint32_t desc;
00424                 (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
00425                 desc = getu32(swap, desc);
00426 
00427                 if (file_printf(ms, ", for NetBSD") == -1)
00428                         return size;
00429                 /*
00430                  * The version number used to be stuck as 199905, and was thus
00431                  * basically content-free.  Newer versions of NetBSD have fixed
00432                  * this and now use the encoding of __NetBSD_Version__:
00433                  *
00434                  *      MMmmrrpp00
00435                  *
00436                  * M = major version
00437                  * m = minor version
00438                  * r = release ["",A-Z,Z[A-Z] but numeric]
00439                  * p = patchlevel
00440                  */
00441                 if (desc > 100000000U) {
00442                         uint32_t ver_patch = (desc / 100) % 100;
00443                         uint32_t ver_rel = (desc / 10000) % 100;
00444                         uint32_t ver_min = (desc / 1000000) % 100;
00445                         uint32_t ver_maj = desc / 100000000;
00446 
00447                         if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1)
00448                                 return size;
00449                         if (ver_rel == 0 && ver_patch != 0) {
00450                                 if (file_printf(ms, ".%u", ver_patch) == -1)
00451                                         return size;
00452                         } else if (ver_rel != 0) {
00453                                 while (ver_rel > 26) {
00454                                         if (file_printf(ms, "Z") == -1)
00455                                                 return size;
00456                                         ver_rel -= 26;
00457                                 }
00458                                 if (file_printf(ms, "%c", 'A' + ver_rel - 1)
00459                                     == -1)
00460                                         return size;
00461                         }
00462                 }
00463                 *flags |= FLAGS_DID_NOTE;
00464                 return size;
00465         }
00466 
00467         if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0 &&
00468             xnh_type == NT_FREEBSD_VERSION && descsz == 4) {
00469                 uint32_t desc;
00470                 (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
00471                 desc = getu32(swap, desc);
00472                 if (file_printf(ms, ", for FreeBSD") == -1)
00473                         return size;
00474 
00475                 /*
00476                  * Contents is __FreeBSD_version, whose relation to OS
00477                  * versions is defined by a huge table in the Porter's
00478                  * Handbook.  This is the general scheme:
00479                  * 
00480                  * Releases:
00481                  *      Mmp000 (before 4.10)
00482                  *      Mmi0p0 (before 5.0)
00483                  *      Mmm0p0
00484                  * 
00485                  * Development branches:
00486                  *      Mmpxxx (before 4.6)
00487                  *      Mmp1xx (before 4.10)
00488                  *      Mmi1xx (before 5.0)
00489                  *      M000xx (pre-M.0)
00490                  *      Mmm1xx
00491                  * 
00492                  * M = major version
00493                  * m = minor version
00494                  * i = minor version increment (491000 -> 4.10)
00495                  * p = patchlevel
00496                  * x = revision
00497                  * 
00498                  * The first release of FreeBSD to use ELF by default
00499                  * was version 3.0.
00500                  */
00501                 if (desc == 460002) {
00502                         if (file_printf(ms, " 4.6.2") == -1)
00503                                 return size;
00504                 } else if (desc < 460100) {
00505                         if (file_printf(ms, " %d.%d", desc / 100000,
00506                             desc / 10000 % 10) == -1)
00507                                 return size;
00508                         if (desc / 1000 % 10 > 0)
00509                                 if (file_printf(ms, ".%d", desc / 1000 % 10)
00510                                     == -1)
00511                                         return size;
00512                         if ((desc % 1000 > 0) || (desc % 100000 == 0))
00513                                 if (file_printf(ms, " (%d)", desc) == -1)
00514                                         return size;
00515                 } else if (desc < 500000) {
00516                         if (file_printf(ms, " %d.%d", desc / 100000,
00517                             desc / 10000 % 10 + desc / 1000 % 10) == -1)
00518                                 return size;
00519                         if (desc / 100 % 10 > 0) {
00520                                 if (file_printf(ms, " (%d)", desc) == -1)
00521                                         return size;
00522                         } else if (desc / 10 % 10 > 0) {
00523                                 if (file_printf(ms, ".%d", desc / 10 % 10)
00524                                     == -1)
00525                                         return size;
00526                         }
00527                 } else {
00528                         if (file_printf(ms, " %d.%d", desc / 100000,
00529                             desc / 1000 % 100) == -1)
00530                                 return size;
00531                         if ((desc / 100 % 10 > 0) ||
00532                             (desc % 100000 / 100 == 0)) {
00533                                 if (file_printf(ms, " (%d)", desc) == -1)
00534                                         return size;
00535                         } else if (desc / 10 % 10 > 0) {
00536                                 if (file_printf(ms, ".%d", desc / 10 % 10)
00537                                     == -1)
00538                                         return size;
00539                         }
00540                 }
00541                 *flags |= FLAGS_DID_NOTE;
00542                 return size;
00543         }
00544 
00545         if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
00546             xnh_type == NT_OPENBSD_VERSION && descsz == 4) {
00547                 if (file_printf(ms, ", for OpenBSD") == -1)
00548                         return size;
00549                 /* Content of note is always 0 */
00550                 *flags |= FLAGS_DID_NOTE;
00551                 return size;
00552         }
00553 
00554         if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
00555             xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) {
00556                 uint32_t desc;
00557                 if (file_printf(ms, ", for DragonFly") == -1)
00558                         return size;
00559                 (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
00560                 desc = getu32(swap, desc);
00561                 if (file_printf(ms, " %d.%d.%d", desc / 100000,
00562                     desc / 10000 % 10, desc % 10000) == -1)
00563                         return size;
00564                 *flags |= FLAGS_DID_NOTE;
00565                 return size;
00566         }
00567 
00568 core:
00569         /*
00570          * Sigh.  The 2.0.36 kernel in Debian 2.1, at
00571          * least, doesn't correctly implement name
00572          * sections, in core dumps, as specified by
00573          * the "Program Linking" section of "UNIX(R) System
00574          * V Release 4 Programmer's Guide: ANSI C and
00575          * Programming Support Tools", because my copy
00576          * clearly says "The first 'namesz' bytes in 'name'
00577          * contain a *null-terminated* [emphasis mine]
00578          * character representation of the entry's owner
00579          * or originator", but the 2.0.36 kernel code
00580          * doesn't include the terminating null in the
00581          * name....
00582          */
00583         if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) ||
00584             (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) {
00585                 os_style = OS_STYLE_SVR4;
00586         } 
00587 
00588         if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) {
00589                 os_style = OS_STYLE_FREEBSD;
00590         }
00591 
00592         if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11)
00593             == 0)) {
00594                 os_style = OS_STYLE_NETBSD;
00595         }
00596 
00597 #ifdef ELFCORE
00598         if ((*flags & FLAGS_DID_CORE) != 0)
00599                 return size;
00600 
00601         if (os_style != -1) {
00602                 if (file_printf(ms, ", %s-style", os_style_names[os_style])
00603                     == -1)
00604                                 return size;
00605         }
00606 
00607         switch (os_style) {
00608         case OS_STYLE_NETBSD:
00609                 if (xnh_type == NT_NETBSD_CORE_PROCINFO) {
00610                         uint32_t signo;
00611                         /*
00612                          * Extract the program name.  It is at
00613                          * offset 0x7c, and is up to 32-bytes,
00614                          * including the terminating NUL.
00615                          */
00616                         if (file_printf(ms, ", from '%.31s'",
00617                             &nbuf[doff + 0x7c]) == -1)
00618                                 return size;
00619                         
00620                         /*
00621                          * Extract the signal number.  It is at
00622                          * offset 0x08.
00623                          */
00624                         (void)memcpy(&signo, &nbuf[doff + 0x08],
00625                             sizeof(signo));
00626                         if (file_printf(ms, " (signal %u)",
00627                             getu32(swap, signo)) == -1)
00628                                 return size;
00629                         return size;
00630                 }
00631                 break;
00632 
00633         default:
00634                 if (xnh_type == NT_PRPSINFO) {
00635                         size_t i, j;
00636                         unsigned char c;
00637                         /*
00638                          * Extract the program name.  We assume
00639                          * it to be 16 characters (that's what it
00640                          * is in SunOS 5.x and Linux).
00641                          *
00642                          * Unfortunately, it's at a different offset
00643                          * in varous OSes, so try multiple offsets.
00644                          * If the characters aren't all printable,
00645                          * reject it.
00646                          */
00647                         for (i = 0; i < NOFFSETS; i++) {
00648                                 size_t reloffset = prpsoffsets(i);
00649                                 size_t noffset = doff + reloffset;
00650                                 for (j = 0; j < 16; j++, noffset++,
00651                                     reloffset++) {
00652                                         /*
00653                                          * Make sure we're not past
00654                                          * the end of the buffer; if
00655                                          * we are, just give up.
00656                                          */
00657                                         if (noffset >= size)
00658                                                 goto tryanother;
00659 
00660                                         /*
00661                                          * Make sure we're not past
00662                                          * the end of the contents;
00663                                          * if we are, this obviously
00664                                          * isn't the right offset.
00665                                          */
00666                                         if (reloffset >= descsz)
00667                                                 goto tryanother;
00668 
00669                                         c = nbuf[noffset];
00670                                         if (c == '\0') {
00671                                                 /*
00672                                                  * A '\0' at the
00673                                                  * beginning is
00674                                                  * obviously wrong.
00675                                                  * Any other '\0'
00676                                                  * means we're done.
00677                                                  */
00678                                                 if (j == 0)
00679                                                         goto tryanother;
00680                                                 else
00681                                                         /*@innerbreak@*/ break;
00682                                         } else {
00683                                                 /*
00684                                                  * A nonprintable
00685                                                  * character is also
00686                                                  * wrong.
00687                                                  */
00688                                                 if (!isprint(c) || isquote(c))
00689                                                         goto tryanother;
00690                                         }
00691                                 }
00692                                 /*
00693                                  * Well, that worked.
00694                                  */
00695                                 if (file_printf(ms, ", from '%.16s'",
00696                                     &nbuf[doff + prpsoffsets(i)]) == -1)
00697                                         return size;
00698                                 return size;
00699 
00700                         tryanother:
00701                                 ;
00702                         }
00703                 }
00704                 break;
00705         }
00706 #endif
00707         *flags |= FLAGS_DID_CORE;
00708         return offset;
00709 }
00710 
00711 private int
00712 doshn(struct magic_set *ms, int class, int swap, int fd, off_t off, int num,
00713     size_t size, int *flags)
00714 {
00715         Elf32_Shdr sh32;
00716         Elf64_Shdr sh64;
00717         int stripped = 1;
00718         void *nbuf;
00719         off_t noff;
00720 
00721         if (size != xsh_sizeof) {
00722                 if (file_printf(ms, ", corrupted section header size") == -1)
00723                         return -1;
00724                 return 0;
00725         }
00726 
00727         if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
00728                 file_badseek(ms);
00729                 return -1;
00730         }
00731 
00732         for ( ; num; num--) {
00733                 if (read(fd, xsh_addr, xsh_sizeof) == -1) {
00734                         file_badread(ms);
00735                         return -1;
00736                 }
00737                 switch (xsh_type) {
00738                 case SHT_SYMTAB:
00739 #if 0
00740                 case SHT_DYNSYM:
00741 #endif
00742                         stripped = 0;
00743                         /*@switchbreak@*/ break;
00744                 case SHT_NOTE:
00745                         if ((off = lseek(fd, (off_t)0, SEEK_CUR)) ==
00746                             (off_t)-1) {
00747                                 file_badread(ms);
00748                                 return -1;
00749                         }
00750                         if ((nbuf = malloc((size_t)xsh_size)) == NULL) {
00751                                 file_error(ms, errno, "Cannot allocate memory"
00752                                     " for note");
00753                                 return -1;
00754                         }
00755                         if ((noff = lseek(fd, (off_t)xsh_offset, SEEK_SET)) ==
00756                             (off_t)-1) {
00757                                 file_badread(ms);
00758                                 free(nbuf);
00759                                 return -1;
00760                         }
00761                         if (read(fd, nbuf, (size_t)xsh_size) !=
00762                             (ssize_t)xsh_size) {
00763                                 free(nbuf);
00764                                 file_badread(ms);
00765                                 return -1;
00766                         }
00767 
00768                         noff = 0;
00769                         for (;;) {
00770                                 if (noff >= (size_t)xsh_size)
00771                                         /*@innerbreak@*/ break;
00772                                 noff = donote(ms, nbuf, (size_t)noff,
00773                                     (size_t)xsh_size, class, swap, 4,
00774                                     flags);
00775                                 if (noff == 0)
00776                                         /*@innerbreak@*/ break;
00777                         }
00778                         if ((lseek(fd, off, SEEK_SET)) == (off_t)-1) {
00779                                 free(nbuf);
00780                                 file_badread(ms);
00781                                 return -1;
00782                         }
00783                         free(nbuf);
00784                         /*@switchbreak@*/ break;
00785                 }
00786         }
00787         if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
00788                 return -1;
00789         return 0;
00790 }
00791 
00792 /*
00793  * Look through the program headers of an executable image, searching
00794  * for a PT_INTERP section; if one is found, it's dynamically linked,
00795  * otherwise it's statically linked.
00796  */
00797 private int
00798 dophn_exec(struct magic_set *ms, int class, int swap, int fd, off_t off,
00799     int num, size_t size, off_t fsize, int *flags, int sh_num)
00800 {
00801         Elf32_Phdr ph32;
00802         Elf64_Phdr ph64;
00803         const char *linking_style = "statically";
00804         const char *shared_libraries = "";
00805         unsigned char nbuf[BUFSIZ];
00806         int bufsize;
00807         size_t offset, align;
00808         off_t savedoffset = (off_t)-1;
00809         struct stat st;
00810 
00811         if (fstat(fd, &st) < 0) {
00812                 file_badread(ms);
00813                 return -1;
00814         }
00815 
00816         if (size != xph_sizeof) {
00817                 if (file_printf(ms, ", corrupted program header size") == -1)
00818                     return -1;
00819                 return 0;
00820         }
00821         if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
00822                 file_badseek(ms);
00823                 return -1;
00824         }
00825 
00826         for ( ; num; num--) {
00827                 if (read(fd, xph_addr, xph_sizeof) == -1) {
00828                         file_badread(ms);
00829                         return -1;
00830                 }
00831                 if (xph_offset > st.st_size && savedoffset != (off_t)-1) {
00832                         if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
00833                                 file_badseek(ms);
00834                                 return -1;
00835                         }
00836                         continue;
00837                 }
00838 
00839                 if ((savedoffset = lseek(fd, (off_t)0, SEEK_CUR)) == (off_t)-1) {
00840                         file_badseek(ms);
00841                         return -1;
00842                 }
00843 
00844                 if (xph_offset > fsize) {
00845                         if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
00846                                 file_badseek(ms);
00847                                 return -1;
00848                         }
00849                         continue;
00850                 }
00851 
00852                 switch (xph_type) {
00853                 case PT_DYNAMIC:
00854                         linking_style = "dynamically";
00855                         /*@switchbreak@*/ break;
00856                 case PT_INTERP:
00857                         shared_libraries = " (uses shared libs)";
00858                         /*@switchbreak@*/ break;
00859                 case PT_NOTE:
00860                         if ((align = xph_align) & 0x80000000) {
00861                                 if (file_printf(ms, 
00862                                     ", invalid note alignment 0x%lx",
00863                                     (unsigned long)align) == -1)
00864                                         return -1;
00865                                 align = 4;
00866                         }
00867                         /* If we have a section header table, handle note
00868                            sections just in doshn.  Handling them also here
00869                            means that for executables we print the note content
00870                            twice and, more importantly, don't handle
00871                            strip -o created debuginfo files correctly.
00872                            They have PT_NOTE header, but the actual note
00873                            content is not present in the debuginfo file,
00874                            only in the original stripped executable or library.
00875                            The corresponding .note.* section is SHT_NOBITS
00876                            rather than SHT_NOTE, so doshn will not look
00877                            at it.  */
00878                         if (sh_num)
00879                                 /*@switchbreak@*/ break;
00880                         /*
00881                          * This is a PT_NOTE section; loop through all the notes
00882                          * in the section.
00883                          */
00884                         if (lseek(fd, xph_offset, SEEK_SET)
00885                             == (off_t)-1) {
00886                                 file_badseek(ms);
00887                                 return -1;
00888                         }
00889                         bufsize = read(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ?
00890                             xph_filesz : sizeof(nbuf)));
00891                         if (bufsize == -1) {
00892                                 file_badread(ms);
00893                                 return -1;
00894                         }
00895                         offset = 0;
00896                         for (;;) {
00897                                 if (offset >= (size_t)bufsize)
00898                                         /*@innerbreak@*/ break;
00899                                 offset = donote(ms, nbuf, offset,
00900                                     (size_t)bufsize, class, swap, align,
00901                                     flags);
00902                                 if (offset == 0)
00903                                         /*@innerbreak@*/ break;
00904                         }
00905                         if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
00906                                 file_badseek(ms);
00907                                 return -1;
00908                         }
00909                         /*@switchbreak@*/ break;
00910                 }
00911         }
00912         if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries)
00913             == -1)
00914             return -1;
00915         return 0;
00916 }
00917 
00918 
00919 protected int
00920 file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
00921     size_t nbytes)
00922 {
00923         union {
00924                 int32_t l;
00925                 char c[sizeof (int32_t)];
00926         } u;
00927         int class;
00928         int swap;
00929         struct stat st;
00930         off_t fsize;
00931         int flags = 0;
00932 
00933         /*
00934          * If we cannot seek, it must be a pipe, socket or fifo.
00935          */
00936         if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE))
00937                 fd = file_pipe2file(ms, fd, buf, nbytes);
00938 
00939         if (fstat(fd, &st) == -1) {
00940                 file_badread(ms);
00941                 return -1;
00942         }
00943         fsize = st.st_size;
00944 
00945         /*
00946          * ELF executables have multiple section headers in arbitrary
00947          * file locations and thus file(1) cannot determine it from easily.
00948          * Instead we traverse thru all section headers until a symbol table
00949          * one is found or else the binary is stripped.
00950          */
00951         if (buf[EI_MAG0] != ELFMAG0
00952             || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
00953             || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
00954             return 0;
00955 
00956 
00957         class = buf[EI_CLASS];
00958 
00959         if (class == ELFCLASS32) {
00960                 Elf32_Ehdr elfhdr;
00961                 if (nbytes <= sizeof (Elf32_Ehdr))
00962                         return 0;
00963 
00964 
00965                 u.l = 1;
00966                 (void) memcpy(&elfhdr, buf, sizeof elfhdr);
00967                 swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
00968 
00969                 if (getu16(swap, elfhdr.e_type) == ET_CORE) {
00970 #ifdef ELFCORE
00971                         if (dophn_core(ms, class, swap, fd,
00972                             (off_t)getu32(swap, elfhdr.e_phoff),
00973                             getu16(swap, elfhdr.e_phnum), 
00974                             (size_t)getu16(swap, elfhdr.e_phentsize),
00975                             fsize, &flags) == -1)
00976                                 return -1;
00977 #else
00978                         ;
00979 #endif
00980                 } else {
00981                         if (getu16(swap, elfhdr.e_type) == ET_EXEC) {
00982                                 if (dophn_exec(ms, class, swap,
00983                                     fd, (off_t)getu32(swap, elfhdr.e_phoff),
00984                                     getu16(swap, elfhdr.e_phnum), 
00985                                     (size_t)getu16(swap, elfhdr.e_phentsize),
00986                                     fsize, &flags,
00987                     getu16(swap, elfhdr.e_shnum))
00988                                     == -1)
00989                                         return -1;
00990                         }
00991                         if (doshn(ms, class, swap, fd,
00992                             (off_t)getu32(swap, elfhdr.e_shoff),
00993                             getu16(swap, elfhdr.e_shnum),
00994                             (size_t)getu16(swap, elfhdr.e_shentsize),
00995                             &flags) == -1)
00996                                 return -1;
00997                 }
00998                 return 1;
00999         }
01000 
01001         if (class == ELFCLASS64) {
01002                 Elf64_Ehdr elfhdr;
01003                 if (nbytes <= sizeof (Elf64_Ehdr))
01004                         return 0;
01005 
01006 
01007                 u.l = 1;
01008                 (void) memcpy(&elfhdr, buf, sizeof elfhdr);
01009                 swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
01010 
01011                 if (getu16(swap, elfhdr.e_type) == ET_CORE) {
01012 #ifdef ELFCORE
01013                         if (dophn_core(ms, class, swap, fd,
01014                             (off_t)elf_getu64(swap, elfhdr.e_phoff),
01015                             getu16(swap, elfhdr.e_phnum), 
01016                             (size_t)getu16(swap, elfhdr.e_phentsize),
01017                             fsize, &flags) == -1)
01018                                 return -1;
01019 #else
01020                         ;
01021 #endif
01022                 } else {
01023                         if (getu16(swap, elfhdr.e_type) == ET_EXEC) {
01024                                 if (dophn_exec(ms, class, swap, fd,
01025                                     (off_t)elf_getu64(swap, elfhdr.e_phoff),
01026                                     getu16(swap, elfhdr.e_phnum), 
01027                                     (size_t)getu16(swap, elfhdr.e_phentsize),
01028                                     fsize, &flags,
01029                     getu16(swap, elfhdr.e_shnum)) == -1)
01030                                         return -1;
01031                         }
01032                         if (doshn(ms, class, swap, fd,
01033                             (off_t)elf_getu64(swap, elfhdr.e_shoff),
01034                             getu16(swap, elfhdr.e_shnum),
01035                             (size_t)getu16(swap, elfhdr.e_shentsize), &flags)
01036                             == -1)
01037                                 return -1;
01038                 }
01039                 return 1;
01040         }
01041         return 0;
01042 }
01043 #endif

Generated on Fri May 25 21:18:11 2007 for rpm by  doxygen 1.5.2