1 /* $NetBSD: load.c,v 1.34 2007/10/05 22:21:07 ad 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.34 2007/10/05 22:21:07 ad 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_add(Objlist *list, Obj_Entry *obj) 74 { 75 Objlist_Entry *elm; 76 77 elm = NEW(Objlist_Entry); 78 elm->obj = obj; 79 SIMPLEQ_INSERT_TAIL(list, elm, link); 80 } 81 82 Objlist_Entry * 83 _rtld_objlist_find(Objlist *list, const Obj_Entry *obj) 84 { 85 Objlist_Entry *elm; 86 87 SIMPLEQ_FOREACH(elm, list, link) { 88 if (elm->obj == obj) 89 return elm; 90 } 91 return NULL; 92 } 93 #endif 94 95 /* 96 * Load a shared object into memory, if it is not already loaded. 97 * 98 * Returns a pointer to the Obj_Entry for the object. Returns NULL 99 * on failure. 100 */ 101 Obj_Entry * 102 _rtld_load_object(const char *filepath, int mode) 103 { 104 Obj_Entry *obj; 105 int fd = -1; 106 struct stat sb; 107 size_t pathlen = strlen(filepath); 108 109 for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next) 110 if (pathlen == obj->pathlen && !strcmp(obj->path, filepath)) 111 break; 112 113 /* 114 * If we didn't find a match by pathname, open the file and check 115 * again by device and inode. This avoids false mismatches caused 116 * by multiple links or ".." in pathnames. 117 * 118 * To avoid a race, we open the file and use fstat() rather than 119 * using stat(). 120 */ 121 if (obj == NULL) { 122 if ((fd = open(filepath, O_RDONLY)) == -1) { 123 _rtld_error("Cannot open \"%s\"", filepath); 124 return NULL; 125 } 126 if (fstat(fd, &sb) == -1) { 127 _rtld_error("Cannot fstat \"%s\"", filepath); 128 close(fd); 129 return NULL; 130 } 131 for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next) { 132 if (obj->ino == sb.st_ino && obj->dev == sb.st_dev) { 133 close(fd); 134 break; 135 } 136 } 137 } 138 139 if (obj == NULL) { /* First use of this object, so we must map it in */ 140 obj = _rtld_map_object(filepath, fd, &sb); 141 (void)close(fd); 142 if (obj == NULL) 143 return NULL; 144 _rtld_digest_dynamic(filepath, obj); 145 146 *_rtld_objtail = obj; 147 _rtld_objtail = &obj->next; 148 #ifdef RTLD_LOADER 149 _rtld_linkmap_add(obj); /* for GDB */ 150 #endif 151 dbg((" %p .. %p: %s", obj->mapbase, 152 obj->mapbase + obj->mapsize - 1, obj->path)); 153 if (obj->textrel) 154 dbg((" WARNING: %s has impure text", obj->path)); 155 } 156 157 ++obj->refcount; 158 #ifdef RTLD_LOADER 159 if (mode & RTLD_MAIN && !obj->mainref) { 160 obj->mainref = 1; 161 rdbg(("adding %p (%s) to _rtld_list_main", obj, obj->path)); 162 _rtld_objlist_add(&_rtld_list_main, obj); 163 } 164 if (mode & RTLD_GLOBAL && !obj->globalref) { 165 obj->globalref = 1; 166 rdbg(("adding %p (%s) to _rtld_list_global", obj, obj->path)); 167 _rtld_objlist_add(&_rtld_list_global, obj); 168 } 169 #endif 170 return obj; 171 } 172 173 static bool 174 _rtld_load_by_name(const char *name, Obj_Entry *obj, Needed_Entry **needed, int mode) 175 { 176 Library_Xform *x = _rtld_xforms; 177 Obj_Entry *o = NULL; 178 size_t i, j; 179 bool got = false; 180 union { 181 int i; 182 u_quad_t q; 183 char s[16]; 184 } val; 185 186 dbg(("load by name %s %p", name, x)); 187 for (; x; x = x->next) { 188 if (strcmp(x->name, name) != 0) 189 continue; 190 191 j = sizeof(val); 192 if ((i = _rtld_sysctl(x->ctlname, &val, &j)) == -1) { 193 xwarnx(_PATH_LD_HINTS ": invalid/unknown sysctl for %s (%d)", 194 name, errno); 195 break; 196 } 197 198 switch (i) { 199 case CTLTYPE_QUAD: 200 xsnprintf(val.s, sizeof(val.s), "%" PRIu64, val.q); 201 break; 202 case CTLTYPE_INT: 203 xsnprintf(val.s, sizeof(val.s), "%d", val.i); 204 break; 205 case CTLTYPE_STRING: 206 break; 207 default: 208 xwarnx("unsupported sysctl type %d", (int)i); 209 break; 210 } 211 212 dbg(("sysctl returns %s", val.s)); 213 214 for (i = 0; i < RTLD_MAX_ENTRY && x->entry[i].value != NULL; 215 i++) { 216 dbg(("entry %ld", (unsigned long)i)); 217 if (strcmp(x->entry[i].value, val.s) == 0) 218 break; 219 } 220 221 if (i == RTLD_MAX_ENTRY) { 222 xwarnx("sysctl value %s not found for lib%s", 223 val.s, name); 224 break; 225 } 226 /* XXX: This can mess up debuggers, cause we lie about 227 * what we loaded in the needed objects */ 228 for (j = 0; j < RTLD_MAX_LIBRARY && 229 x->entry[i].library[j] != NULL; j++) { 230 o = _rtld_load_library(x->entry[i].library[j], obj, 231 mode); 232 if (o == NULL) { 233 xwarnx("could not load %s for %s", 234 x->entry[i].library[j], name); 235 continue; 236 } 237 got = true; 238 if (j == 0) 239 (*needed)->obj = o; 240 else { 241 /* make a new one and put it in the chain */ 242 Needed_Entry *ne = xmalloc(sizeof(*ne)); 243 ne->name = (*needed)->name; 244 ne->obj = o; 245 ne->next = (*needed)->next; 246 (*needed)->next = ne; 247 *needed = ne; 248 } 249 250 } 251 252 } 253 254 if (got) 255 return true; 256 257 return ((*needed)->obj = _rtld_load_library(name, obj, mode)) != NULL; 258 } 259 260 261 /* 262 * Given a shared object, traverse its list of needed objects, and load 263 * each of them. Returns 0 on success. Generates an error message and 264 * returns -1 on failure. 265 */ 266 int 267 _rtld_load_needed_objects(Obj_Entry *first, int mode) 268 { 269 Obj_Entry *obj; 270 int status = 0; 271 272 for (obj = first; obj != NULL; obj = obj->next) { 273 Needed_Entry *needed; 274 275 for (needed = obj->needed; needed != NULL; 276 needed = needed->next) { 277 const char *name = obj->strtab + needed->name; 278 if (!_rtld_load_by_name(name, obj, &needed, mode)) 279 status = -1; /* FIXME - cleanup */ 280 #ifdef RTLD_LOADER 281 if (status == -1) 282 return status; 283 #endif 284 } 285 } 286 287 return status; 288 } 289 290 #ifdef RTLD_LOADER 291 int 292 _rtld_preload(const char *preload_path) 293 { 294 const char *path; 295 char *cp, *buf; 296 int status = 0; 297 298 if (preload_path != NULL && *preload_path != '\0') { 299 cp = buf = xstrdup(preload_path); 300 while ((path = strsep(&cp, " :")) != NULL && status == 0) { 301 if (!_rtld_load_object(path, RTLD_MAIN)) 302 status = -1; 303 else 304 dbg((" preloaded \"%s\"", path)); 305 } 306 xfree(buf); 307 } 308 309 return (status); 310 } 311 #endif 312