17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7257d1b4Sraf * Common Development and Distribution License (the "License"). 6*7257d1b4Sraf * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21*7257d1b4Sraf 22*7257d1b4Sraf /* 23*7257d1b4Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*7257d1b4Sraf * Use is subject to license terms. 25*7257d1b4Sraf */ 26*7257d1b4Sraf 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 30*7257d1b4Sraf #pragma ident "%Z%%M% %I% %E% SMI" 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <string.h> 337c478bd9Sstevel@tonic-gate #include <ar.h> 347c478bd9Sstevel@tonic-gate #include <stdlib.h> 357c478bd9Sstevel@tonic-gate #include <sys/mman.h> 367c478bd9Sstevel@tonic-gate #include <errno.h> 377c478bd9Sstevel@tonic-gate #include <libelf.h> 387c478bd9Sstevel@tonic-gate #include "decl.h" 397c478bd9Sstevel@tonic-gate #include "member.h" 407c478bd9Sstevel@tonic-gate #include "msg.h" 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <sys/mman.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /* 457c478bd9Sstevel@tonic-gate * Cook the input file. 467c478bd9Sstevel@tonic-gate * These functions take the input file buffer and extract 477c478bd9Sstevel@tonic-gate * the Ehdr, Phdr table, and the Shdr table. They keep track 487c478bd9Sstevel@tonic-gate * of the buffer status as "fresh," "cooked," or "frozen." 497c478bd9Sstevel@tonic-gate * 507c478bd9Sstevel@tonic-gate * fresh The file buffer is in its original state and 517c478bd9Sstevel@tonic-gate * nothing has yet referenced it. 527c478bd9Sstevel@tonic-gate * 537c478bd9Sstevel@tonic-gate * cooked The application asked for translated data first 547c478bd9Sstevel@tonic-gate * and caused the library to return a pointer into 557c478bd9Sstevel@tonic-gate * the file buffer. After this happens, all "raw" 567c478bd9Sstevel@tonic-gate * operations must go back to the disk. 577c478bd9Sstevel@tonic-gate * 587c478bd9Sstevel@tonic-gate * frozen The application first did a "raw" operation that 597c478bd9Sstevel@tonic-gate * prohibits reusing the file buffer. This effectively 607c478bd9Sstevel@tonic-gate * freezes the buffer, and all "normal" operations must 617c478bd9Sstevel@tonic-gate * duplicate their data. 627c478bd9Sstevel@tonic-gate * 637c478bd9Sstevel@tonic-gate * For archive handling, these functions conspire to align the 647c478bd9Sstevel@tonic-gate * file buffer to the host memory format. Archive members 657c478bd9Sstevel@tonic-gate * are guaranteed only even byte alignment, but the file uses 667c478bd9Sstevel@tonic-gate * objects at least 4 bytes long. If an archive member is about 677c478bd9Sstevel@tonic-gate * to be cooked and is not aligned in memory, these functions 687c478bd9Sstevel@tonic-gate * "slide" the buffer up into the archive member header. 697c478bd9Sstevel@tonic-gate * This sliding never occurs for frozen files. 707c478bd9Sstevel@tonic-gate * 717c478bd9Sstevel@tonic-gate * Some processors might not need sliding at all, if they have 727c478bd9Sstevel@tonic-gate * no alignment constraints on memory references. This code 737c478bd9Sstevel@tonic-gate * ignores that possibility for two reasons. First, even machines 747c478bd9Sstevel@tonic-gate * that have no constraints usually handle aligned objects faster 757c478bd9Sstevel@tonic-gate * than unaligned. Forcing alignment here probably leads to better 767c478bd9Sstevel@tonic-gate * performance. Second, there's no way to test at run time whether 777c478bd9Sstevel@tonic-gate * alignment is required or not. The safe thing is to align in 787c478bd9Sstevel@tonic-gate * all cases. 797c478bd9Sstevel@tonic-gate * 807c478bd9Sstevel@tonic-gate * This sliding relies on the archive header being disposable. 817c478bd9Sstevel@tonic-gate * Only archive members that are object files ever slide. 827c478bd9Sstevel@tonic-gate * They're also the only ones that ever need to. Archives never 837c478bd9Sstevel@tonic-gate * freeze to make headers disposable. Any program peculiar enough 847c478bd9Sstevel@tonic-gate * to want a frozen archive pays the penalty. 857c478bd9Sstevel@tonic-gate * 867c478bd9Sstevel@tonic-gate * The library itself inspects the Ehdr and the Shdr table 877c478bd9Sstevel@tonic-gate * from the file. Consequently, it converts the file's data 887c478bd9Sstevel@tonic-gate * to EV_CURRENT version, not the working version. This is 897c478bd9Sstevel@tonic-gate * transparent to the user. The library never looks at the 907c478bd9Sstevel@tonic-gate * Phdr table; so that's kept in the working version. 917c478bd9Sstevel@tonic-gate */ 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate Dnode * 947c478bd9Sstevel@tonic-gate _elf_dnode() 957c478bd9Sstevel@tonic-gate { 967c478bd9Sstevel@tonic-gate register Dnode *d; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate if ((d = (Dnode *)malloc(sizeof (Dnode))) == 0) { 997c478bd9Sstevel@tonic-gate _elf_seterr(EMEM_DNODE, errno); 1007c478bd9Sstevel@tonic-gate return (0); 1017c478bd9Sstevel@tonic-gate } 1027c478bd9Sstevel@tonic-gate NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*d)) 1037c478bd9Sstevel@tonic-gate *d = _elf_dnode_init; 1047c478bd9Sstevel@tonic-gate d->db_myflags = DBF_ALLOC; 1057c478bd9Sstevel@tonic-gate NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*d)) 1067c478bd9Sstevel@tonic-gate return (d); 1077c478bd9Sstevel@tonic-gate } 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate int 1127c478bd9Sstevel@tonic-gate _elf_slide(Elf * elf) 1137c478bd9Sstevel@tonic-gate { 1147c478bd9Sstevel@tonic-gate NOTE(ASSUMING_PROTECTED(*elf)) 1157c478bd9Sstevel@tonic-gate Elf *par = elf->ed_parent; 1167c478bd9Sstevel@tonic-gate size_t sz, szof; 1177c478bd9Sstevel@tonic-gate register char *dst; 1187c478bd9Sstevel@tonic-gate register char *src = elf->ed_ident; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate if (par == 0 || par->ed_kind != ELF_K_AR) 1217c478bd9Sstevel@tonic-gate return (0); 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate /* 1247c478bd9Sstevel@tonic-gate * This code relies on other code to ensure 1257c478bd9Sstevel@tonic-gate * the ar_hdr is big enough to move into. 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate if (elf->ed_ident[EI_CLASS] == ELFCLASS64) 1287c478bd9Sstevel@tonic-gate szof = sizeof (Elf64); 1297c478bd9Sstevel@tonic-gate else 1307c478bd9Sstevel@tonic-gate szof = sizeof (Elf32); 1317c478bd9Sstevel@tonic-gate if ((sz = (size_t)(src - (char *)elf->ed_image) % szof) == 0) 1327c478bd9Sstevel@tonic-gate return (0); 1337c478bd9Sstevel@tonic-gate dst = src - sz; 1347c478bd9Sstevel@tonic-gate elf->ed_ident -= sz; 1357c478bd9Sstevel@tonic-gate elf->ed_memoff -= sz; 1367c478bd9Sstevel@tonic-gate elf->ed_armem->m_slide = sz; 1377c478bd9Sstevel@tonic-gate if (_elf_vm(par, elf->ed_memoff, sz + elf->ed_fsz) != OK_YES) 1387c478bd9Sstevel@tonic-gate return (-1); 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate /* 1417c478bd9Sstevel@tonic-gate * If the archive has been mmaped in, and we're going to slide it, 1427c478bd9Sstevel@tonic-gate * and it wasn't open for write in the first place, and we've never 1437c478bd9Sstevel@tonic-gate * done the mprotect() operation before, then do it now. 1447c478bd9Sstevel@tonic-gate */ 1457c478bd9Sstevel@tonic-gate if ((elf->ed_vm == 0) && ((elf->ed_myflags & EDF_WRITE) == 0) && 1467c478bd9Sstevel@tonic-gate ((elf->ed_myflags & EDF_MPROTECT) == 0)) { 1477c478bd9Sstevel@tonic-gate if (mprotect((char *)elf->ed_image, elf->ed_imagesz, 1487c478bd9Sstevel@tonic-gate PROT_READ|PROT_WRITE) == -1) { 1497c478bd9Sstevel@tonic-gate _elf_seterr(EIO_VM, errno); 1507c478bd9Sstevel@tonic-gate return (-1); 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate elf->ed_myflags |= EDF_MPROTECT; 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate if (memmove((void *)dst, (const void *)src, elf->ed_fsz) != (void *)dst) 1567c478bd9Sstevel@tonic-gate return (-1); 1577c478bd9Sstevel@tonic-gate else 1587c478bd9Sstevel@tonic-gate return (0); 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate Okay 1637c478bd9Sstevel@tonic-gate _elf_cook(Elf * elf) 1647c478bd9Sstevel@tonic-gate { 1657c478bd9Sstevel@tonic-gate NOTE(ASSUMING_PROTECTED(*elf)) 1667c478bd9Sstevel@tonic-gate register int inplace = 1; 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate if (elf->ed_kind != ELF_K_ELF) 1697c478bd9Sstevel@tonic-gate return (OK_YES); 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate if ((elf->ed_status == ES_COOKED) || 1727c478bd9Sstevel@tonic-gate ((elf->ed_myflags & EDF_READ) == 0)) 1737c478bd9Sstevel@tonic-gate return (OK_YES); 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate /* 1767c478bd9Sstevel@tonic-gate * Here's where the unaligned archive member gets fixed. 1777c478bd9Sstevel@tonic-gate */ 1787c478bd9Sstevel@tonic-gate if (elf->ed_status == ES_FRESH && _elf_slide(elf) != 0) 1797c478bd9Sstevel@tonic-gate return (OK_NO); 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate if (elf->ed_status == ES_FROZEN) 1827c478bd9Sstevel@tonic-gate inplace = 0; 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate /* 1857c478bd9Sstevel@tonic-gate * This is the first time we've actually looked at the file 1867c478bd9Sstevel@tonic-gate * contents. We need to know whether or not this is an 1877c478bd9Sstevel@tonic-gate * Elf32 or Elf64 file before we can decode the header. 1887c478bd9Sstevel@tonic-gate * But it's the header that tells us which is which. 1897c478bd9Sstevel@tonic-gate * 1907c478bd9Sstevel@tonic-gate * Resolve the chicken-and-egg problem by peeking at the 1917c478bd9Sstevel@tonic-gate * 'class' byte in the ident string. 1927c478bd9Sstevel@tonic-gate */ 1937c478bd9Sstevel@tonic-gate if (elf->ed_ident[EI_CLASS] == ELFCLASS32) { 1947c478bd9Sstevel@tonic-gate if (_elf32_ehdr(elf, inplace) != 0) 1957c478bd9Sstevel@tonic-gate return (OK_NO); 1967c478bd9Sstevel@tonic-gate if (_elf32_phdr(elf, inplace) != 0) 1977c478bd9Sstevel@tonic-gate goto xehdr; 1987c478bd9Sstevel@tonic-gate if (_elf32_shdr(elf, inplace) != 0) 1997c478bd9Sstevel@tonic-gate goto xphdr; 2007c478bd9Sstevel@tonic-gate elf->ed_class = ELFCLASS32; 2017c478bd9Sstevel@tonic-gate } else if (elf->ed_ident[EI_CLASS] == ELFCLASS64) { 2027c478bd9Sstevel@tonic-gate if (_elf64_ehdr(elf, inplace) != 0) 2037c478bd9Sstevel@tonic-gate return (OK_NO); 2047c478bd9Sstevel@tonic-gate if (_elf64_phdr(elf, inplace) != 0) 2057c478bd9Sstevel@tonic-gate goto xehdr; 2067c478bd9Sstevel@tonic-gate if (_elf64_shdr(elf, inplace) != 0) 2077c478bd9Sstevel@tonic-gate goto xphdr; 2087c478bd9Sstevel@tonic-gate elf->ed_class = ELFCLASS64; 2097c478bd9Sstevel@tonic-gate } else 2107c478bd9Sstevel@tonic-gate return (OK_NO); 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate return (OK_YES); 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate xphdr: 2157c478bd9Sstevel@tonic-gate if (elf->ed_myflags & EDF_PHALLOC) { 2167c478bd9Sstevel@tonic-gate elf->ed_myflags &= ~EDF_PHALLOC; 2177c478bd9Sstevel@tonic-gate free(elf->ed_phdr); 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate elf->ed_phdr = 0; 2207c478bd9Sstevel@tonic-gate xehdr: 2217c478bd9Sstevel@tonic-gate if (elf->ed_myflags & EDF_EHALLOC) { 2227c478bd9Sstevel@tonic-gate elf->ed_myflags &= ~EDF_EHALLOC; 2237c478bd9Sstevel@tonic-gate free(elf->ed_ehdr); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate elf->ed_ehdr = 0; 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate return (OK_NO); 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate Okay 2327c478bd9Sstevel@tonic-gate _elf_cookscn(Elf_Scn * s) 2337c478bd9Sstevel@tonic-gate { 2347c478bd9Sstevel@tonic-gate Elf * elf = s->s_elf; 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate if (elf->ed_class == ELFCLASS32) { 2377c478bd9Sstevel@tonic-gate return (_elf32_cookscn(s)); 2387c478bd9Sstevel@tonic-gate } else if (elf->ed_class == ELFCLASS64) { 2397c478bd9Sstevel@tonic-gate return (_elf64_cookscn(s)); 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate _elf_seterr(EREQ_CLASS, 0); 2437c478bd9Sstevel@tonic-gate return (OK_NO); 2447c478bd9Sstevel@tonic-gate } 245