xref: /netbsd-src/libexec/ld.elf_so/search.c (revision dca0c0f499b8093e902298b3ec3b106f85e999d8)
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