1*dca0c0f4Sjoerg /* $NetBSD: search.c,v 1.27 2020/04/22 23:54:32 joerg Exp $ */
241fe218bScgd
341fe218bScgd /*
441fe218bScgd * Copyright 1996 Matt Thomas <matt@3am-software.com>
541fe218bScgd * All rights reserved.
641fe218bScgd *
741fe218bScgd * Redistribution and use in source and binary forms, with or without
841fe218bScgd * modification, are permitted provided that the following conditions
941fe218bScgd * are met:
1041fe218bScgd * 1. Redistributions of source code must retain the above copyright
1141fe218bScgd * notice, this list of conditions and the following disclaimer.
1241fe218bScgd * 2. Redistributions in binary form must reproduce the above copyright
1341fe218bScgd * notice, this list of conditions and the following disclaimer in the
1441fe218bScgd * documentation and/or other materials provided with the distribution.
1541fe218bScgd * 3. All advertising materials mentioning features or use of this software
1641fe218bScgd * must display the following acknowledgement:
1741fe218bScgd * This product includes software developed by John Polstra.
1841fe218bScgd * 4. The name of the author may not be used to endorse or promote products
1941fe218bScgd * derived from this software without specific prior written permission.
2041fe218bScgd *
2141fe218bScgd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2241fe218bScgd * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2341fe218bScgd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2441fe218bScgd * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2541fe218bScgd * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2641fe218bScgd * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2741fe218bScgd * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2841fe218bScgd * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2941fe218bScgd * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3041fe218bScgd * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3141fe218bScgd */
3241fe218bScgd
3341fe218bScgd /*
3441fe218bScgd * Dynamic linker for ELF.
3541fe218bScgd *
3641fe218bScgd * John Polstra <jdp@polstra.com>.
3741fe218bScgd */
3841fe218bScgd
392728318eSskrll #include <sys/cdefs.h>
402728318eSskrll #ifndef lint
41*dca0c0f4Sjoerg __RCSID("$NetBSD: search.c,v 1.27 2020/04/22 23:54:32 joerg Exp $");
422728318eSskrll #endif /* not lint */
432728318eSskrll
4441fe218bScgd #include <err.h>
4541fe218bScgd #include <errno.h>
4641fe218bScgd #include <fcntl.h>
4741fe218bScgd #include <stdarg.h>
4841fe218bScgd #include <stdio.h>
4941fe218bScgd #include <stdlib.h>
5041fe218bScgd #include <string.h>
5141fe218bScgd #include <unistd.h>
5241fe218bScgd #include <sys/types.h>
5341fe218bScgd #include <sys/mman.h>
5441fe218bScgd #include <sys/stat.h>
5541fe218bScgd #include <dirent.h>
5641fe218bScgd
5741fe218bScgd #include "debug.h"
5841fe218bScgd #include "rtld.h"
5941fe218bScgd
6041fe218bScgd /*
6141fe218bScgd * Data declarations.
6241fe218bScgd */
63*dca0c0f4Sjoerg static Search_Path *_rtld_invalid_paths;
64a189aa3eSjunyoung
655f573ab6Sskrll static Obj_Entry *_rtld_search_library_path(const char *, size_t,
665f573ab6Sskrll const char *, size_t, int);
6741fe218bScgd
6886103e2fSmycroft static Obj_Entry *
_rtld_search_library_path(const char * name,size_t namelen,const char * dir,size_t dirlen,int flags)695f573ab6Sskrll _rtld_search_library_path(const char *name, size_t namelen,
70f1d73a2cSskrll const char *dir, size_t dirlen, int flags)
7141fe218bScgd {
720339fe66Schristos char pathname[MAXPATHLEN];
73a189aa3eSjunyoung size_t pathnamelen;
7486103e2fSmycroft Obj_Entry *obj;
75a189aa3eSjunyoung Search_Path *sp;
7641fe218bScgd
77a189aa3eSjunyoung pathnamelen = dirlen + 1 + namelen;
780339fe66Schristos if (pathnamelen >= sizeof(pathname))
790339fe66Schristos return NULL;
80a189aa3eSjunyoung
81a189aa3eSjunyoung for (sp = _rtld_invalid_paths; sp != NULL; sp = sp->sp_next) {
82a189aa3eSjunyoung if (sp->sp_pathlen == pathnamelen &&
8369722116Sjoerg sp->sp_path[dirlen] == '/' &&
84ad8ccd62Smycroft !memcmp(name, sp->sp_path + dirlen + 1, namelen) &&
85ad8ccd62Smycroft !memcmp(dir, sp->sp_path, dirlen)) {
86a189aa3eSjunyoung return NULL;
87a189aa3eSjunyoung }
88a189aa3eSjunyoung }
89a189aa3eSjunyoung
9069722116Sjoerg memcpy(pathname, dir, dirlen);
9119480313Scgd pathname[dirlen] = '/';
9269722116Sjoerg memcpy(pathname + dirlen + 1, name, namelen);
9369722116Sjoerg pathname[pathnamelen] = '\0';
9441fe218bScgd
9526475619Schristos dbg((" Trying \"%s\"", pathname));
96f1d73a2cSskrll obj = _rtld_load_object(pathname, flags);
97a189aa3eSjunyoung if (obj == NULL) {
98a189aa3eSjunyoung Search_Path *path;
99a189aa3eSjunyoung
100a189aa3eSjunyoung path = NEW(Search_Path);
101a189aa3eSjunyoung path->sp_pathlen = pathnamelen;
1020339fe66Schristos path->sp_path = xstrdup(pathname);
103a189aa3eSjunyoung path->sp_next = _rtld_invalid_paths;
104a189aa3eSjunyoung _rtld_invalid_paths = path;
105a189aa3eSjunyoung }
10686103e2fSmycroft return obj;
10741fe218bScgd }
10826475619Schristos
10941fe218bScgd /*
11041fe218bScgd * Find the library with the given name, and return its full pathname.
11141fe218bScgd * The returned string is dynamically allocated. Generates an error
11241fe218bScgd * message and returns NULL if the library cannot be found.
11341fe218bScgd *
11441fe218bScgd * If the second argument is non-NULL, then it refers to an already-
11541fe218bScgd * loaded shared object, whose library search path will be searched.
11641fe218bScgd */
11786103e2fSmycroft Obj_Entry *
_rtld_load_library(const char * name,const Obj_Entry * refobj,int flags)118f1d73a2cSskrll _rtld_load_library(const char *name, const Obj_Entry *refobj, int flags)
11941fe218bScgd {
120d17b8a0eSchristos extern char *__progname;
12115f633fbSnathanw char tmperror[512], *tmperrorp;
12219480313Scgd Search_Path *sp;
1230339fe66Schristos const char *pathname;
12419480313Scgd int namelen;
12586103e2fSmycroft Obj_Entry *obj;
12641fe218bScgd
12741fe218bScgd if (strchr(name, '/') != NULL) { /* Hard coded pathname */
12841fe218bScgd if (name[0] != '/' && !_rtld_trust) {
12926475619Schristos _rtld_error(
1307f448552Smycroft "absolute pathname required for shared object \"%s\"",
13141fe218bScgd name);
13241fe218bScgd return NULL;
13341fe218bScgd }
1340339fe66Schristos pathname = name;
135f1184d19Smycroft goto found;
13641fe218bScgd }
13726475619Schristos dbg((" Searching for \"%s\" (%p)", name, refobj));
13841fe218bScgd
139d9007319Sskrll tmperrorp = dlerror();
14015f633fbSnathanw if (tmperrorp != NULL) {
1419d7a8fa9Smrg strlcpy(tmperror, tmperrorp, sizeof(tmperror));
14215f633fbSnathanw tmperrorp = tmperror;
14315f633fbSnathanw }
14415f633fbSnathanw
14519480313Scgd namelen = strlen(name);
14619480313Scgd
1471cc052ceSkleink for (sp = _rtld_paths; sp != NULL; sp = sp->sp_next)
14886103e2fSmycroft if ((obj = _rtld_search_library_path(name, namelen,
149f1d73a2cSskrll sp->sp_path, sp->sp_pathlen, flags)) != NULL)
15015f633fbSnathanw goto pathfound;
15119480313Scgd
1521cc052ceSkleink if (refobj != NULL)
1531cc052ceSkleink for (sp = refobj->rpaths; sp != NULL; sp = sp->sp_next)
15486103e2fSmycroft if ((obj = _rtld_search_library_path(name,
155f1d73a2cSskrll namelen, sp->sp_path, sp->sp_pathlen, flags)) != NULL)
15615f633fbSnathanw goto pathfound;
1571cc052ceSkleink
1581cc052ceSkleink for (sp = _rtld_default_paths; sp != NULL; sp = sp->sp_next)
15986103e2fSmycroft if ((obj = _rtld_search_library_path(name, namelen,
160f1d73a2cSskrll sp->sp_path, sp->sp_pathlen, flags)) != NULL)
16115f633fbSnathanw goto pathfound;
16219480313Scgd
163d17b8a0eSchristos _rtld_error("%s: Shared object \"%s\" not found",
164d17b8a0eSchristos refobj ? refobj->path : __progname, name);
16519480313Scgd return NULL;
16686103e2fSmycroft
16715f633fbSnathanw pathfound:
16815f633fbSnathanw /*
169f1d73a2cSskrll * The library has been found, but it couldn't be loaded for some
170f1d73a2cSskrll * reason.
171f1d73a2cSskrll */
172f1d73a2cSskrll if (obj == OBJ_ERR)
173f1d73a2cSskrll return NULL;
174f1d73a2cSskrll /*
17515f633fbSnathanw * Successfully found a library; restore the dlerror state as it was
17615f633fbSnathanw * before _rtld_load_library() was called (any failed call to
17715f633fbSnathanw * _rtld_search_library_path() will set the dlerror state, but if the
17815f633fbSnathanw * library was eventually found, then the error state should not
17915f633fbSnathanw * change.
18015f633fbSnathanw */
18115f633fbSnathanw if (tmperrorp)
18215f633fbSnathanw _rtld_error("%s", tmperror);
18315f633fbSnathanw else
184d9007319Sskrll (void)dlerror();
18515f633fbSnathanw return obj;
18615f633fbSnathanw
187f1184d19Smycroft found:
188f1d73a2cSskrll obj = _rtld_load_object(pathname, flags);
189f1d73a2cSskrll if (obj == OBJ_ERR)
190f1d73a2cSskrll return NULL;
191f1d73a2cSskrll
192f1d73a2cSskrll return obj;
19341fe218bScgd }
194f1d73a2cSskrll
195