1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 23*0Sstevel@tonic-gate /* All Rights Reserved */ 24*0Sstevel@tonic-gate 25*0Sstevel@tonic-gate 26*0Sstevel@tonic-gate /* 27*0Sstevel@tonic-gate * Copyright (c) 1998 by Sun Microsystems, Inc. 28*0Sstevel@tonic-gate * All rights reserved. 29*0Sstevel@tonic-gate */ 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.10 */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include "syn.h" 34*0Sstevel@tonic-gate #include <string.h> 35*0Sstevel@tonic-gate #include <ar.h> 36*0Sstevel@tonic-gate #include <stdlib.h> 37*0Sstevel@tonic-gate #include <sys/mman.h> 38*0Sstevel@tonic-gate #include <errno.h> 39*0Sstevel@tonic-gate #include <libelf.h> 40*0Sstevel@tonic-gate #include "decl.h" 41*0Sstevel@tonic-gate #include "member.h" 42*0Sstevel@tonic-gate #include "msg.h" 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate #include <sys/mman.h> 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate /* 47*0Sstevel@tonic-gate * Cook the input file. 48*0Sstevel@tonic-gate * These functions take the input file buffer and extract 49*0Sstevel@tonic-gate * the Ehdr, Phdr table, and the Shdr table. They keep track 50*0Sstevel@tonic-gate * of the buffer status as "fresh," "cooked," or "frozen." 51*0Sstevel@tonic-gate * 52*0Sstevel@tonic-gate * fresh The file buffer is in its original state and 53*0Sstevel@tonic-gate * nothing has yet referenced it. 54*0Sstevel@tonic-gate * 55*0Sstevel@tonic-gate * cooked The application asked for translated data first 56*0Sstevel@tonic-gate * and caused the library to return a pointer into 57*0Sstevel@tonic-gate * the file buffer. After this happens, all "raw" 58*0Sstevel@tonic-gate * operations must go back to the disk. 59*0Sstevel@tonic-gate * 60*0Sstevel@tonic-gate * frozen The application first did a "raw" operation that 61*0Sstevel@tonic-gate * prohibits reusing the file buffer. This effectively 62*0Sstevel@tonic-gate * freezes the buffer, and all "normal" operations must 63*0Sstevel@tonic-gate * duplicate their data. 64*0Sstevel@tonic-gate * 65*0Sstevel@tonic-gate * For archive handling, these functions conspire to align the 66*0Sstevel@tonic-gate * file buffer to the host memory format. Archive members 67*0Sstevel@tonic-gate * are guaranteed only even byte alignment, but the file uses 68*0Sstevel@tonic-gate * objects at least 4 bytes long. If an archive member is about 69*0Sstevel@tonic-gate * to be cooked and is not aligned in memory, these functions 70*0Sstevel@tonic-gate * "slide" the buffer up into the archive member header. 71*0Sstevel@tonic-gate * This sliding never occurs for frozen files. 72*0Sstevel@tonic-gate * 73*0Sstevel@tonic-gate * Some processors might not need sliding at all, if they have 74*0Sstevel@tonic-gate * no alignment constraints on memory references. This code 75*0Sstevel@tonic-gate * ignores that possibility for two reasons. First, even machines 76*0Sstevel@tonic-gate * that have no constraints usually handle aligned objects faster 77*0Sstevel@tonic-gate * than unaligned. Forcing alignment here probably leads to better 78*0Sstevel@tonic-gate * performance. Second, there's no way to test at run time whether 79*0Sstevel@tonic-gate * alignment is required or not. The safe thing is to align in 80*0Sstevel@tonic-gate * all cases. 81*0Sstevel@tonic-gate * 82*0Sstevel@tonic-gate * This sliding relies on the archive header being disposable. 83*0Sstevel@tonic-gate * Only archive members that are object files ever slide. 84*0Sstevel@tonic-gate * They're also the only ones that ever need to. Archives never 85*0Sstevel@tonic-gate * freeze to make headers disposable. Any program peculiar enough 86*0Sstevel@tonic-gate * to want a frozen archive pays the penalty. 87*0Sstevel@tonic-gate * 88*0Sstevel@tonic-gate * The library itself inspects the Ehdr and the Shdr table 89*0Sstevel@tonic-gate * from the file. Consequently, it converts the file's data 90*0Sstevel@tonic-gate * to EV_CURRENT version, not the working version. This is 91*0Sstevel@tonic-gate * transparent to the user. The library never looks at the 92*0Sstevel@tonic-gate * Phdr table; so that's kept in the working version. 93*0Sstevel@tonic-gate */ 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate Dnode * 96*0Sstevel@tonic-gate _elf_dnode() 97*0Sstevel@tonic-gate { 98*0Sstevel@tonic-gate register Dnode *d; 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate if ((d = (Dnode *)malloc(sizeof (Dnode))) == 0) { 101*0Sstevel@tonic-gate _elf_seterr(EMEM_DNODE, errno); 102*0Sstevel@tonic-gate return (0); 103*0Sstevel@tonic-gate } 104*0Sstevel@tonic-gate NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*d)) 105*0Sstevel@tonic-gate *d = _elf_dnode_init; 106*0Sstevel@tonic-gate d->db_myflags = DBF_ALLOC; 107*0Sstevel@tonic-gate NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*d)) 108*0Sstevel@tonic-gate return (d); 109*0Sstevel@tonic-gate } 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate int 114*0Sstevel@tonic-gate _elf_slide(Elf * elf) 115*0Sstevel@tonic-gate { 116*0Sstevel@tonic-gate NOTE(ASSUMING_PROTECTED(*elf)) 117*0Sstevel@tonic-gate Elf *par = elf->ed_parent; 118*0Sstevel@tonic-gate size_t sz, szof; 119*0Sstevel@tonic-gate register char *dst; 120*0Sstevel@tonic-gate register char *src = elf->ed_ident; 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate if (par == 0 || par->ed_kind != ELF_K_AR) 123*0Sstevel@tonic-gate return (0); 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate /* 126*0Sstevel@tonic-gate * This code relies on other code to ensure 127*0Sstevel@tonic-gate * the ar_hdr is big enough to move into. 128*0Sstevel@tonic-gate */ 129*0Sstevel@tonic-gate if (elf->ed_ident[EI_CLASS] == ELFCLASS64) 130*0Sstevel@tonic-gate szof = sizeof (Elf64); 131*0Sstevel@tonic-gate else 132*0Sstevel@tonic-gate szof = sizeof (Elf32); 133*0Sstevel@tonic-gate if ((sz = (size_t)(src - (char *)elf->ed_image) % szof) == 0) 134*0Sstevel@tonic-gate return (0); 135*0Sstevel@tonic-gate dst = src - sz; 136*0Sstevel@tonic-gate elf->ed_ident -= sz; 137*0Sstevel@tonic-gate elf->ed_memoff -= sz; 138*0Sstevel@tonic-gate elf->ed_armem->m_slide = sz; 139*0Sstevel@tonic-gate if (_elf_vm(par, elf->ed_memoff, sz + elf->ed_fsz) != OK_YES) 140*0Sstevel@tonic-gate return (-1); 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate /* 143*0Sstevel@tonic-gate * If the archive has been mmaped in, and we're going to slide it, 144*0Sstevel@tonic-gate * and it wasn't open for write in the first place, and we've never 145*0Sstevel@tonic-gate * done the mprotect() operation before, then do it now. 146*0Sstevel@tonic-gate */ 147*0Sstevel@tonic-gate if ((elf->ed_vm == 0) && ((elf->ed_myflags & EDF_WRITE) == 0) && 148*0Sstevel@tonic-gate ((elf->ed_myflags & EDF_MPROTECT) == 0)) { 149*0Sstevel@tonic-gate if (mprotect((char *)elf->ed_image, elf->ed_imagesz, 150*0Sstevel@tonic-gate PROT_READ|PROT_WRITE) == -1) { 151*0Sstevel@tonic-gate _elf_seterr(EIO_VM, errno); 152*0Sstevel@tonic-gate return (-1); 153*0Sstevel@tonic-gate } 154*0Sstevel@tonic-gate elf->ed_myflags |= EDF_MPROTECT; 155*0Sstevel@tonic-gate } 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate if (memmove((void *)dst, (const void *)src, elf->ed_fsz) != (void *)dst) 158*0Sstevel@tonic-gate return (-1); 159*0Sstevel@tonic-gate else 160*0Sstevel@tonic-gate return (0); 161*0Sstevel@tonic-gate } 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate Okay 165*0Sstevel@tonic-gate _elf_cook(Elf * elf) 166*0Sstevel@tonic-gate { 167*0Sstevel@tonic-gate NOTE(ASSUMING_PROTECTED(*elf)) 168*0Sstevel@tonic-gate register int inplace = 1; 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate if (elf->ed_kind != ELF_K_ELF) 171*0Sstevel@tonic-gate return (OK_YES); 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate if ((elf->ed_status == ES_COOKED) || 174*0Sstevel@tonic-gate ((elf->ed_myflags & EDF_READ) == 0)) 175*0Sstevel@tonic-gate return (OK_YES); 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate /* 178*0Sstevel@tonic-gate * Here's where the unaligned archive member gets fixed. 179*0Sstevel@tonic-gate */ 180*0Sstevel@tonic-gate if (elf->ed_status == ES_FRESH && _elf_slide(elf) != 0) 181*0Sstevel@tonic-gate return (OK_NO); 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate if (elf->ed_status == ES_FROZEN) 184*0Sstevel@tonic-gate inplace = 0; 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate /* 187*0Sstevel@tonic-gate * This is the first time we've actually looked at the file 188*0Sstevel@tonic-gate * contents. We need to know whether or not this is an 189*0Sstevel@tonic-gate * Elf32 or Elf64 file before we can decode the header. 190*0Sstevel@tonic-gate * But it's the header that tells us which is which. 191*0Sstevel@tonic-gate * 192*0Sstevel@tonic-gate * Resolve the chicken-and-egg problem by peeking at the 193*0Sstevel@tonic-gate * 'class' byte in the ident string. 194*0Sstevel@tonic-gate */ 195*0Sstevel@tonic-gate if (elf->ed_ident[EI_CLASS] == ELFCLASS32) { 196*0Sstevel@tonic-gate if (_elf32_ehdr(elf, inplace) != 0) 197*0Sstevel@tonic-gate return (OK_NO); 198*0Sstevel@tonic-gate if (_elf32_phdr(elf, inplace) != 0) 199*0Sstevel@tonic-gate goto xehdr; 200*0Sstevel@tonic-gate if (_elf32_shdr(elf, inplace) != 0) 201*0Sstevel@tonic-gate goto xphdr; 202*0Sstevel@tonic-gate elf->ed_class = ELFCLASS32; 203*0Sstevel@tonic-gate } else if (elf->ed_ident[EI_CLASS] == ELFCLASS64) { 204*0Sstevel@tonic-gate if (_elf64_ehdr(elf, inplace) != 0) 205*0Sstevel@tonic-gate return (OK_NO); 206*0Sstevel@tonic-gate if (_elf64_phdr(elf, inplace) != 0) 207*0Sstevel@tonic-gate goto xehdr; 208*0Sstevel@tonic-gate if (_elf64_shdr(elf, inplace) != 0) 209*0Sstevel@tonic-gate goto xphdr; 210*0Sstevel@tonic-gate elf->ed_class = ELFCLASS64; 211*0Sstevel@tonic-gate } else 212*0Sstevel@tonic-gate return (OK_NO); 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate return (OK_YES); 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate xphdr: 217*0Sstevel@tonic-gate if (elf->ed_myflags & EDF_PHALLOC) { 218*0Sstevel@tonic-gate elf->ed_myflags &= ~EDF_PHALLOC; 219*0Sstevel@tonic-gate free(elf->ed_phdr); 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate elf->ed_phdr = 0; 222*0Sstevel@tonic-gate xehdr: 223*0Sstevel@tonic-gate if (elf->ed_myflags & EDF_EHALLOC) { 224*0Sstevel@tonic-gate elf->ed_myflags &= ~EDF_EHALLOC; 225*0Sstevel@tonic-gate free(elf->ed_ehdr); 226*0Sstevel@tonic-gate } 227*0Sstevel@tonic-gate elf->ed_ehdr = 0; 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate return (OK_NO); 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate Okay 234*0Sstevel@tonic-gate _elf_cookscn(Elf_Scn * s) 235*0Sstevel@tonic-gate { 236*0Sstevel@tonic-gate Elf * elf = s->s_elf; 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate if (elf->ed_class == ELFCLASS32) { 239*0Sstevel@tonic-gate return (_elf32_cookscn(s)); 240*0Sstevel@tonic-gate } else if (elf->ed_class == ELFCLASS64) { 241*0Sstevel@tonic-gate return (_elf64_cookscn(s)); 242*0Sstevel@tonic-gate } 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate _elf_seterr(EREQ_CLASS, 0); 245*0Sstevel@tonic-gate return (OK_NO); 246*0Sstevel@tonic-gate } 247