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 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*      Copyright (c) 1988 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 /*
  31  * This stuff used to live in cook.c, but was moved out to
  32  * facilitate dual (Elf32 and Elf64) compilation.  See block
  33  * comment in cook.c for more info.
  34  */
  35 
  36 #include <string.h>
  37 #include <ar.h>
  38 #include <stdlib.h>
  39 #include <errno.h>
  40 #include <sys/sysmacros.h>
  41 #include "decl.h"
  42 #include "member.h"
  43 #include "msg.h"
  44 
  45 /*
  46  * This module is compiled twice, the second time having
  47  * -D_ELF64 defined.  The following set of macros, along
  48  * with machelf.h, represent the differences between the
  49  * two compilations.  Be careful *not* to add any class-
  50  * dependent code (anything that has elf32 or elf64 in the
  51  * name) to this code without hiding it behind a switch-
  52  * able macro like these.
  53  */
  54 #if     defined(_ELF64)
  55 #define Snode           Snode64
  56 #define ELFCLASS        ELFCLASS64
  57 #define ElfField        Elf64
  58 #define _elf_snode_init _elf64_snode_init
  59 #define _elf_prepscan   _elf64_prepscan
  60 #define _elf_cookscn    _elf64_cookscn
  61 #define _elf_mtype      _elf64_mtype
  62 #define _elf_msize      _elf64_msize
  63 #define elf_fsize       elf64_fsize
  64 #define _elf_snode      _elf64_snode
  65 #define _elf_ehdr       _elf64_ehdr
  66 #define elf_xlatetom    elf64_xlatetom
  67 #define _elf_phdr       _elf64_phdr
  68 #define _elf_shdr       _elf64_shdr
  69 #define _elf_prepscn    _elf64_prepscn
  70 
  71 #else  /* Elf32 */
  72 #define Snode           Snode32
  73 #define ELFCLASS        ELFCLASS32
  74 #define ElfField        Elf32
  75 #define _elf_snode_init _elf32_snode_init
  76 #define _elf_prepscan   _elf32_prepscan
  77 #define _elf_cookscn    _elf32_cookscn
  78 #define _elf_mtype      _elf32_mtype
  79 #define _elf_msize      _elf32_msize
  80 #define elf_fsize       elf32_fsize
  81 #define _elf_snode      _elf32_snode
  82 #define _elf_ehdr       _elf32_ehdr
  83 #define elf_xlatetom    elf32_xlatetom
  84 #define _elf_phdr       _elf32_phdr
  85 #define _elf_shdr       _elf32_shdr
  86 #define _elf_prepscn    _elf32_prepscn
  87 
  88 #endif /* _ELF64 */
  89 
  90 
  91 static Okay
  92 _elf_prepscn(Elf *elf, size_t cnt)
  93 {
  94         NOTE(ASSUMING_PROTECTED(*elf))
  95         Elf_Scn *       s;
  96         Elf_Scn *       end;
  97 
  98         if (cnt == 0)
  99                 return (OK_YES);
 100 
 101         if ((s = malloc(cnt * sizeof (Elf_Scn))) == 0) {
 102                 _elf_seterr(EMEM_SCN, errno);
 103                 return (OK_NO);
 104         }
 105         NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*s))
 106         elf->ed_scntabsz = cnt;
 107         end = s + cnt;
 108         elf->ed_hdscn = s;
 109         do {
 110                 *s = _elf_snode_init.sb_scn;
 111                 s->s_elf = elf;
 112                 s->s_next = s + 1;
 113                 s->s_index = s - elf->ed_hdscn;
 114                 s->s_shdr = (Shdr*)s->s_elf->ed_shdr + s->s_index;
 115                 ELFMUTEXINIT(&s->s_mutex);
 116 
 117                 /*
 118                  * Section has not yet been cooked!
 119                  *
 120                  * We don't cook a section until it's data is actually
 121                  * referenced.
 122                  */
 123                 s->s_myflags = 0;
 124         } while (++s < end);
 125 
 126         elf->ed_tlscn = --s;
 127         s->s_next = 0;
 128 
 129         /*
 130          * Section index SHN_UNDEF (0) does not and cannot
 131          * have a data buffer.  Fix it here.  Also mark the
 132          * initial section as being allocated for the block
 133          */
 134 
 135         s = elf->ed_hdscn;
 136         s->s_myflags = SF_ALLOC;
 137         s->s_hdnode = 0;
 138         s->s_tlnode = 0;
 139         NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*s))
 140         return (OK_YES);
 141 }
 142 
 143 
 144 Okay
 145 _elf_cookscn(Elf_Scn * s)
 146 {
 147         NOTE(ASSUMING_PROTECTED(*s, *(s->s_elf)))
 148         Elf *                   elf;
 149         Shdr *                  sh;
 150         register Dnode *        d = &s->s_dnode;
 151         size_t                  fsz, msz;
 152         unsigned                work;
 153 
 154         NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*d))
 155         s->s_hdnode = s->s_tlnode = d;
 156         s->s_err = 0;
 157         s->s_shflags = 0;
 158         s->s_uflags = 0;
 159 
 160 
 161         /*
 162          * Prepare d_data for inspection, but don't actually
 163          * translate data until needed.  Leave the READY
 164          * flag off.  NOBITS sections see zero size.
 165          */
 166         elf = s->s_elf;
 167         sh = s->s_shdr;
 168 
 169         d->db_scn = s;
 170         d->db_off = sh->sh_offset;
 171         d->db_data.d_align = sh->sh_addralign;
 172         d->db_data.d_version = elf->ed_version;
 173         ELFACCESSDATA(work, _elf_work)
 174         d->db_data.d_type = _elf_mtype(elf, sh->sh_type, work);
 175         d->db_data.d_buf = 0;
 176         d->db_data.d_off = 0;
 177         fsz = elf_fsize(d->db_data.d_type, 1, elf->ed_version);
 178         msz = _elf_msize(d->db_data.d_type, elf->ed_version);
 179         d->db_data.d_size = MAX(sh->sh_size, (sh->sh_size / fsz) * msz);
 180         d->db_shsz = sh->sh_size;
 181         d->db_raw = 0;
 182         d->db_buf = 0;
 183         d->db_uflags = 0;
 184         d->db_myflags = 0;
 185         d->db_next = 0;
 186 
 187         if (sh->sh_type != SHT_NOBITS)
 188                 d->db_fsz = sh->sh_size;
 189         else
 190                 d->db_fsz = 0;
 191 
 192         s->s_myflags |= SF_READY;
 193 
 194         NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*d))
 195         return (OK_YES);
 196 }
 197 
 198 
 199 
 200 Snode *
 201 _elf_snode()
 202 {
 203         register Snode  *s;
 204 
 205         if ((s = malloc(sizeof (Snode))) == 0) {
 206                 _elf_seterr(EMEM_SNODE, errno);
 207                 return (0);
 208         }
 209         *s = _elf_snode_init;
 210         ELFMUTEXINIT(&s->sb_scn.s_mutex);
 211         s->sb_scn.s_myflags = SF_ALLOC | SF_READY;
 212         s->sb_scn.s_shdr = &s->sb_shdr;
 213         return (s);
 214 }
 215 
 216 
 217 
 218 int
 219 _elf_ehdr(Elf * elf, int inplace)
 220 {
 221         NOTE(ASSUMING_PROTECTED(*elf))
 222         register size_t fsz;            /* field size */
 223         Elf_Data        dst, src;
 224 
 225         fsz = elf_fsize(ELF_T_EHDR, 1, elf->ed_version);
 226         if (fsz > elf->ed_fsz) {
 227                 _elf_seterr(EFMT_EHDRSZ, 0);
 228                 return (-1);
 229         }
 230         if (inplace && (fsz >= sizeof (Ehdr))) {
 231                 /*
 232                  * The translated Ehdr will fit over the original Ehdr.
 233                  */
 234                 /* LINTED */
 235                 elf->ed_ehdr = (Ehdr *)elf->ed_ident;
 236                 elf->ed_status = ES_COOKED;
 237         } else {
 238                 elf->ed_ehdr = malloc(sizeof (Ehdr));
 239                 if (elf->ed_ehdr == 0) {
 240                         _elf_seterr(EMEM_EHDR, errno);
 241                         return (-1);
 242                 }
 243                 elf->ed_myflags |= EDF_EHALLOC;
 244         }
 245 
 246         /*
 247          * Memory size >= fsz, because otherwise the memory version
 248          * loses information and cannot accurately implement the
 249          * file.
 250          */
 251 
 252         src.d_buf = (Elf_Void *)elf->ed_ident;
 253         src.d_type = ELF_T_EHDR;
 254         src.d_size = fsz;
 255         src.d_version = elf->ed_version;
 256         dst.d_buf = (Elf_Void *)elf->ed_ehdr;
 257         dst.d_size = sizeof (Ehdr);
 258         dst.d_version = EV_CURRENT;
 259 
 260         if ((_elf_vm(elf, (size_t)0, fsz) != OK_YES) ||
 261             (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) {
 262                 if (elf->ed_myflags & EDF_EHALLOC) {
 263                         elf->ed_myflags &= ~EDF_EHALLOC;
 264                         free(elf->ed_ehdr);
 265                 }
 266                 elf->ed_ehdr = 0;
 267                 return (-1);
 268         }
 269 
 270         if (((Ehdr*)elf->ed_ehdr)->e_ident[EI_CLASS] != ELFCLASS) {
 271                 _elf_seterr(EREQ_CLASS, 0);
 272                 if (elf->ed_myflags & EDF_EHALLOC) {
 273                         elf->ed_myflags &= ~EDF_EHALLOC;
 274                         free(elf->ed_ehdr);
 275                 }
 276                 elf->ed_ehdr = 0;
 277                 return (-1);
 278         }
 279 
 280         if (((Ehdr*)elf->ed_ehdr)->e_version != elf->ed_version) {
 281                 _elf_seterr(EFMT_VER2, 0);
 282                 if (elf->ed_myflags & EDF_EHALLOC) {
 283                         elf->ed_myflags &= ~EDF_EHALLOC;
 284                         free(elf->ed_ehdr);
 285                 }
 286                 elf->ed_ehdr = 0;
 287                 return (-1);
 288         }
 289 
 290         return (0);
 291 }
 292 
 293 
 294 
 295 int
 296 _elf_phdr(Elf * elf, int inplace)
 297 {
 298         NOTE(ASSUMING_PROTECTED(*elf))
 299         register size_t         fsz, msz;
 300         Elf_Data                dst, src;
 301         Ehdr *                  eh = elf->ed_ehdr;   /* must be present */
 302         unsigned                work;
 303 
 304         if (eh->e_phnum == 0)
 305                 return (0);
 306 
 307         fsz = elf_fsize(ELF_T_PHDR, 1, elf->ed_version);
 308         if (eh->e_phentsize != fsz) {
 309                 _elf_seterr(EFMT_PHDRSZ, 0);
 310                 return (-1);
 311         }
 312 
 313         fsz *= eh->e_phnum;
 314         ELFACCESSDATA(work, _elf_work)
 315         msz = _elf_msize(ELF_T_PHDR, work) * eh->e_phnum;
 316         if ((eh->e_phoff == 0) ||
 317             ((fsz + eh->e_phoff) > elf->ed_fsz)) {
 318                 _elf_seterr(EFMT_PHTAB, 0);
 319                 return (-1);
 320         }
 321 
 322         if (inplace && fsz >= msz && eh->e_phoff % sizeof (ElfField) == 0) {
 323                 elf->ed_phdr = (Elf_Void *)(elf->ed_ident + eh->e_phoff);
 324                 elf->ed_status = ES_COOKED;
 325         } else {
 326                 if ((elf->ed_phdr = malloc(msz)) == 0) {
 327                         _elf_seterr(EMEM_PHDR, errno);
 328                         return (-1);
 329                 }
 330                 elf->ed_myflags |= EDF_PHALLOC;
 331         }
 332         src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_phoff);
 333         src.d_type = ELF_T_PHDR;
 334         src.d_size = fsz;
 335         src.d_version = elf->ed_version;
 336         dst.d_buf = elf->ed_phdr;
 337         dst.d_size = msz;
 338         dst.d_version = work;
 339         if ((_elf_vm(elf, (size_t)eh->e_phoff, fsz) != OK_YES) ||
 340             (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) {
 341                 if (elf->ed_myflags & EDF_PHALLOC) {
 342                         elf->ed_myflags &= ~EDF_PHALLOC;
 343                         free(elf->ed_phdr);
 344                 }
 345                 elf->ed_phdr = 0;
 346                 return (-1);
 347         }
 348         elf->ed_phdrsz = msz;
 349         return (0);
 350 }
 351 
 352 
 353 
 354 int
 355 _elf_shdr(Elf * elf, int inplace)
 356 {
 357         NOTE(ASSUMING_PROTECTED(*elf))
 358         register size_t         fsz, msz;
 359         size_t                  scncnt;
 360         Elf_Data                dst, src;
 361         register Ehdr           *eh = elf->ed_ehdr;  /* must be present */
 362 
 363         if ((eh->e_shnum == 0) && (eh->e_shoff == 0))
 364                 return (0);
 365 
 366         fsz = elf_fsize(ELF_T_SHDR, 1, elf->ed_version);
 367         if (eh->e_shentsize != fsz) {
 368                 _elf_seterr(EFMT_SHDRSZ, 0);
 369                 return (-1);
 370         }
 371         /*
 372          * If we are dealing with a file with 'extended section
 373          * indexes' - then we need to load the first section
 374          * header.  The actual section count is stored in
 375          * Shdr[0].sh_size.
 376          */
 377         if ((scncnt = eh->e_shnum) == 0) {
 378                 Shdr    sh;
 379                 if ((eh->e_shoff == 0) ||
 380                     (elf->ed_fsz <= eh->e_shoff) ||
 381                     (elf->ed_fsz - eh->e_shoff < fsz)) {
 382                         _elf_seterr(EFMT_SHTAB, 0);
 383                         return (-1);
 384                 }
 385                 src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_shoff);
 386                 src.d_type = ELF_T_SHDR;
 387                 src.d_size = fsz;
 388                 src.d_version = elf->ed_version;
 389                 dst.d_buf = (Elf_Void *)&sh;
 390                 dst.d_size = sizeof (Shdr);
 391                 dst.d_version = EV_CURRENT;
 392                 if ((_elf_vm(elf, (size_t)eh->e_shoff, fsz) != OK_YES) ||
 393                     (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) {
 394                         return (-1);
 395                 }
 396                 scncnt = sh.sh_size;
 397         }
 398 
 399         fsz *= scncnt;
 400         msz = scncnt * sizeof (Shdr);
 401         if ((eh->e_shoff == 0) ||
 402             (elf->ed_fsz <= eh->e_shoff) ||
 403             (elf->ed_fsz - eh->e_shoff < fsz)) {
 404                 _elf_seterr(EFMT_SHTAB, 0);
 405                 return (-1);
 406         }
 407 
 408         if (inplace && (fsz >= msz) &&
 409             ((eh->e_shoff % sizeof (ElfField)) == 0)) {
 410                 /* LINTED */
 411                 elf->ed_shdr = (Shdr *)(elf->ed_ident + eh->e_shoff);
 412                 elf->ed_status = ES_COOKED;
 413         } else {
 414                 if ((elf->ed_shdr = malloc(msz)) == 0) {
 415                         _elf_seterr(EMEM_SHDR, errno);
 416                         return (-1);
 417                 }
 418                 elf->ed_myflags |= EDF_SHALLOC;
 419         }
 420         src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_shoff);
 421         src.d_type = ELF_T_SHDR;
 422         src.d_size = fsz;
 423         src.d_version = elf->ed_version;
 424         dst.d_buf = (Elf_Void *)elf->ed_shdr;
 425         dst.d_size = msz;
 426         dst.d_version = EV_CURRENT;
 427         if ((_elf_vm(elf, (size_t)eh->e_shoff, fsz) != OK_YES) ||
 428             (elf_xlatetom(&dst, &src, elf->ed_encode) == 0) ||
 429             (_elf_prepscn(elf, scncnt) != OK_YES)) {
 430                 if (elf->ed_myflags & EDF_SHALLOC) {
 431                         elf->ed_myflags &= ~EDF_SHALLOC;
 432                         free(elf->ed_shdr);
 433                 }
 434                 elf->ed_shdr = 0;
 435                 return (-1);
 436         }
 437         return (0);
 438 }