File: | src/libexec/ld.so/library.c |
Warning: | line 147, column 23 The left operand of '!=' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: library.c,v 1.86 2022/01/08 06:49:41 guenther 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/mman.h> | |||
34 | #include <sys/stat.h> | |||
35 | #include <fcntl.h> | |||
36 | ||||
37 | #include "syscall.h" | |||
38 | #include "util.h" | |||
39 | #include "archdep.h" | |||
40 | #include "resolve.h" | |||
41 | #include "sod.h" | |||
42 | ||||
43 | #define PFLAGS(X)((((X) & 0x4) ? 0x01 : 0) | (((X) & 0x2) ? 0x02 : 0) | (((X) & 0x1) ? 0x04 : 0)) ((((X) & PF_R0x4) ? PROT_READ0x01 : 0) | \ | |||
44 | (((X) & PF_W0x2) ? PROT_WRITE0x02 : 0) | \ | |||
45 | (((X) & PF_X0x1) ? PROT_EXEC0x04 : 0)) | |||
46 | ||||
47 | void | |||
48 | _dl_load_list_free(struct load_list *load_list) | |||
49 | { | |||
50 | struct load_list *next; | |||
51 | ||||
52 | while (load_list != NULL((void*)0)) { | |||
53 | next = load_list->next; | |||
54 | _dl_free(load_list); | |||
55 | load_list = next; | |||
56 | } | |||
57 | } | |||
58 | ||||
59 | void | |||
60 | _dl_unload_shlib(elf_object_t *object) | |||
61 | { | |||
62 | struct dep_node *n; | |||
63 | elf_object_t *load_object = object->load_object; | |||
64 | ||||
65 | /* | |||
66 | * If our load object has become unreferenced then we lost the | |||
67 | * last group reference to it, so the entire group should be taken | |||
68 | * down. The current object is somewhere below load_object in | |||
69 | * the child_vec tree, so it'll get cleaned up by the recursion. | |||
70 | * That means we can just switch here to the load object. | |||
71 | */ | |||
72 | if (load_object != object && OBJECT_REF_CNT(load_object)((load_object->refcount + load_object->opencount + load_object ->grprefcount)) == 0 && | |||
73 | (load_object->status & STAT_UNLOADED0x020) == 0) { | |||
74 | DL_DEB(("unload_shlib switched from %s to %s\n",do { if (_dl_debug) _dl_printf ("unload_shlib switched from %s to %s\n" , object->load_name, load_object->load_name) ; } while ( 0) | |||
75 | object->load_name, load_object->load_name))do { if (_dl_debug) _dl_printf ("unload_shlib switched from %s to %s\n" , object->load_name, load_object->load_name) ; } while ( 0); | |||
76 | object = load_object; | |||
77 | goto unload; | |||
78 | } | |||
79 | ||||
80 | DL_DEB(("unload_shlib called on %s\n", object->load_name))do { if (_dl_debug) _dl_printf ("unload_shlib called on %s\n" , object->load_name) ; } while (0); | |||
81 | if (OBJECT_REF_CNT(object)((object->refcount + object->opencount + object->grprefcount )) == 0 && | |||
82 | (object->status & STAT_UNLOADED0x020) == 0) { | |||
83 | struct object_vector vec; | |||
84 | int i; | |||
85 | unload: | |||
86 | object->status |= STAT_UNLOADED0x020; | |||
87 | for (vec = object->child_vec, i = 0; i < vec.len; i++) | |||
88 | _dl_unload_shlib(vec.vec[i]); | |||
89 | TAILQ_FOREACH(n, &object->grpref_list, next_sib)for((n) = ((&object->grpref_list)->tqh_first); (n) != ((void*)0); (n) = ((n)->next_sib.tqe_next)) | |||
90 | _dl_unload_shlib(n->data); | |||
91 | DL_DEB(("unload_shlib unloading on %s\n", object->load_name))do { if (_dl_debug) _dl_printf ("unload_shlib unloading on %s\n" , object->load_name) ; } while (0); | |||
92 | _dl_load_list_free(object->load_list); | |||
93 | _dl_munmap((void *)object->load_base, object->load_size); | |||
94 | _dl_remove_object(object); | |||
95 | } | |||
96 | } | |||
97 | ||||
98 | elf_object_t * | |||
99 | _dl_tryload_shlib(const char *libname, int type, int flags) | |||
100 | { | |||
101 | int libfile, i; | |||
102 | struct load_list *next_load, *load_list = NULL((void*)0); | |||
103 | Elf_AddrElf64_Addr maxva = 0, minva = ELF_NO_ADDR((__uint64_t) ~0); | |||
104 | Elf_AddrElf64_Addr libaddr, loff, align = _dl_pagesz - 1; | |||
105 | Elf_AddrElf64_Addr relro_addr = 0, relro_size = 0; | |||
106 | elf_object_t *object; | |||
107 | char hbuf[4096], *exec_start = 0; | |||
108 | size_t exec_size = 0; | |||
109 | Elf_DynElf64_Dyn *dynp = NULL((void*)0); | |||
110 | Elf_EhdrElf64_Ehdr *ehdr; | |||
111 | Elf_PhdrElf64_Phdr *phdp; | |||
112 | Elf_PhdrElf64_Phdr *ptls = NULL((void*)0); | |||
113 | struct stat sb; | |||
114 | ||||
115 | #define ROUND_PG(x)(((x) + align) & ~(align)) (((x) + align) & ~(align)) | |||
116 | #define TRUNC_PG(x)((x) & ~(align)) ((x) & ~(align)) | |||
117 | ||||
118 | libfile = _dl_open(libname, O_RDONLY0x0000 | O_CLOEXEC0x10000); | |||
119 | if (libfile < 0) { | |||
| ||||
120 | _dl_errno = DL_CANT_OPEN2; | |||
121 | return(0); | |||
122 | } | |||
123 | ||||
124 | if ( _dl_fstat(libfile, &sb) < 0) { | |||
125 | _dl_errno = DL_CANT_OPEN2; | |||
126 | return(0); | |||
127 | } | |||
128 | ||||
129 | for (object = _dl_objects; object != NULL((void*)0); object = object->next) { | |||
130 | if (object->dev == sb.st_dev && | |||
131 | object->inode == sb.st_ino) { | |||
132 | object->obj_flags |= flags & DF_1_GLOBAL0x00000002; | |||
133 | _dl_close(libfile); | |||
134 | if (_dl_loading_object == NULL((void*)0)) | |||
135 | _dl_loading_object = object; | |||
136 | if (object->load_object != _dl_objects && | |||
137 | object->load_object != _dl_loading_object) { | |||
138 | _dl_link_grpref(object->load_object, | |||
139 | _dl_loading_object); | |||
140 | } | |||
141 | return(object); | |||
142 | } | |||
143 | } | |||
144 | ||||
145 | _dl_read(libfile, hbuf, sizeof(hbuf)); | |||
146 | ehdr = (Elf_EhdrElf64_Ehdr *)hbuf; | |||
147 | if (ehdr->e_ident[0] != ELFMAG00x7f || ehdr->e_ident[1] != ELFMAG1'E' || | |||
| ||||
148 | ehdr->e_ident[2] != ELFMAG2'L' || ehdr->e_ident[3] != ELFMAG3'F' || | |||
149 | ehdr->e_type != ET_DYN3 || ehdr->e_machine != MACHID62) { | |||
150 | _dl_close(libfile); | |||
151 | _dl_errno = DL_NOT_ELF3; | |||
152 | return(0); | |||
153 | } | |||
154 | ||||
155 | /* | |||
156 | * Alright, we might have a winner! | |||
157 | * Figure out how much VM space we need. | |||
158 | */ | |||
159 | phdp = (Elf_PhdrElf64_Phdr *)(hbuf + ehdr->e_phoff); | |||
160 | for (i = 0; i < ehdr->e_phnum; i++, phdp++) { | |||
161 | switch (phdp->p_type) { | |||
162 | case PT_LOAD1: | |||
163 | if (phdp->p_vaddr < minva) | |||
164 | minva = phdp->p_vaddr; | |||
165 | if (phdp->p_vaddr + phdp->p_memsz > maxva) | |||
166 | maxva = phdp->p_vaddr + phdp->p_memsz; | |||
167 | break; | |||
168 | case PT_DYNAMIC2: | |||
169 | dynp = (Elf_DynElf64_Dyn *)phdp->p_vaddr; | |||
170 | break; | |||
171 | case PT_TLS7: | |||
172 | if (phdp->p_filesz > phdp->p_memsz) { | |||
173 | _dl_printf("%s: invalid tls data in %s.\n", | |||
174 | __progname, libname); | |||
175 | _dl_close(libfile); | |||
176 | _dl_errno = DL_CANT_LOAD_OBJ11; | |||
177 | return(0); | |||
178 | } | |||
179 | if (!_dl_tib_static_done) { | |||
180 | ptls = phdp; | |||
181 | break; | |||
182 | } | |||
183 | _dl_printf("%s: unsupported TLS program header in %s\n", | |||
184 | __progname, libname); | |||
185 | _dl_close(libfile); | |||
186 | _dl_errno = DL_CANT_LOAD_OBJ11; | |||
187 | return(0); | |||
188 | default: | |||
189 | break; | |||
190 | } | |||
191 | } | |||
192 | minva = TRUNC_PG(minva)((minva) & ~(align)); | |||
193 | maxva = ROUND_PG(maxva)(((maxva) + align) & ~(align)); | |||
194 | ||||
195 | /* | |||
196 | * We map the entire area to see that we can get the VM | |||
197 | * space required. Map it unaccessible to start with. | |||
198 | * | |||
199 | * We must map the file we'll map later otherwise the VM | |||
200 | * system won't be able to align the mapping properly | |||
201 | * on VAC architectures. | |||
202 | */ | |||
203 | libaddr = (Elf_AddrElf64_Addr)_dl_mmap(0, maxva - minva, PROT_NONE0x00, | |||
204 | MAP_PRIVATE0x0002|MAP_FILE0, libfile, 0); | |||
205 | if (_dl_mmap_error(libaddr)((long)libaddr < 0 && (long)libaddr >= -512L)) { | |||
206 | _dl_printf("%s: ld.so mmap failed mapping %s.\n", | |||
207 | __progname, libname); | |||
208 | _dl_close(libfile); | |||
209 | _dl_errno = DL_CANT_MMAP5; | |||
210 | return(0); | |||
211 | } | |||
212 | ||||
213 | loff = libaddr - minva; | |||
214 | phdp = (Elf_PhdrElf64_Phdr *)(hbuf + ehdr->e_phoff); | |||
215 | ||||
216 | for (i = 0; i < ehdr->e_phnum; i++, phdp++) { | |||
217 | switch (phdp->p_type) { | |||
218 | case PT_LOAD1: { | |||
219 | char *start = (char *)(TRUNC_PG(phdp->p_vaddr)((phdp->p_vaddr) & ~(align))) + loff; | |||
220 | Elf_AddrElf64_Addr off = (phdp->p_vaddr & align); | |||
221 | Elf_AddrElf64_Addr size = off + phdp->p_filesz; | |||
222 | int flags = PFLAGS(phdp->p_flags)((((phdp->p_flags) & 0x4) ? 0x01 : 0) | (((phdp->p_flags ) & 0x2) ? 0x02 : 0) | (((phdp->p_flags) & 0x1) ? 0x04 : 0)); | |||
223 | void *res; | |||
224 | ||||
225 | /* | |||
226 | * Initially map W|X segments without X | |||
227 | * permission. After we're done with the | |||
228 | * initial relocation processing, we will make | |||
229 | * these segments read-only and add back the X | |||
230 | * permission. This way we maintain W^X at | |||
231 | * all times. | |||
232 | */ | |||
233 | if ((flags & PROT_WRITE0x02) && (flags & PROT_EXEC0x04)) | |||
234 | flags &= ~PROT_EXEC0x04; | |||
235 | ||||
236 | if (size != 0) { | |||
237 | res = _dl_mmap(start, ROUND_PG(size)(((size) + align) & ~(align)), flags, | |||
238 | MAP_FIXED0x0010|MAP_PRIVATE0x0002, libfile, | |||
239 | TRUNC_PG(phdp->p_offset)((phdp->p_offset) & ~(align))); | |||
240 | } else | |||
241 | res = NULL((void*)0); /* silence gcc */ | |||
242 | next_load = _dl_calloc(1, sizeof(struct load_list)); | |||
243 | if (next_load == NULL((void*)0)) | |||
244 | _dl_oom(); | |||
245 | next_load->next = load_list; | |||
246 | load_list = next_load; | |||
247 | next_load->start = start; | |||
248 | next_load->size = size; | |||
249 | next_load->prot = PFLAGS(phdp->p_flags)((((phdp->p_flags) & 0x4) ? 0x01 : 0) | (((phdp->p_flags ) & 0x2) ? 0x02 : 0) | (((phdp->p_flags) & 0x1) ? 0x04 : 0)); | |||
250 | if (size != 0 && _dl_mmap_error(res)((long)res < 0 && (long)res >= -512L)) { | |||
251 | _dl_printf("%s: ld.so mmap failed mapping %s.\n", | |||
252 | __progname, libname); | |||
253 | _dl_close(libfile); | |||
254 | _dl_errno = DL_CANT_MMAP5; | |||
255 | _dl_munmap((void *)libaddr, maxva - minva); | |||
256 | _dl_load_list_free(load_list); | |||
257 | return(0); | |||
258 | } | |||
259 | if ((flags & PROT_EXEC0x04) && exec_start == 0) { | |||
260 | exec_start = start; | |||
261 | exec_size = ROUND_PG(size)(((size) + align) & ~(align)); | |||
262 | } | |||
263 | ||||
264 | if (phdp->p_flags & PF_W0x2) { | |||
265 | /* Zero out everything past the EOF */ | |||
266 | if ((size & align) != 0) | |||
267 | _dl_memset(start + size, 0, | |||
268 | _dl_pagesz - (size & align)); | |||
269 | if (ROUND_PG(size)(((size) + align) & ~(align)) == | |||
270 | ROUND_PG(off + phdp->p_memsz)(((off + phdp->p_memsz) + align) & ~(align))) | |||
271 | continue; | |||
272 | start = start + ROUND_PG(size)(((size) + align) & ~(align)); | |||
273 | size = ROUND_PG(off + phdp->p_memsz)(((off + phdp->p_memsz) + align) & ~(align)) - | |||
274 | ROUND_PG(size)(((size) + align) & ~(align)); | |||
275 | res = _dl_mmap(start, size, flags, | |||
276 | MAP_FIXED0x0010|MAP_PRIVATE0x0002|MAP_ANON0x1000, -1, 0); | |||
277 | if (_dl_mmap_error(res)((long)res < 0 && (long)res >= -512L)) { | |||
278 | _dl_printf("%s: ld.so mmap failed mapping %s.\n", | |||
279 | __progname, libname); | |||
280 | _dl_close(libfile); | |||
281 | _dl_errno = DL_CANT_MMAP5; | |||
282 | _dl_munmap((void *)libaddr, maxva - minva); | |||
283 | _dl_load_list_free(load_list); | |||
284 | return(0); | |||
285 | } | |||
286 | } | |||
287 | break; | |||
288 | } | |||
289 | ||||
290 | case PT_OPENBSD_RANDOMIZE0x65a3dbe6: | |||
291 | _dl_arc4randombuf((char *)(phdp->p_vaddr + loff), | |||
292 | phdp->p_memsz); | |||
293 | break; | |||
294 | ||||
295 | case PT_GNU_RELRO0x6474e552: | |||
296 | relro_addr = phdp->p_vaddr + loff; | |||
297 | relro_size = phdp->p_memsz; | |||
298 | break; | |||
299 | ||||
300 | default: | |||
301 | break; | |||
302 | } | |||
303 | } | |||
304 | ||||
305 | _dl_close(libfile); | |||
306 | ||||
307 | dynp = (Elf_DynElf64_Dyn *)((unsigned long)dynp + loff); | |||
308 | object = _dl_finalize_object(libname, dynp, | |||
309 | (Elf_PhdrElf64_Phdr *)((char *)libaddr + ehdr->e_phoff), ehdr->e_phnum,type, | |||
310 | libaddr, loff); | |||
311 | if (object) { | |||
312 | char *soname = (char *)object->Dyn.info[DT_SONAME14]; | |||
313 | ||||
314 | object->load_size = maxva - minva; /*XXX*/ | |||
315 | object->load_list = load_list; | |||
316 | /* set inode, dev from stat info */ | |||
317 | object->dev = sb.st_dev; | |||
318 | object->inode = sb.st_ino; | |||
319 | object->obj_flags |= flags; | |||
320 | object->relro_addr = relro_addr; | |||
321 | object->relro_size = relro_size; | |||
322 | _dl_set_sod(object->load_name, &object->sod); | |||
323 | if (ptls != NULL((void*)0) && ptls->p_memsz) | |||
324 | _dl_set_tls(object, ptls, libaddr, libname); | |||
325 | ||||
326 | /* Request permission for system calls in libc.so's text segment */ | |||
327 | if (soname != NULL((void*)0) && | |||
328 | _dl_strncmp(soname, "libc.so.", 8) == 0) { | |||
329 | if (_dl_msyscall(exec_start, exec_size) == -1) | |||
330 | _dl_printf("msyscall %lx %lx error\n", | |||
331 | exec_start, exec_size); | |||
332 | } | |||
333 | } else { | |||
334 | _dl_munmap((void *)libaddr, maxva - minva); | |||
335 | _dl_load_list_free(load_list); | |||
336 | } | |||
337 | return(object); | |||
338 | } |