1 /* $OpenBSD: library_mquery.c,v 1.66 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) & PF_R) ? PROT_READ : 0) | \ 44 (((X) & PF_W) ? PROT_WRITE : 0) | \ 45 (((X) & PF_X) ? PROT_EXEC : 0)) 46 47 void 48 _dl_load_list_free(struct load_list *load_list) 49 { 50 struct load_list *next; 51 Elf_Addr align = _dl_pagesz - 1; 52 53 while (load_list != NULL) { 54 if (load_list->start != NULL) 55 _dl_munmap(load_list->start, 56 ((load_list->size) + align) & ~align); 57 next = load_list->next; 58 _dl_free(load_list); 59 load_list = next; 60 } 61 } 62 63 64 void 65 _dl_unload_shlib(elf_object_t *object) 66 { 67 struct dep_node *n; 68 elf_object_t *load_object = object->load_object; 69 70 /* 71 * If our load object has become unreferenced then we lost the 72 * last group reference to it, so the entire group should be taken 73 * down. The current object is somewhere below load_object in 74 * the child_vec tree, so it'll get cleaned up by the recursion. 75 * That means we can just switch here to the load object. 76 */ 77 if (load_object != object && OBJECT_REF_CNT(load_object) == 0 && 78 (load_object->status & STAT_UNLOADED) == 0) { 79 DL_DEB(("unload_shlib switched from %s to %s\n", 80 object->load_name, load_object->load_name)); 81 object = load_object; 82 goto unload; 83 } 84 85 DL_DEB(("unload_shlib called on %s\n", object->load_name)); 86 if (OBJECT_REF_CNT(object) == 0 && 87 (object->status & STAT_UNLOADED) == 0) { 88 struct object_vector vec; 89 int i; 90 unload: 91 object->status |= STAT_UNLOADED; 92 for (vec = object->child_vec, i = 0; i < vec.len; i++) 93 _dl_unload_shlib(vec.vec[i]); 94 TAILQ_FOREACH(n, &object->grpref_list, next_sib) 95 _dl_unload_shlib(n->data); 96 DL_DEB(("unload_shlib unloading on %s\n", object->load_name)); 97 _dl_load_list_free(object->load_list); 98 _dl_remove_object(object); 99 } 100 } 101 102 103 elf_object_t * 104 _dl_tryload_shlib(const char *libname, int type, int flags) 105 { 106 int libfile, i; 107 struct load_list *ld, *lowld = NULL; 108 elf_object_t *object; 109 Elf_Dyn *dynp = NULL; 110 Elf_Ehdr *ehdr; 111 Elf_Phdr *phdp; 112 Elf_Addr load_end = 0; 113 Elf_Addr align = _dl_pagesz - 1, off, size; 114 Elf_Phdr *ptls = NULL; 115 Elf_Addr relro_addr = 0, relro_size = 0; 116 struct stat sb; 117 char hbuf[4096], *exec_start; 118 size_t exec_size; 119 120 #define ROUND_PG(x) (((x) + align) & ~(align)) 121 #define TRUNC_PG(x) ((x) & ~(align)) 122 123 libfile = _dl_open(libname, O_RDONLY | O_CLOEXEC); 124 if (libfile < 0) { 125 _dl_errno = DL_CANT_OPEN; 126 return(0); 127 } 128 129 if ( _dl_fstat(libfile, &sb) < 0) { 130 _dl_errno = DL_CANT_OPEN; 131 return(0); 132 } 133 134 for (object = _dl_objects; object != NULL; object = object->next) { 135 if (object->dev == sb.st_dev && 136 object->inode == sb.st_ino) { 137 object->obj_flags |= flags & DF_1_GLOBAL; 138 _dl_close(libfile); 139 if (_dl_loading_object == NULL) 140 _dl_loading_object = object; 141 if (object->load_object != _dl_objects && 142 object->load_object != _dl_loading_object) { 143 _dl_link_grpref(object->load_object, 144 _dl_loading_object); 145 } 146 return(object); 147 } 148 } 149 150 _dl_read(libfile, hbuf, sizeof(hbuf)); 151 ehdr = (Elf_Ehdr *)hbuf; 152 if (ehdr->e_ident[0] != ELFMAG0 || ehdr->e_ident[1] != ELFMAG1 || 153 ehdr->e_ident[2] != ELFMAG2 || ehdr->e_ident[3] != ELFMAG3 || 154 ehdr->e_type != ET_DYN || ehdr->e_machine != MACHID) { 155 _dl_close(libfile); 156 _dl_errno = DL_NOT_ELF; 157 return(0); 158 } 159 160 /* Insertion sort */ 161 #define LDLIST_INSERT(ld) do { \ 162 struct load_list **_ld; \ 163 for (_ld = &lowld; *_ld != NULL; _ld = &(*_ld)->next) \ 164 if ((*_ld)->moff > ld->moff) \ 165 break; \ 166 ld->next = *_ld; \ 167 *_ld = ld; \ 168 } while (0) 169 /* 170 * Alright, we might have a winner! 171 * Figure out how much VM space we need and set up the load 172 * list that we'll use to find free VM space. 173 */ 174 phdp = (Elf_Phdr *)(hbuf + ehdr->e_phoff); 175 for (i = 0; i < ehdr->e_phnum; i++, phdp++) { 176 switch (phdp->p_type) { 177 case PT_LOAD: 178 off = (phdp->p_vaddr & align); 179 size = off + phdp->p_filesz; 180 181 if (size != 0) { 182 ld = _dl_malloc(sizeof(struct load_list)); 183 if (ld == NULL) 184 _dl_oom(); 185 ld->start = NULL; 186 ld->size = size; 187 ld->moff = TRUNC_PG(phdp->p_vaddr); 188 ld->foff = TRUNC_PG(phdp->p_offset); 189 ld->prot = PFLAGS(phdp->p_flags); 190 LDLIST_INSERT(ld); 191 } 192 193 if ((PFLAGS(phdp->p_flags) & PROT_WRITE) == 0 || 194 ROUND_PG(size) == ROUND_PG(off + phdp->p_memsz)) 195 break; 196 /* This phdr has a zfod section */ 197 ld = _dl_calloc(1, sizeof(struct load_list)); 198 if (ld == NULL) 199 _dl_oom(); 200 ld->start = NULL; 201 ld->size = ROUND_PG(off + phdp->p_memsz) - 202 ROUND_PG(size); 203 ld->moff = TRUNC_PG(phdp->p_vaddr) + 204 ROUND_PG(size); 205 ld->foff = -1; 206 ld->prot = PFLAGS(phdp->p_flags); 207 LDLIST_INSERT(ld); 208 break; 209 case PT_DYNAMIC: 210 dynp = (Elf_Dyn *)phdp->p_vaddr; 211 break; 212 case PT_TLS: 213 if (phdp->p_filesz > phdp->p_memsz) { 214 _dl_printf("%s: invalid tls data in %s.\n", 215 __progname, libname); 216 _dl_close(libfile); 217 _dl_errno = DL_CANT_LOAD_OBJ; 218 return(0); 219 } 220 if (!_dl_tib_static_done) { 221 ptls = phdp; 222 break; 223 } 224 _dl_printf("%s: unsupported TLS program header in %s\n", 225 __progname, libname); 226 _dl_close(libfile); 227 _dl_errno = DL_CANT_LOAD_OBJ; 228 return(0); 229 default: 230 break; 231 } 232 } 233 234 #define LOFF ((Elf_Addr)lowld->start - lowld->moff) 235 236 retry: 237 exec_start = NULL; 238 exec_size = 0; 239 for (ld = lowld; ld != NULL; ld = ld->next) { 240 off_t foff; 241 int fd, flags; 242 void *res; 243 244 flags = MAP_PRIVATE; 245 246 if (ld->foff < 0) { 247 fd = -1; 248 foff = 0; 249 flags |= MAP_ANON; 250 } else { 251 fd = libfile; 252 foff = ld->foff; 253 } 254 255 if (ld == lowld) { 256 /* 257 * Add PROT_EXEC to force the first allocation in 258 * EXEC region unless it is writable. 259 */ 260 int exec = (ld->prot & PROT_WRITE) ? 0 : PROT_EXEC; 261 if (exec && lowld->start == NULL) 262 lowld->start = _dl_exec_hint; 263 res = _dl_mquery((void *)(LOFF + ld->moff), 264 ROUND_PG(ld->size), ld->prot | exec, flags, 265 fd, foff); 266 if (_dl_mmap_error(res)) 267 goto fail; 268 lowld->start = res; 269 } 270 271 res = _dl_mmap((void *)(LOFF + ld->moff), ROUND_PG(ld->size), 272 ld->prot, flags | MAP_FIXED | __MAP_NOREPLACE, fd, foff); 273 if (_dl_mmap_error(res)) { 274 struct load_list *ll; 275 276 /* Unmap any mappings that we did get in. */ 277 for (ll = lowld; ll != NULL && ll != ld; 278 ll = ll->next) { 279 _dl_munmap(ll->start, ROUND_PG(ll->size)); 280 } 281 282 lowld->start += ROUND_PG(ld->size); 283 goto retry; 284 } 285 286 if ((ld->prot & PROT_EXEC) && exec_start == NULL) { 287 exec_start = (void *)(LOFF + ld->moff); 288 exec_size = ROUND_PG(ld->size); 289 } 290 291 ld->start = res; 292 } 293 294 for (ld = lowld; ld != NULL; ld = ld->next) { 295 /* Zero out everything past the EOF */ 296 if ((ld->prot & PROT_WRITE) != 0 && (ld->size & align) != 0) 297 _dl_memset((char *)ld->start + ld->size, 0, 298 _dl_pagesz - (ld->size & align)); 299 load_end = (Elf_Addr)ld->start + ROUND_PG(ld->size); 300 } 301 302 phdp = (Elf_Phdr *)(hbuf + ehdr->e_phoff); 303 for (i = 0; i < ehdr->e_phnum; i++, phdp++) { 304 if (phdp->p_type == PT_OPENBSD_RANDOMIZE) 305 _dl_arc4randombuf((char *)(phdp->p_vaddr + LOFF), 306 phdp->p_memsz); 307 else if (phdp->p_type == PT_GNU_RELRO) { 308 relro_addr = phdp->p_vaddr + LOFF; 309 relro_size = phdp->p_memsz; 310 } 311 } 312 313 _dl_close(libfile); 314 315 dynp = (Elf_Dyn *)((unsigned long)dynp + LOFF); 316 object = _dl_finalize_object(libname, dynp, 317 (Elf_Phdr *)((char *)lowld->start + ehdr->e_phoff), ehdr->e_phnum, 318 type, (Elf_Addr)lowld->start, LOFF); 319 if (object) { 320 char *soname = (char *)object->Dyn.info[DT_SONAME]; 321 322 object->load_size = (Elf_Addr)load_end - (Elf_Addr)lowld->start; 323 object->load_list = lowld; 324 /* set inode, dev from stat info */ 325 object->dev = sb.st_dev; 326 object->inode = sb.st_ino; 327 object->obj_flags |= flags; 328 object->relro_addr = relro_addr; 329 object->relro_size = relro_size; 330 _dl_set_sod(object->load_name, &object->sod); 331 if (ptls != NULL && ptls->p_memsz) 332 _dl_set_tls(object, ptls, (Elf_Addr)lowld->start, 333 libname); 334 335 /* Request permission for system calls in libc.so's text segment */ 336 if (soname != NULL && 337 _dl_strncmp(soname, "libc.so.", 8) == 0) { 338 if (_dl_msyscall(exec_start, exec_size) == -1) 339 _dl_printf("msyscall %lx %lx error\n", 340 exec_start, exec_size); 341 } 342 } else { 343 _dl_load_list_free(lowld); 344 } 345 return(object); 346 fail: 347 _dl_printf("%s: ld.so mmap failed mapping %s.\n", __progname, libname); 348 _dl_close(libfile); 349 _dl_errno = DL_CANT_MMAP; 350 _dl_load_list_free(lowld); 351 return(0); 352 } 353