1 /* $OpenBSD: library.c,v 1.54 2006/05/08 20:34:36 deraadt Exp $ */
2
3 /*
4 * Copyright (c) 2002 Dale Rahn
5 * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29
30 #define _DYN_LOADER
31
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <fcntl.h>
35 #include <sys/mman.h>
36 #include "dl_prebind.h"
37
38 #include "syscall.h"
39 #include "archdep.h"
40 #include "resolve.h"
41
42 #define PFLAGS(X) ((((X) & PF_R) ? PROT_READ : 0) | \
43 (((X) & PF_W) ? PROT_WRITE : 0) | \
44 (((X) & PF_X) ? PROT_EXEC : 0))
45
46 void
_dl_load_list_free(struct load_list * load_list)47 _dl_load_list_free(struct load_list *load_list)
48 {
49 struct load_list *next;
50
51 while (load_list != NULL) {
52 next = load_list->next;
53 _dl_free(load_list);
54 load_list = next;
55 }
56 }
57
58 void
_dl_unload_shlib(elf_object_t * object)59 _dl_unload_shlib(elf_object_t *object)
60 {
61 struct dep_node *n;
62 DL_DEB(("unload_shlib called on %s\n", object->load_name));
63 if (OBJECT_REF_CNT(object) == 0 &&
64 (object->status & STAT_UNLOADED) == 0) {
65 object->status |= STAT_UNLOADED;
66 TAILQ_FOREACH(n, &object->child_list, next_sib)
67 _dl_unload_shlib(n->data);
68 TAILQ_FOREACH(n, &object->grpref_list, next_sib)
69 _dl_unload_shlib(n->data);
70 DL_DEB(("unload_shlib unloading on %s\n", object->load_name));
71 _dl_load_list_free(object->load_list);
72 _dl_munmap((void *)object->load_addr, object->load_size);
73 _dl_remove_object(object);
74 }
75 }
76
77 elf_object_t *
_dl_tryload_shlib(const char * libname,int type,int flags)78 _dl_tryload_shlib(const char *libname, int type, int flags)
79 {
80 int libfile, i, align = _dl_pagesz - 1;
81 struct load_list *next_load, *load_list = NULL;
82 Elf_Addr maxva = 0, minva = 0x7fffffff; /* XXX Correct for 64bit? */
83 Elf_Addr libaddr, loff;
84 elf_object_t *object;
85 char hbuf[4096];
86 Elf_Dyn *dynp = 0;
87 Elf_Ehdr *ehdr;
88 Elf_Phdr *phdp;
89 struct stat sb;
90 void *prebind_data;
91
92 #define ROUND_PG(x) (((x) + align) & ~(align))
93 #define TRUNC_PG(x) ((x) & ~(align))
94
95 object = _dl_lookup_object(libname);
96 if (object) {
97 object->obj_flags |= flags & RTLD_GLOBAL;
98 if (_dl_loading_object == NULL)
99 _dl_loading_object = object;
100 if (object->load_object != _dl_objects &&
101 object->load_object != _dl_loading_object) {
102 _dl_link_grpref(object->load_object, _dl_loading_object);
103 }
104 return(object); /* Already loaded */
105 }
106
107 libfile = _dl_open(libname, O_RDONLY);
108 if (libfile < 0) {
109 _dl_errno = DL_CANT_OPEN;
110 return(0);
111 }
112
113 if ( _dl_fstat(libfile, &sb) < 0) {
114 _dl_errno = DL_CANT_OPEN;
115 return(0);
116 }
117
118 for (object = _dl_objects; object != NULL; object = object->next) {
119 if (object->dev == sb.st_dev &&
120 object->inode == sb.st_ino) {
121 object->obj_flags |= flags & RTLD_GLOBAL;
122 _dl_close(libfile);
123 if (_dl_loading_object == NULL)
124 _dl_loading_object = object;
125 if (object->load_object != _dl_objects &&
126 object->load_object != _dl_loading_object) {
127 _dl_link_grpref(object->load_object,
128 _dl_loading_object);
129 }
130 return(object);
131 }
132 }
133
134 _dl_read(libfile, hbuf, sizeof(hbuf));
135 ehdr = (Elf_Ehdr *)hbuf;
136 if (ehdr->e_ident[0] != ELFMAG0 || ehdr->e_ident[1] != ELFMAG1 ||
137 ehdr->e_ident[2] != ELFMAG2 || ehdr->e_ident[3] != ELFMAG3 ||
138 ehdr->e_type != ET_DYN || ehdr->e_machine != MACHID) {
139 _dl_close(libfile);
140 _dl_errno = DL_NOT_ELF;
141 return(0);
142 }
143
144 /*
145 * Alright, we might have a winner!
146 * Figure out how much VM space we need.
147 */
148 phdp = (Elf_Phdr *)(hbuf + ehdr->e_phoff);
149 for (i = 0; i < ehdr->e_phnum; i++, phdp++) {
150 switch (phdp->p_type) {
151 case PT_LOAD:
152 if (phdp->p_vaddr < minva)
153 minva = phdp->p_vaddr;
154 if (phdp->p_vaddr + phdp->p_memsz > maxva)
155 maxva = phdp->p_vaddr + phdp->p_memsz;
156 break;
157 case PT_DYNAMIC:
158 dynp = (Elf_Dyn *)phdp->p_vaddr;
159 break;
160 default:
161 break;
162 }
163 }
164 minva = TRUNC_PG(minva);
165 maxva = ROUND_PG(maxva);
166
167 /*
168 * We map the entire area to see that we can get the VM
169 * space required. Map it unaccessible to start with.
170 *
171 * We must map the file we'll map later otherwise the VM
172 * system won't be able to align the mapping properly
173 * on VAC architectures.
174 */
175 libaddr = (Elf_Addr)_dl_mmap(0, maxva - minva, PROT_NONE,
176 MAP_PRIVATE|MAP_FILE, libfile, 0);
177 if (_dl_check_error(libaddr)) {
178 _dl_printf("%s: rtld mmap failed mapping %s.\n",
179 _dl_progname, libname);
180 _dl_close(libfile);
181 _dl_errno = DL_CANT_MMAP;
182 return(0);
183 }
184
185 loff = libaddr - minva;
186 phdp = (Elf_Phdr *)(hbuf + ehdr->e_phoff);
187
188 for (i = 0; i < ehdr->e_phnum; i++, phdp++) {
189 if (phdp->p_type == PT_LOAD) {
190 char *start = (char *)(TRUNC_PG(phdp->p_vaddr)) + loff;
191 int off = (phdp->p_vaddr & align);
192 int size = off + phdp->p_filesz;
193 void *res;
194
195 res = _dl_mmap(start, ROUND_PG(size),
196 PFLAGS(phdp->p_flags),
197 MAP_FIXED|MAP_PRIVATE, libfile,
198 TRUNC_PG(phdp->p_offset));
199 next_load = _dl_malloc(sizeof(struct load_list));
200 next_load->next = load_list;
201 load_list = next_load;
202 next_load->start = start;
203 next_load->size = size;
204 next_load->prot = PFLAGS(phdp->p_flags);
205 if (_dl_check_error((long)res)) {
206 _dl_printf("%s: rtld mmap failed mapping %s.\n",
207 _dl_progname, libname);
208 _dl_close(libfile);
209 _dl_errno = DL_CANT_MMAP;
210 _dl_munmap((void *)libaddr, maxva - minva);
211 _dl_load_list_free(load_list);
212 return(0);
213 }
214 if (phdp->p_flags & PF_W) {
215 /* Zero out everything past the EOF */
216 if ((size & align) != 0)
217 _dl_memset(start + size, 0,
218 _dl_pagesz - (size & align));
219 if (ROUND_PG(size) ==
220 ROUND_PG(off + phdp->p_memsz))
221 continue;
222 start = start + ROUND_PG(size);
223 size = ROUND_PG(off + phdp->p_memsz) -
224 ROUND_PG(size);
225 res = _dl_mmap(start, size,
226 PFLAGS(phdp->p_flags),
227 MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0);
228 if (_dl_check_error((long)res)) {
229 _dl_printf("%s: rtld mmap failed mapping %s.\n",
230 _dl_progname, libname);
231 _dl_close(libfile);
232 _dl_errno = DL_CANT_MMAP;
233 _dl_munmap((void *)libaddr, maxva - minva);
234 _dl_load_list_free(load_list);
235 return(0);
236 }
237 }
238 }
239 }
240
241 prebind_data = prebind_load_fd(libfile, libname);
242
243 _dl_close(libfile);
244
245 dynp = (Elf_Dyn *)((unsigned long)dynp + loff);
246 object = _dl_finalize_object(libname, dynp, 0, type, libaddr, loff);
247 if (object) {
248 object->prebind_data = prebind_data;
249 object->load_size = maxva - minva; /*XXX*/
250 object->load_list = load_list;
251 /* set inode, dev from stat info */
252 object->dev = sb.st_dev;
253 object->inode = sb.st_ino;
254 object->obj_flags |= flags;
255 } else {
256 /* XXX not possible. object cannot come back NULL */
257 _dl_munmap((void *)libaddr, maxva - minva);
258 _dl_load_list_free(load_list);
259 }
260 return(object);
261 }
262