1 /* $NetBSD: load.c,v 1.42 2010/12/24 12:41:43 skrll 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.42 2010/12/24 12:41:43 skrll 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 if (obj == NULL) { /* First use of this object, so we must map it in */ 150 obj = _rtld_map_object(filepath, fd, &sb); 151 (void)close(fd); 152 if (obj == NULL) 153 return NULL; 154 _rtld_digest_dynamic(filepath, obj); 155 156 if (flags & _RTLD_DLOPEN) { 157 if (obj->z_noopen || (flags & _RTLD_NOLOAD)) { 158 dbg(("refusing to load non-loadable \"%s\"", 159 obj->path)); 160 _rtld_error("Cannot dlopen non-loadable %s", 161 obj->path); 162 munmap(obj->mapbase, obj->mapsize); 163 _rtld_obj_free(obj); 164 return OBJ_ERR; 165 } 166 } 167 168 *_rtld_objtail = obj; 169 _rtld_objtail = &obj->next; 170 _rtld_objcount++; 171 _rtld_objloads++; 172 #ifdef RTLD_LOADER 173 _rtld_linkmap_add(obj); /* for GDB */ 174 #endif 175 dbg((" %p .. %p: %s", obj->mapbase, 176 obj->mapbase + obj->mapsize - 1, obj->path)); 177 if (obj->textrel) 178 dbg((" WARNING: %s has impure text", obj->path)); 179 } 180 181 ++obj->refcount; 182 #ifdef RTLD_LOADER 183 if (flags & _RTLD_MAIN && !obj->mainref) { 184 obj->mainref = 1; 185 dbg(("adding %p (%s) to _rtld_list_main", obj, obj->path)); 186 _rtld_objlist_push_tail(&_rtld_list_main, obj); 187 } 188 if (flags & _RTLD_GLOBAL && !obj->globalref) { 189 obj->globalref = 1; 190 dbg(("adding %p (%s) to _rtld_list_global", obj, obj->path)); 191 _rtld_objlist_push_tail(&_rtld_list_global, obj); 192 } 193 #endif 194 return obj; 195 } 196 197 static bool 198 _rtld_load_by_name(const char *name, Obj_Entry *obj, Needed_Entry **needed, 199 int flags) 200 { 201 Library_Xform *x = _rtld_xforms; 202 Obj_Entry *o = NULL; 203 size_t j; 204 ssize_t i; 205 bool got = false; 206 union { 207 int i; 208 u_quad_t q; 209 char s[16]; 210 } val; 211 212 dbg(("load by name %s %p", name, x)); 213 for (; x; x = x->next) { 214 if (strcmp(x->name, name) != 0) 215 continue; 216 217 j = sizeof(val); 218 if ((i = _rtld_sysctl(x->ctlname, &val, &j)) == -1) { 219 xwarnx(_PATH_LD_HINTS ": invalid/unknown sysctl for %s (%d)", 220 name, errno); 221 break; 222 } 223 224 switch (i) { 225 case CTLTYPE_QUAD: 226 xsnprintf(val.s, sizeof(val.s), "%" PRIu64, val.q); 227 break; 228 case CTLTYPE_INT: 229 xsnprintf(val.s, sizeof(val.s), "%d", val.i); 230 break; 231 case CTLTYPE_STRING: 232 break; 233 default: 234 xwarnx("unsupported sysctl type %d", (int)i); 235 break; 236 } 237 238 dbg(("sysctl returns %s", val.s)); 239 240 for (i = 0; i < RTLD_MAX_ENTRY && x->entry[i].value != NULL; 241 i++) { 242 dbg(("entry %ld", (unsigned long)i)); 243 if (strcmp(x->entry[i].value, val.s) == 0) 244 break; 245 } 246 247 if (i == RTLD_MAX_ENTRY) { 248 xwarnx("sysctl value %s not found for lib%s", 249 val.s, name); 250 break; 251 } 252 253 for (j = 0; j < RTLD_MAX_LIBRARY && 254 x->entry[i].library[j] != NULL; j++) { 255 o = _rtld_load_library(x->entry[i].library[j], obj, 256 flags); 257 if (o == NULL) { 258 xwarnx("could not load %s for %s", 259 x->entry[i].library[j], name); 260 continue; 261 } 262 got = true; 263 if (j == 0) 264 (*needed)->obj = o; 265 else { 266 /* make a new one and put it in the chain */ 267 Needed_Entry *ne = xmalloc(sizeof(*ne)); 268 ne->name = (*needed)->name; 269 ne->obj = o; 270 ne->next = (*needed)->next; 271 (*needed)->next = ne; 272 *needed = ne; 273 } 274 275 } 276 277 } 278 279 if (got) 280 return true; 281 282 return ((*needed)->obj = _rtld_load_library(name, obj, flags)) != NULL; 283 } 284 285 286 /* 287 * Given a shared object, traverse its list of needed objects, and load 288 * each of them. Returns 0 on success. Generates an error message and 289 * returns -1 on failure. 290 */ 291 int 292 _rtld_load_needed_objects(Obj_Entry *first, int flags) 293 { 294 Obj_Entry *obj; 295 int status = 0; 296 297 for (obj = first; obj != NULL; obj = obj->next) { 298 Needed_Entry *needed; 299 300 for (needed = obj->needed; needed != NULL; 301 needed = needed->next) { 302 const char *name = obj->strtab + needed->name; 303 #ifdef RTLD_LOADER 304 Obj_Entry *nobj; 305 #endif 306 if (!_rtld_load_by_name(name, obj, &needed, 307 flags & ~_RTLD_NOLOAD)) 308 status = -1; /* FIXME - cleanup */ 309 #ifdef RTLD_LOADER 310 if (status == -1) 311 return status; 312 313 if (flags & _RTLD_MAIN) 314 continue; 315 316 nobj = needed->obj; 317 if (nobj->z_nodelete && !obj->ref_nodel) { 318 dbg(("obj %s nodelete", nobj->path)); 319 _rtld_ref_dag(nobj); 320 nobj->ref_nodel = true; 321 } 322 #endif 323 } 324 } 325 326 return status; 327 } 328 329 #ifdef RTLD_LOADER 330 int 331 _rtld_preload(const char *preload_path) 332 { 333 const char *path; 334 char *cp, *buf; 335 int status = 0; 336 337 if (preload_path != NULL && *preload_path != '\0') { 338 cp = buf = xstrdup(preload_path); 339 while ((path = strsep(&cp, " :")) != NULL && status == 0) { 340 if (!_rtld_load_object(path, _RTLD_MAIN)) 341 status = -1; 342 else 343 dbg((" preloaded \"%s\"", path)); 344 } 345 xfree(buf); 346 } 347 348 return status; 349 } 350 #endif 351