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

Generated on Fri Oct 12 08:44:53 2007 for rpm by  doxygen 1.5.2