1 /* $NetBSD: search.c,v 1.30 2026/07/21 04:05:06 riastradh Exp $ */ 2 3 /* 4 * Copyright 1996 Matt Thomas <matt (at) 3am-software.com> 5 * All rights reserved. 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 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by John Polstra. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Dynamic linker for ELF. 35 * 36 * John Polstra <jdp (at) polstra.com>. 37 */ 38 39 #include <sys/cdefs.h> 40 #ifndef lint 41 __RCSID("$NetBSD: search.c,v 1.30 2026/07/21 04:05:06 riastradh Exp $"); 42 #endif /* not lint */ 43 44 #include <err.h> 45 #include <errno.h> 46 #include <fcntl.h> 47 #include <stdarg.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 #include <sys/types.h> 53 #include <sys/mman.h> 54 #include <sys/stat.h> 55 #include <dirent.h> 56 57 #include "debug.h" 58 #include "rtld.h" 59 60 /* 61 * Data declarations. 62 */ 63 static Search_Path *_rtld_invalid_paths; 64 65 static Obj_Entry *_rtld_search_library_path(const char *, size_t, 66 const char *, size_t, int, sigset_t *); 67 68 static Obj_Entry * 69 _rtld_search_library_path(const char *name, size_t namelen, 70 const char *dir, size_t dirlen, int flags, sigset_t *mask) 71 { 72 char pathname[MAXPATHLEN]; 73 size_t pathnamelen; 74 Obj_Entry *obj; 75 Search_Path *sp; 76 77 pathnamelen = dirlen + 1 + namelen; 78 if (pathnamelen >= sizeof(pathname)) 79 return NULL; 80 81 for (sp = _rtld_invalid_paths; sp != NULL; sp = sp->sp_next) { 82 if (sp->sp_pathlen == pathnamelen && 83 sp->sp_path[dirlen] == '/' && 84 !memcmp(name, sp->sp_path + dirlen + 1, namelen) && 85 !memcmp(dir, sp->sp_path, dirlen)) { 86 return NULL; 87 } 88 } 89 90 memcpy(pathname, dir, dirlen); 91 pathname[dirlen] = '/'; 92 memcpy(pathname + dirlen + 1, name, namelen); 93 pathname[pathnamelen] = '\0'; 94 95 dbg((" Trying \"%s\"", pathname)); 96 obj = _rtld_load_object(pathname, flags, mask); 97 if (obj == NULL) { 98 Search_Path *path; 99 100 path = NEW(Search_Path); 101 path->sp_pathlen = pathnamelen; 102 path->sp_path = xstrdup(pathname); 103 path->sp_next = _rtld_invalid_paths; 104 _rtld_invalid_paths = path; 105 } else if (__predict_true(obj != OBJ_ERR)) { 106 assert(obj->refcount > 0); 107 } 108 return obj; 109 } 110 111 /* 112 * Find the library with the given name, and return its full pathname. 113 * The returned string is dynamically allocated. Generates an error 114 * message and returns NULL if the library cannot be found. 115 * 116 * If the second argument is non-NULL, then it refers to an already- 117 * loaded shared object, whose library search path will be searched. 118 */ 119 Obj_Entry * 120 _rtld_load_library(const char *name, const Obj_Entry *refobj, int flags, 121 sigset_t *mask) 122 { 123 extern char *__progname; 124 char tmperror[512], *tmperrorp; 125 Search_Path *sp; 126 const char *pathname; 127 int namelen; 128 Obj_Entry *obj; 129 130 if (strchr(name, '/') != NULL) { /* Hard coded pathname */ 131 if (name[0] != '/' && !_rtld_trust) { 132 _rtld_error( 133 "absolute pathname required for shared object \"%s\"", 134 name); 135 return NULL; 136 } 137 pathname = name; 138 goto found; 139 } 140 dbg((" Searching for \"%s\" (%p)", name, refobj)); 141 142 tmperrorp = dlerror(); 143 if (tmperrorp != NULL) { 144 strlcpy(tmperror, tmperrorp, sizeof(tmperror)); 145 tmperrorp = tmperror; 146 } 147 148 namelen = strlen(name); 149 150 for (sp = _rtld_paths; sp != NULL; sp = sp->sp_next) 151 if ((obj = _rtld_search_library_path(name, namelen, 152 sp->sp_path, sp->sp_pathlen, flags, mask)) != NULL) 153 goto pathfound; 154 155 if (refobj != NULL) 156 for (sp = refobj->rpaths; sp != NULL; sp = sp->sp_next) 157 if ((obj = _rtld_search_library_path(name, 158 namelen, sp->sp_path, sp->sp_pathlen, flags, mask)) 159 != NULL) 160 goto pathfound; 161 162 for (sp = _rtld_default_paths; sp != NULL; sp = sp->sp_next) 163 if ((obj = _rtld_search_library_path(name, namelen, 164 sp->sp_path, sp->sp_pathlen, flags, mask)) != NULL) 165 goto pathfound; 166 167 _rtld_error("%s: Shared object \"%s\" not found", 168 refobj ? refobj->path : __progname, name); 169 return NULL; 170 171 pathfound: 172 /* 173 * The library has been found, but it couldn't be loaded for some 174 * reason. 175 */ 176 if (obj == OBJ_ERR) 177 return NULL; 178 /* 179 * Successfully found a library; restore the dlerror state as it was 180 * before _rtld_load_library() was called (any failed call to 181 * _rtld_search_library_path() will set the dlerror state, but if the 182 * library was eventually found, then the error state should not 183 * change. 184 */ 185 if (tmperrorp) 186 _rtld_error("%s", tmperror); 187 else 188 (void)dlerror(); 189 assert(obj->refcount > 0); 190 return obj; 191 192 found: 193 obj = _rtld_load_object(pathname, flags, mask); 194 if (obj == OBJ_ERR) 195 return NULL; 196 197 assert(obj == NULL || obj->refcount > 0); 198 return obj; 199 } 200