1 1.49 kamil /* $NetBSD: load.c,v 1.49 2020/09/21 16:08:57 kamil Exp $ */ 2 1.1 cgd 3 1.1 cgd /* 4 1.1 cgd * Copyright 1996 John D. Polstra. 5 1.1 cgd * Copyright 1996 Matt Thomas <matt (at) 3am-software.com> 6 1.24 mycroft * Copyright 2002 Charles M. Hannum <root (at) ihack.net> 7 1.1 cgd * All rights reserved. 8 1.1 cgd * 9 1.1 cgd * Redistribution and use in source and binary forms, with or without 10 1.1 cgd * modification, are permitted provided that the following conditions 11 1.1 cgd * are met: 12 1.1 cgd * 1. Redistributions of source code must retain the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer. 14 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 cgd * notice, this list of conditions and the following disclaimer in the 16 1.1 cgd * documentation and/or other materials provided with the distribution. 17 1.1 cgd * 3. All advertising materials mentioning features or use of this software 18 1.1 cgd * must display the following acknowledgement: 19 1.1 cgd * This product includes software developed by John Polstra. 20 1.1 cgd * 4. The name of the author may not be used to endorse or promote products 21 1.1 cgd * derived from this software without specific prior written permission. 22 1.1 cgd * 23 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 1.1 cgd * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 1.1 cgd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 1.1 cgd * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 1.1 cgd * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 1.1 cgd * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 1.1 cgd * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 1.1 cgd * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 1.1 cgd * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 1.1 cgd * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.1 cgd /* 36 1.1 cgd * Dynamic linker for ELF. 37 1.1 cgd * 38 1.1 cgd * John Polstra <jdp (at) polstra.com>. 39 1.1 cgd */ 40 1.1 cgd 41 1.29 skrll #include <sys/cdefs.h> 42 1.29 skrll #ifndef lint 43 1.49 kamil __RCSID("$NetBSD: load.c,v 1.49 2020/09/21 16:08:57 kamil Exp $"); 44 1.29 skrll #endif /* not lint */ 45 1.29 skrll 46 1.48 christos #include <sys/types.h> 47 1.48 christos #include <sys/param.h> 48 1.48 christos #include <sys/mman.h> 49 1.48 christos #include <sys/sysctl.h> 50 1.48 christos #include <sys/stat.h> 51 1.48 christos 52 1.1 cgd #include <err.h> 53 1.1 cgd #include <errno.h> 54 1.1 cgd #include <fcntl.h> 55 1.1 cgd #include <stdarg.h> 56 1.1 cgd #include <stdio.h> 57 1.1 cgd #include <stdlib.h> 58 1.1 cgd #include <string.h> 59 1.1 cgd #include <unistd.h> 60 1.1 cgd #include <dirent.h> 61 1.1 cgd 62 1.1 cgd #include "debug.h" 63 1.1 cgd #include "rtld.h" 64 1.1 cgd 65 1.26 skrll static bool _rtld_load_by_name(const char *, Obj_Entry *, Needed_Entry **, 66 1.26 skrll int); 67 1.13 mycroft 68 1.22 mycroft #ifdef RTLD_LOADER 69 1.21 mycroft Objlist _rtld_list_main = /* Objects loaded at program startup */ 70 1.21 mycroft SIMPLEQ_HEAD_INITIALIZER(_rtld_list_main); 71 1.13 mycroft Objlist _rtld_list_global = /* Objects dlopened with RTLD_GLOBAL */ 72 1.13 mycroft SIMPLEQ_HEAD_INITIALIZER(_rtld_list_global); 73 1.43 skrll 74 1.35 ad void 75 1.35 ad _rtld_objlist_push_head(Objlist *list, Obj_Entry *obj) 76 1.35 ad { 77 1.35 ad Objlist_Entry *elm; 78 1.35 ad 79 1.35 ad elm = NEW(Objlist_Entry); 80 1.35 ad elm->obj = obj; 81 1.35 ad SIMPLEQ_INSERT_HEAD(list, elm, link); 82 1.35 ad } 83 1.13 mycroft 84 1.13 mycroft void 85 1.35 ad _rtld_objlist_push_tail(Objlist *list, Obj_Entry *obj) 86 1.13 mycroft { 87 1.13 mycroft Objlist_Entry *elm; 88 1.13 mycroft 89 1.13 mycroft elm = NEW(Objlist_Entry); 90 1.13 mycroft elm->obj = obj; 91 1.13 mycroft SIMPLEQ_INSERT_TAIL(list, elm, link); 92 1.13 mycroft } 93 1.13 mycroft 94 1.13 mycroft Objlist_Entry * 95 1.13 mycroft _rtld_objlist_find(Objlist *list, const Obj_Entry *obj) 96 1.13 mycroft { 97 1.13 mycroft Objlist_Entry *elm; 98 1.13 mycroft 99 1.16 lukem SIMPLEQ_FOREACH(elm, list, link) { 100 1.13 mycroft if (elm->obj == obj) 101 1.13 mycroft return elm; 102 1.13 mycroft } 103 1.13 mycroft return NULL; 104 1.13 mycroft } 105 1.23 mycroft #endif 106 1.6 christos 107 1.1 cgd /* 108 1.31 christos * Load a shared object into memory, if it is not already loaded. 109 1.1 cgd * 110 1.1 cgd * Returns a pointer to the Obj_Entry for the object. Returns NULL 111 1.1 cgd * on failure. 112 1.1 cgd */ 113 1.1 cgd Obj_Entry * 114 1.42 skrll _rtld_load_object(const char *filepath, int flags) 115 1.1 cgd { 116 1.3 christos Obj_Entry *obj; 117 1.5 mycroft int fd = -1; 118 1.5 mycroft struct stat sb; 119 1.25 junyoung size_t pathlen = strlen(filepath); 120 1.1 cgd 121 1.25 junyoung for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next) 122 1.43 skrll if (pathlen == obj->pathlen && !strcmp(obj->path, filepath)) 123 1.25 junyoung break; 124 1.3 christos 125 1.5 mycroft /* 126 1.5 mycroft * If we didn't find a match by pathname, open the file and check 127 1.5 mycroft * again by device and inode. This avoids false mismatches caused 128 1.5 mycroft * by multiple links or ".." in pathnames. 129 1.5 mycroft * 130 1.5 mycroft * To avoid a race, we open the file and use fstat() rather than 131 1.5 mycroft * using stat(). 132 1.5 mycroft */ 133 1.5 mycroft if (obj == NULL) { 134 1.3 christos if ((fd = open(filepath, O_RDONLY)) == -1) { 135 1.3 christos _rtld_error("Cannot open \"%s\"", filepath); 136 1.3 christos return NULL; 137 1.3 christos } 138 1.5 mycroft if (fstat(fd, &sb) == -1) { 139 1.5 mycroft _rtld_error("Cannot fstat \"%s\"", filepath); 140 1.5 mycroft close(fd); 141 1.5 mycroft return NULL; 142 1.5 mycroft } 143 1.5 mycroft for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next) { 144 1.5 mycroft if (obj->ino == sb.st_ino && obj->dev == sb.st_dev) { 145 1.5 mycroft close(fd); 146 1.5 mycroft break; 147 1.5 mycroft } 148 1.5 mycroft } 149 1.5 mycroft } 150 1.5 mycroft 151 1.46 skrll #ifdef RTLD_LOADER 152 1.46 skrll if (pathlen == _rtld_objself.pathlen && 153 1.46 skrll strcmp(_rtld_objself.path, filepath) == 0) { 154 1.47 christos close(fd); 155 1.46 skrll return &_rtld_objself; 156 1.46 skrll } 157 1.46 skrll #endif 158 1.46 skrll 159 1.5 mycroft if (obj == NULL) { /* First use of this object, so we must map it in */ 160 1.5 mycroft obj = _rtld_map_object(filepath, fd, &sb); 161 1.3 christos (void)close(fd); 162 1.31 christos if (obj == NULL) 163 1.3 christos return NULL; 164 1.33 cube _rtld_digest_dynamic(filepath, obj); 165 1.1 cgd 166 1.42 skrll if (flags & _RTLD_DLOPEN) { 167 1.42 skrll if (obj->z_noopen || (flags & _RTLD_NOLOAD)) { 168 1.42 skrll dbg(("refusing to load non-loadable \"%s\"", 169 1.42 skrll obj->path)); 170 1.42 skrll _rtld_error("Cannot dlopen non-loadable %s", 171 1.42 skrll obj->path); 172 1.42 skrll munmap(obj->mapbase, obj->mapsize); 173 1.42 skrll _rtld_obj_free(obj); 174 1.42 skrll return OBJ_ERR; 175 1.42 skrll } 176 1.42 skrll } 177 1.42 skrll 178 1.3 christos *_rtld_objtail = obj; 179 1.3 christos _rtld_objtail = &obj->next; 180 1.37 roy _rtld_objcount++; 181 1.38 skrll _rtld_objloads++; 182 1.1 cgd #ifdef RTLD_LOADER 183 1.49 kamil _rtld_linkmap_add(obj); /* for the debugger */ 184 1.1 cgd #endif 185 1.18 mycroft dbg((" %p .. %p: %s", obj->mapbase, 186 1.18 mycroft obj->mapbase + obj->mapsize - 1, obj->path)); 187 1.18 mycroft if (obj->textrel) 188 1.18 mycroft dbg((" WARNING: %s has impure text", obj->path)); 189 1.31 christos } 190 1.1 cgd 191 1.3 christos ++obj->refcount; 192 1.22 mycroft #ifdef RTLD_LOADER 193 1.42 skrll if (flags & _RTLD_MAIN && !obj->mainref) { 194 1.20 mycroft obj->mainref = 1; 195 1.40 skrll dbg(("adding %p (%s) to _rtld_list_main", obj, obj->path)); 196 1.35 ad _rtld_objlist_push_tail(&_rtld_list_main, obj); 197 1.20 mycroft } 198 1.42 skrll if (flags & _RTLD_GLOBAL && !obj->globalref) { 199 1.20 mycroft obj->globalref = 1; 200 1.40 skrll dbg(("adding %p (%s) to _rtld_list_global", obj, obj->path)); 201 1.35 ad _rtld_objlist_push_tail(&_rtld_list_global, obj); 202 1.20 mycroft } 203 1.22 mycroft #endif 204 1.3 christos return obj; 205 1.1 cgd } 206 1.1 cgd 207 1.7 christos static bool 208 1.42 skrll _rtld_load_by_name(const char *name, Obj_Entry *obj, Needed_Entry **needed, 209 1.42 skrll int flags) 210 1.6 christos { 211 1.6 christos Library_Xform *x = _rtld_xforms; 212 1.44 christos Obj_Entry *o; 213 1.36 christos size_t j; 214 1.36 christos ssize_t i; 215 1.7 christos bool got = false; 216 1.6 christos union { 217 1.6 christos int i; 218 1.28 cube u_quad_t q; 219 1.6 christos char s[16]; 220 1.6 christos } val; 221 1.6 christos 222 1.18 mycroft dbg(("load by name %s %p", name, x)); 223 1.44 christos for (o = _rtld_objlist->next; o != NULL; o = o->next) 224 1.44 christos if (_rtld_object_match_name(o, name)) { 225 1.45 christos ++o->refcount; 226 1.44 christos (*needed)->obj = o; 227 1.44 christos return true; 228 1.44 christos } 229 1.44 christos 230 1.6 christos for (; x; x = x->next) { 231 1.6 christos if (strcmp(x->name, name) != 0) 232 1.6 christos continue; 233 1.6 christos 234 1.28 cube j = sizeof(val); 235 1.28 cube if ((i = _rtld_sysctl(x->ctlname, &val, &j)) == -1) { 236 1.28 cube xwarnx(_PATH_LD_HINTS ": invalid/unknown sysctl for %s (%d)", 237 1.28 cube name, errno); 238 1.6 christos break; 239 1.6 christos } 240 1.6 christos 241 1.28 cube switch (i) { 242 1.28 cube case CTLTYPE_QUAD: 243 1.28 cube xsnprintf(val.s, sizeof(val.s), "%" PRIu64, val.q); 244 1.28 cube break; 245 1.6 christos case CTLTYPE_INT: 246 1.6 christos xsnprintf(val.s, sizeof(val.s), "%d", val.i); 247 1.6 christos break; 248 1.6 christos case CTLTYPE_STRING: 249 1.6 christos break; 250 1.6 christos default: 251 1.28 cube xwarnx("unsupported sysctl type %d", (int)i); 252 1.6 christos break; 253 1.6 christos } 254 1.6 christos 255 1.18 mycroft dbg(("sysctl returns %s", val.s)); 256 1.6 christos 257 1.6 christos for (i = 0; i < RTLD_MAX_ENTRY && x->entry[i].value != NULL; 258 1.6 christos i++) { 259 1.18 mycroft dbg(("entry %ld", (unsigned long)i)); 260 1.6 christos if (strcmp(x->entry[i].value, val.s) == 0) 261 1.6 christos break; 262 1.6 christos } 263 1.6 christos 264 1.6 christos if (i == RTLD_MAX_ENTRY) { 265 1.11 christos xwarnx("sysctl value %s not found for lib%s", 266 1.6 christos val.s, name); 267 1.6 christos break; 268 1.6 christos } 269 1.39 skrll 270 1.6 christos for (j = 0; j < RTLD_MAX_LIBRARY && 271 1.6 christos x->entry[i].library[j] != NULL; j++) { 272 1.19 mycroft o = _rtld_load_library(x->entry[i].library[j], obj, 273 1.42 skrll flags); 274 1.19 mycroft if (o == NULL) { 275 1.11 christos xwarnx("could not load %s for %s", 276 1.6 christos x->entry[i].library[j], name); 277 1.6 christos continue; 278 1.6 christos } 279 1.7 christos got = true; 280 1.7 christos if (j == 0) 281 1.7 christos (*needed)->obj = o; 282 1.7 christos else { 283 1.7 christos /* make a new one and put it in the chain */ 284 1.7 christos Needed_Entry *ne = xmalloc(sizeof(*ne)); 285 1.7 christos ne->name = (*needed)->name; 286 1.7 christos ne->obj = o; 287 1.7 christos ne->next = (*needed)->next; 288 1.7 christos (*needed)->next = ne; 289 1.7 christos *needed = ne; 290 1.7 christos } 291 1.43 skrll 292 1.6 christos } 293 1.43 skrll 294 1.6 christos } 295 1.6 christos 296 1.7 christos if (got) 297 1.7 christos return true; 298 1.6 christos 299 1.42 skrll return ((*needed)->obj = _rtld_load_library(name, obj, flags)) != NULL; 300 1.6 christos } 301 1.6 christos 302 1.6 christos 303 1.1 cgd /* 304 1.1 cgd * Given a shared object, traverse its list of needed objects, and load 305 1.1 cgd * each of them. Returns 0 on success. Generates an error message and 306 1.1 cgd * returns -1 on failure. 307 1.1 cgd */ 308 1.1 cgd int 309 1.42 skrll _rtld_load_needed_objects(Obj_Entry *first, int flags) 310 1.1 cgd { 311 1.3 christos Obj_Entry *obj; 312 1.3 christos int status = 0; 313 1.1 cgd 314 1.3 christos for (obj = first; obj != NULL; obj = obj->next) { 315 1.3 christos Needed_Entry *needed; 316 1.1 cgd 317 1.3 christos for (needed = obj->needed; needed != NULL; 318 1.3 christos needed = needed->next) { 319 1.3 christos const char *name = obj->strtab + needed->name; 320 1.42 skrll #ifdef RTLD_LOADER 321 1.42 skrll Obj_Entry *nobj; 322 1.42 skrll #endif 323 1.42 skrll if (!_rtld_load_by_name(name, obj, &needed, 324 1.42 skrll flags & ~_RTLD_NOLOAD)) 325 1.6 christos status = -1; /* FIXME - cleanup */ 326 1.1 cgd #ifdef RTLD_LOADER 327 1.3 christos if (status == -1) 328 1.3 christos return status; 329 1.42 skrll 330 1.42 skrll if (flags & _RTLD_MAIN) 331 1.42 skrll continue; 332 1.42 skrll 333 1.42 skrll nobj = needed->obj; 334 1.42 skrll if (nobj->z_nodelete && !obj->ref_nodel) { 335 1.42 skrll dbg(("obj %s nodelete", nobj->path)); 336 1.42 skrll _rtld_ref_dag(nobj); 337 1.42 skrll nobj->ref_nodel = true; 338 1.42 skrll } 339 1.1 cgd #endif 340 1.3 christos } 341 1.1 cgd } 342 1.1 cgd 343 1.3 christos return status; 344 1.1 cgd } 345 1.4 kleink 346 1.4 kleink #ifdef RTLD_LOADER 347 1.4 kleink int 348 1.26 skrll _rtld_preload(const char *preload_path) 349 1.4 kleink { 350 1.4 kleink const char *path; 351 1.4 kleink char *cp, *buf; 352 1.4 kleink int status = 0; 353 1.4 kleink 354 1.27 christos if (preload_path != NULL && *preload_path != '\0') { 355 1.4 kleink cp = buf = xstrdup(preload_path); 356 1.15 skrll while ((path = strsep(&cp, " :")) != NULL && status == 0) { 357 1.42 skrll if (!_rtld_load_object(path, _RTLD_MAIN)) 358 1.4 kleink status = -1; 359 1.18 mycroft else 360 1.4 kleink dbg((" preloaded \"%s\"", path)); 361 1.4 kleink } 362 1.34 ad xfree(buf); 363 1.4 kleink } 364 1.4 kleink 365 1.41 skrll return status; 366 1.4 kleink } 367 1.4 kleink #endif 368