| 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 | } |