1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  22 /*        All Rights Reserved   */
  23 
  24 
  25 /*      Copyright (c) 1987, 1988 Microsoft Corporation  */
  26 /*        All Rights Reserved   */
  27 
  28 /*
  29  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  30  * Use is subject to license terms.
  31  */
  32 
  33 /*
  34  * ELF files can exceed 2GB in size. A standard 32-bit program
  35  * like 'file' cannot read past 2GB, and will be unable to see
  36  * the ELF section headers that typically are at the end of the
  37  * object. The simplest solution to this problem would be to make
  38  * the 'file' command a 64-bit application. However, as a matter of
  39  * policy, we do not want to require this. A simple command like
  40  * 'file' should not carry such a requirement, especially as we
  41  * support 32-bit only hardware.
  42  *
  43  * An alternative solution is to build this code as 32-bit
  44  * large file aware. The usual way to do this is to define a pair
  45  * of preprocessor definitions:
  46  *
  47  *      _LARGEFILE64_SOURCE
  48  *              Map standard I/O routines to their largefile aware versions.
  49  *
  50  *      _FILE_OFFSET_BITS=64
  51  *              Map off_t to off64_t
  52  *
  53  * The problem with this solution is that libelf is not large file capable,
  54  * and the libelf header file will prevent compilation if
  55  * _FILE_OFFSET_BITS is set to 64.
  56  *
  57  * So, the solution used in this code is to define _LARGEFILE64_SOURCE
  58  * to get access to the 64-bit APIs, not to define _FILE_OFFSET_BITS, and to
  59  * use our own types in place of off_t, and size_t. We read all the file
  60  * data directly using pread64(), and avoid the use of libelf for anything
  61  * other than the xlate functionality.
  62  */
  63 #define _LARGEFILE64_SOURCE
  64 #define FILE_ELF_OFF_T  off64_t
  65 #define FILE_ELF_SIZE_T uint64_t
  66 
  67 #include <ctype.h>
  68 #include <unistd.h>
  69 #include <fcntl.h>
  70 #include <stdio.h>
  71 #include <libelf.h>
  72 #include <stdlib.h>
  73 #include <limits.h>
  74 #include <locale.h>
  75 #include <string.h>
  76 #include <errno.h>
  77 #include <procfs.h>
  78 #include <sys/param.h>
  79 #include <sys/types.h>
  80 #include <sys/stat.h>
  81 #include <sys/elf.h>
  82 #include <sys/link.h>
  83 #include <elfcap.h>
  84 #include "file.h"
  85 #include "elf_read.h"
  86 
  87 extern const char *File;
  88 
  89 static int get_class(void);
  90 static int get_version(void);
  91 static int get_format(void);
  92 static int process_shdr(Elf_Info *);
  93 static int process_phdr(Elf_Info *);
  94 static int file_xlatetom(Elf_Type, char *);
  95 static int xlatetom_nhdr(Elf_Nhdr *);
  96 static int get_phdr(Elf_Info *, int);
  97 static int get_shdr(Elf_Info *, int);
  98 
  99 static Elf_Ehdr EI_Ehdr;                /* Elf_Ehdr to be stored */
 100 static Elf_Word EI_Ehdr_shnum;          /* # section headers */
 101 static Elf_Word EI_Ehdr_phnum;          /* # program headers */
 102 static Elf_Word EI_Ehdr_shstrndx;       /* Index of section hdr string table */
 103 static Elf_Shdr EI_Shdr;                /* recent Elf_Shdr to be stored */
 104 static Elf_Phdr EI_Phdr;                /* recent Elf_Phdr to be stored */
 105 
 106 
 107 static int
 108 get_class(void)
 109 {
 110         return (EI_Ehdr.e_ident[EI_CLASS]);
 111 }
 112 
 113 static int
 114 get_version(void)
 115 {
 116         /* do as what libelf:_elf_config() does */
 117         return (EI_Ehdr.e_ident[EI_VERSION] ?
 118             EI_Ehdr.e_ident[EI_VERSION] : 1);
 119 }
 120 
 121 static int
 122 get_format(void)
 123 {
 124         return (EI_Ehdr.e_ident[EI_DATA]);
 125 }
 126 
 127 /*
 128  * file_xlatetom:       translate different headers from file
 129  *                      representation to memory representaion.
 130  */
 131 #define HDRSZ 512
 132 static int
 133 file_xlatetom(Elf_Type type, char *hdr)
 134 {
 135         Elf_Data src, dst;
 136         char *hbuf[HDRSZ];
 137         int version, format;
 138 
 139         version = get_version();
 140         format = get_format();
 141 
 142         /* will convert only these types */
 143         if (type != ELF_T_EHDR && type != ELF_T_PHDR &&
 144             type != ELF_T_SHDR && type != ELF_T_WORD &&
 145             type != ELF_T_CAP && type != ELF_T_DYN)
 146                 return (ELF_READ_FAIL);
 147 
 148         src.d_buf = (Elf_Void *)hdr;
 149         src.d_type = type;
 150         src.d_version = version;
 151 
 152         dst.d_buf = (Elf_Void *)&hbuf;
 153         dst.d_version = EV_CURRENT;
 154 
 155         src.d_size = elf_fsize(type, 1, version);
 156         dst.d_size = elf_fsize(type, 1, EV_CURRENT);
 157         if (elf_xlatetom(&dst, &src, format) == NULL)
 158                 return (ELF_READ_FAIL);
 159 
 160         (void) memcpy(hdr, &hbuf, dst.d_size);
 161         return (ELF_READ_OKAY);
 162 }
 163 
 164 /*
 165  * xlatetom_nhdr:       There is no routine to convert Note header
 166  *                      so we convert each field of this header.
 167  */
 168 static int
 169 xlatetom_nhdr(Elf_Nhdr *nhdr)
 170 {
 171         int r = ELF_READ_FAIL;
 172 
 173         r |= file_xlatetom(ELF_T_WORD, (char *)&nhdr->n_namesz);
 174         r |= file_xlatetom(ELF_T_WORD, (char *)&nhdr->n_descsz);
 175         r |= file_xlatetom(ELF_T_WORD, (char *)&nhdr->n_type);
 176         return (r);
 177 }
 178 
 179 /*
 180  * elf_read:    reads elf header, program, section headers to
 181  *              collect all information needed for file(1)
 182  *              output and stores them in Elf_Info.
 183  */
 184 int
 185 elf_read(int fd, Elf_Info *EI)
 186 {
 187         FILE_ELF_SIZE_T size;
 188         int             ret = 1;
 189 
 190         Elf_Ehdr *ehdr = &EI_Ehdr;
 191 
 192         EI->elffd = fd;
 193         size = sizeof (Elf_Ehdr);
 194 
 195         if (pread64(EI->elffd, (void*)ehdr, size, 0) != size)
 196                 ret = 0;
 197 
 198 
 199         if (file_xlatetom(ELF_T_EHDR, (char *)ehdr) == ELF_READ_FAIL)
 200                 ret = 0;
 201 
 202         if (EI->file == NULL)
 203                 return (ELF_READ_FAIL);
 204 
 205         /*
 206          * Extended section or program indexes in use? If so, special
 207          * values in the ELF header redirect us to get the real values
 208          * from shdr[0].
 209          */
 210         EI_Ehdr_shnum = EI_Ehdr.e_shnum;
 211         EI_Ehdr_phnum = EI_Ehdr.e_phnum;
 212         EI_Ehdr_shstrndx = EI_Ehdr.e_shstrndx;
 213         if (((EI_Ehdr_shnum == 0) || (EI_Ehdr_phnum == PN_XNUM)) &&
 214             (EI_Ehdr.e_shoff != 0)) {
 215                 if (get_shdr(EI, 0) == ELF_READ_FAIL)
 216                         return (ELF_READ_FAIL);
 217                 if (EI_Ehdr_shnum == 0)
 218                         EI_Ehdr_shnum = EI_Shdr.sh_size;
 219                 if ((EI_Ehdr_phnum == PN_XNUM) && (EI_Shdr.sh_info != 0))
 220                         EI_Ehdr_phnum = EI_Shdr.sh_info;
 221                 if (EI_Ehdr_shstrndx == SHN_XINDEX)
 222                         EI_Ehdr_shstrndx = EI_Shdr.sh_link;
 223         }
 224 
 225         EI->type = ehdr->e_type;
 226         EI->machine = ehdr->e_machine;
 227         EI->flags = ehdr->e_flags;
 228 
 229         if (ret == 0) {
 230                 (void) fprintf(stderr, gettext("%s: %s: can't "
 231                     "read ELF header\n"), File, EI->file);
 232                 return (ELF_READ_FAIL);
 233         }
 234         if (process_phdr(EI) == ELF_READ_FAIL)
 235                 return (ELF_READ_FAIL);
 236 
 237         /* We don't need section info for core files */
 238         if (ehdr->e_type != ET_CORE)
 239                 if (process_shdr(EI) == ELF_READ_FAIL)
 240                         return (ELF_READ_FAIL);
 241 
 242         return (ELF_READ_OKAY);
 243 }
 244 
 245 /*
 246  * get_phdr:    reads program header of specified index.
 247  */
 248 static int
 249 get_phdr(Elf_Info *EI, int inx)
 250 {
 251         FILE_ELF_OFF_T  off = 0;
 252         FILE_ELF_SIZE_T size;
 253 
 254         if (inx >= EI_Ehdr_phnum)
 255                 return (ELF_READ_FAIL);
 256 
 257         size = sizeof (Elf_Phdr);
 258         off = (FILE_ELF_OFF_T)EI_Ehdr.e_phoff + (inx * size);
 259         if (pread64(EI->elffd, (void *)&EI_Phdr, size, off) != size)
 260                 return (ELF_READ_FAIL);
 261 
 262         if (file_xlatetom(ELF_T_PHDR, (char *)&EI_Phdr) == ELF_READ_FAIL)
 263                 return (ELF_READ_FAIL);
 264 
 265         return (ELF_READ_OKAY);
 266 }
 267 
 268 /*
 269  * get_shdr:    reads section header of specified index.
 270  */
 271 static int
 272 get_shdr(Elf_Info *EI, int inx)
 273 {
 274         FILE_ELF_OFF_T  off = 0;
 275         FILE_ELF_SIZE_T size;
 276 
 277         /*
 278          * Prevent access to non-existent section headers.
 279          *
 280          * A value of 0 for e_shoff means that there is no section header
 281          * array in the file. A value of 0 for e_shndx does not necessarily
 282          * mean this - there can still be a 1-element section header array
 283          * to support extended section or program header indexes that
 284          * exceed the 16-bit fields used in the ELF header to represent them.
 285          */
 286         if ((EI_Ehdr.e_shoff == 0) || ((inx > 0) && (inx >= EI_Ehdr_shnum)))
 287                 return (ELF_READ_FAIL);
 288 
 289         size = sizeof (Elf_Shdr);
 290         off = (FILE_ELF_OFF_T)EI_Ehdr.e_shoff + (inx * size);
 291 
 292         if (pread64(EI->elffd, (void *)&EI_Shdr, size, off) != size)
 293                 return (ELF_READ_FAIL);
 294 
 295         if (file_xlatetom(ELF_T_SHDR, (char *)&EI_Shdr) == ELF_READ_FAIL)
 296                 return (ELF_READ_FAIL);
 297 
 298         return (ELF_READ_OKAY);
 299 }
 300 
 301 /*
 302  * process_phdr:        Read Program Headers and see if it is a core
 303  *                      file of either new or (pre-restructured /proc)
 304  *                      type, read the name of the file that dumped this
 305  *                      core, else see if this is a dynamically linked.
 306  */
 307 static int
 308 process_phdr(Elf_Info *EI)
 309 {
 310         register int inx;
 311 
 312         Elf_Nhdr        Nhdr, *nhdr;    /* note header just read */
 313         Elf_Phdr        *phdr = &EI_Phdr;
 314 
 315         FILE_ELF_SIZE_T nsz, nmsz, dsz;
 316         FILE_ELF_OFF_T  offset;
 317         int     class;
 318         int     ntype;
 319         char    *psinfo, *fname;
 320 
 321         nsz = sizeof (Elf_Nhdr);
 322         nhdr = &Nhdr;
 323         class = get_class();
 324         for (inx = 0; inx < EI_Ehdr_phnum; inx++) {
 325                 if (get_phdr(EI, inx) == ELF_READ_FAIL)
 326                         return (ELF_READ_FAIL);
 327 
 328                 /* read the note if it is a core */
 329                 if (phdr->p_type == PT_NOTE &&
 330                     EI_Ehdr.e_type == ET_CORE) {
 331                         /*
 332                          * If the next segment is also a note, use it instead.
 333                          */
 334                         if (get_phdr(EI, inx+1) == ELF_READ_FAIL)
 335                                 return (ELF_READ_FAIL);
 336                         if (phdr->p_type != PT_NOTE) {
 337                                 /* read the first phdr back */
 338                                 if (get_phdr(EI, inx) == ELF_READ_FAIL)
 339                                         return (ELF_READ_FAIL);
 340                         }
 341                         offset = phdr->p_offset;
 342                         if (pread64(EI->elffd, (void *)nhdr, nsz, offset)
 343                             != nsz)
 344                                 return (ELF_READ_FAIL);
 345 
 346                         /* Translate the ELF note header */
 347                         if (xlatetom_nhdr(nhdr) == ELF_READ_FAIL)
 348                                 return (ELF_READ_FAIL);
 349 
 350                         ntype = nhdr->n_type;
 351                         nmsz = nhdr->n_namesz;
 352                         dsz = nhdr->n_descsz;
 353 
 354                         offset += nsz + ((nmsz + 0x03) & ~0x3);
 355                         if ((psinfo = malloc(dsz)) == NULL) {
 356                                 int err = errno;
 357                                 (void) fprintf(stderr, gettext("%s: malloc "
 358                                     "failed: %s\n"), File, strerror(err));
 359                                 exit(1);
 360                         }
 361                         if (pread64(EI->elffd, psinfo, dsz, offset) != dsz)
 362                                 return (ELF_READ_FAIL);
 363                         /*
 364                          * We want to print the string contained
 365                          * in psinfo->pr_fname[], where 'psinfo'
 366                          * is either an old NT_PRPSINFO structure
 367                          * or a new NT_PSINFO structure.
 368                          *
 369                          * Old core files have only type NT_PRPSINFO.
 370                          * New core files have type NT_PSINFO.
 371                          *
 372                          * These structures are also different by
 373                          * virtue of being contained in a core file
 374                          * of either 32-bit or 64-bit type.
 375                          *
 376                          * To further complicate matters, we ourself
 377                          * might be compiled either 32-bit or 64-bit.
 378                          *
 379                          * For these reason, we just *know* the offsets of
 380                          * pr_fname[] into the four different structures
 381                          * here, regardless of how we are compiled.
 382                          */
 383                         if (class == ELFCLASS32) {
 384                                 /* 32-bit core file, 32-bit structures */
 385                                 if (ntype == NT_PSINFO)
 386                                         fname = psinfo + 88;
 387                                 else    /* old: NT_PRPSINFO */
 388                                         fname = psinfo + 84;
 389                         } else if (class == ELFCLASS64) {
 390                                 /* 64-bit core file, 64-bit structures */
 391                                 if (ntype == NT_PSINFO)
 392                                         fname = psinfo + 136;
 393                                 else    /* old: NT_PRPSINFO */
 394                                         fname = psinfo + 120;
 395                         }
 396                         EI->core_type = (ntype == NT_PRPSINFO)?
 397                             EC_OLDCORE : EC_NEWCORE;
 398                         (void) memcpy(EI->fname, fname, strlen(fname));
 399                         free(psinfo);
 400                 }
 401                 if (phdr->p_type == PT_DYNAMIC) {
 402                         EI->dynamic = B_TRUE;
 403                 }
 404         }
 405         return (ELF_READ_OKAY);
 406 }
 407 
 408 /*
 409  * process_shdr:        Read Section Headers to attempt to get HW/SW
 410  *                      capabilities by looking at the SUNW_cap
 411  *                      section and set string in Elf_Info.
 412  *                      Also look for symbol tables and debug
 413  *                      information sections. Set the "stripped" field
 414  *                      in Elf_Info with corresponding flags.
 415  */
 416 static int
 417 process_shdr(Elf_Info *EI)
 418 {
 419         int             mac;
 420         int             i, j, idx;
 421         char            *strtab;
 422         size_t          strtab_sz;
 423         Elf_Shdr        *shdr = &EI_Shdr;
 424 
 425         mac = EI_Ehdr.e_machine;
 426 
 427         /* if there are no sections, return success anyway */
 428         if (EI_Ehdr.e_shoff == 0 && EI_Ehdr_shnum == 0)
 429                 return (ELF_READ_OKAY);
 430 
 431         /* read section names from String Section */
 432         if (get_shdr(EI, EI_Ehdr_shstrndx) == ELF_READ_FAIL)
 433                 return (ELF_READ_FAIL);
 434 
 435         if ((strtab = malloc(shdr->sh_size)) == NULL)
 436                 return (ELF_READ_FAIL);
 437 
 438         if (pread64(EI->elffd, strtab, shdr->sh_size, shdr->sh_offset)
 439             != shdr->sh_size)
 440                 return (ELF_READ_FAIL);
 441 
 442         strtab_sz = shdr->sh_size;
 443 
 444         /* read all the sections and process them */
 445         for (idx = 1, i = 0; i < EI_Ehdr_shnum; idx++, i++) {
 446                 char *shnam;
 447 
 448                 if (get_shdr(EI, i) == ELF_READ_FAIL)
 449                         return (ELF_READ_FAIL);
 450 
 451                 if (shdr->sh_type == SHT_NULL) {
 452                         idx--;
 453                         continue;
 454                 }
 455 
 456                 if (shdr->sh_type == SHT_SUNW_cap) {
 457                         char            capstr[128];
 458                         Elf_Cap         Chdr;
 459                         FILE_ELF_OFF_T  cap_off;
 460                         FILE_ELF_SIZE_T csize;
 461                         int capn;
 462 
 463                         cap_off = shdr->sh_offset;
 464                         csize = sizeof (Elf_Cap);
 465 
 466                         if (shdr->sh_size == 0 || shdr->sh_entsize == 0) {
 467                                 (void) fprintf(stderr, ELF_ERR_ELFCAP1,
 468                                     File, EI->file);
 469                                 return (ELF_READ_FAIL);
 470                         }
 471                         capn = (shdr->sh_size / shdr->sh_entsize);
 472                         for (j = 0; j < capn; j++) {
 473                                 /*
 474                                  * read cap and xlate the values
 475                                  */
 476                                 if ((pread64(EI->elffd, &Chdr, csize, cap_off)
 477                                     != csize) ||
 478                                     file_xlatetom(ELF_T_CAP, (char *)&Chdr)
 479                                     == 0) {
 480                                         (void) fprintf(stderr, ELF_ERR_ELFCAP2,
 481                                             File, EI->file);
 482                                         return (ELF_READ_FAIL);
 483                                 }
 484 
 485                                 cap_off += csize;
 486 
 487                                 /*
 488                                  * Each capatibility group is terminated with
 489                                  * CA_SUNW_NULL.  Groups other than the first
 490                                  * represent symbol capabilities, and aren't
 491                                  * interesting here.
 492                                  */
 493                                 if (Chdr.c_tag == CA_SUNW_NULL)
 494                                         break;
 495 
 496                                 (void) elfcap_tag_to_str(ELFCAP_STYLE_UC,
 497                                     Chdr.c_tag, Chdr.c_un.c_val, capstr,
 498                                     sizeof (capstr), ELFCAP_FMT_SNGSPACE,
 499                                     mac);
 500 
 501                                 if ((*EI->cap_str != '\0') && (*capstr != '\0'))
 502                                         (void) strlcat(EI->cap_str, " ",
 503                                             sizeof (EI->cap_str));
 504 
 505                                 (void) strlcat(EI->cap_str, capstr,
 506                                     sizeof (EI->cap_str));
 507                         }
 508                 } else if (shdr->sh_type == SHT_DYNAMIC) {
 509                         Elf_Dyn dyn;
 510                         FILE_ELF_SIZE_T dsize;
 511                         FILE_ELF_OFF_T doff;
 512                         int dynn;
 513 
 514                         doff = shdr->sh_offset;
 515                         dsize = sizeof (Elf_Dyn);
 516 
 517                         if (shdr->sh_size == 0 || shdr->sh_entsize == 0) {
 518                                 (void) fprintf(stderr, ELF_ERR_DYNAMIC1,
 519                                     File, EI->file);
 520                                 return (ELF_READ_FAIL);
 521                         }
 522 
 523                         dynn = (shdr->sh_size / shdr->sh_entsize);
 524                         for (j = 0; j < dynn; j++) {
 525                                 if (pread64(EI->elffd, &dyn, dsize, doff)
 526                                     != dsize ||
 527                                     file_xlatetom(ELF_T_DYN, (char *)&dyn)
 528                                     == 0) {
 529                                         (void) fprintf(stderr, ELF_ERR_DYNAMIC2,
 530                                             File, EI->file);
 531                                         return (ELF_READ_FAIL);
 532                                 }
 533 
 534                                 doff += dsize;
 535 
 536                                 if ((dyn.d_tag == DT_SUNW_KMOD) &&
 537                                     (dyn.d_un.d_val == 1)) {
 538                                         EI->kmod = B_TRUE;
 539                                 }
 540                         }
 541                 }
 542 
 543                 /*
 544                  * Definition time:
 545                  *      - "not stripped" means that an executable file
 546                  *      contains a Symbol Table (.symtab)
 547                  *      - "stripped" means that an executable file
 548                  *      does not contain a Symbol Table.
 549                  * When strip -l or strip -x is run, it strips the
 550                  * debugging information (.line section name (strip -l),
 551                  * .line, .debug*, .stabs*, .dwarf* section names
 552                  * and SHT_SUNW_DEBUGSTR and SHT_SUNW_DEBUG
 553                  * section types (strip -x), however the Symbol
 554                  * Table will still be present.
 555                  * Therefore, if
 556                  *      - No Symbol Table present, then report
 557                  *              "stripped"
 558                  *      - Symbol Table present with debugging
 559                  *      information (line number or debug section names,
 560                  *      or SHT_SUNW_DEBUGSTR or SHT_SUNW_DEBUG section
 561                  *      types) then report:
 562                  *              "not stripped"
 563                  *      - Symbol Table present with no debugging
 564                  *      information (line number or debug section names,
 565                  *      or SHT_SUNW_DEBUGSTR or SHT_SUNW_DEBUG section
 566                  *      types) then report:
 567                  *              "not stripped, no debugging information
 568                  *              available"
 569                  */
 570                 if ((EI->stripped & E_NOSTRIP) == E_NOSTRIP)
 571                         continue;
 572 
 573                 if (!(EI->stripped & E_SYMTAB) &&
 574                     (shdr->sh_type == SHT_SYMTAB)) {
 575                         EI->stripped |= E_SYMTAB;
 576                         continue;
 577                 }
 578 
 579                 if (shdr->sh_name >= strtab_sz)
 580                         shnam = NULL;
 581                 else
 582                         shnam = &strtab[shdr->sh_name];
 583 
 584                 if (!(EI->stripped & E_DBGINF) &&
 585                     ((shdr->sh_type == SHT_SUNW_DEBUG) ||
 586                     (shdr->sh_type == SHT_SUNW_DEBUGSTR) ||
 587                     (shnam != NULL && is_in_list(shnam)))) {
 588                         EI->stripped |= E_DBGINF;
 589                 }
 590         }
 591         free(strtab);
 592 
 593         return (ELF_READ_OKAY);
 594 }