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