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