Ejemplo n.º 1
0
/*
 * char *dl_realpath(const char *path, char resolved[PATH_MAX]);
 *
 * Find the real name of path, by removing all ".", ".." and symlink
 * components.  Returns (resolved) on success, or (NULL) on failure,
 * in which case the path which caused trouble is left in (resolved).
 */
char *
_dl_realpath(const char *path, char *resolved)
{
	struct stat sb;
	const char *p, *s;
	char *q;
	size_t left_len, resolved_len;
	unsigned symlinks;
	int slen, mem_allocated, ret;
	char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];

	if (path[0] == '\0') {
		return (NULL);
	}

	if (resolved == NULL) {
		resolved = _dl_malloc(PATH_MAX);
		if (resolved == NULL)
			return (NULL);
		mem_allocated = 1;
	} else
		mem_allocated = 0;

	symlinks = 0;
	if (path[0] == '/') {
		resolved[0] = '/';
		resolved[1] = '\0';
		if (path[1] == '\0')
			return (resolved);
		resolved_len = 1;
		left_len = _dl_strlcpy(left, path + 1, sizeof(left));
	} else {
		if (_dl_getcwd(resolved, PATH_MAX) <= 0) {
			if (mem_allocated)
				_dl_free(resolved);
			else
				_dl_strlcpy(resolved, ".", PATH_MAX);
			return (NULL);
		}
		resolved_len = _dl_strlen(resolved);
		left_len = _dl_strlcpy(left, path, sizeof(left));
	}
	if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
		goto err;
	}

	/*
	 * Iterate over path components in `left'.
	 */
	while (left_len != 0) {
		/*
		 * Extract the next path component and adjust `left'
		 * and its length.
		 */
		p = _dl_strchr(left, '/');
		s = p ? p : left + left_len;
		if (s - left >= sizeof(next_token)) {
			goto err;
		}
		_dl_bcopy(left, next_token, s - left);
		next_token[s - left] = '\0';
		left_len -= s - left;
		if (p != NULL)
			_dl_bcopy(s + 1, left, left_len + 1);
		if (resolved[resolved_len - 1] != '/') {
			if (resolved_len + 1 >= PATH_MAX) {
				goto err;
			}
			resolved[resolved_len++] = '/';
			resolved[resolved_len] = '\0';
		}
		if (next_token[0] == '\0')
			continue;
		else if (_dl_strcmp(next_token, ".") == 0)
			continue;
		else if (_dl_strcmp(next_token, "..") == 0) {
			/*
			 * Strip the last path component except when we have
			 * single "/"
			 */
			if (resolved_len > 1) {
				resolved[resolved_len - 1] = '\0';
				q = _dl_strrchr(resolved, '/') + 1;
				*q = '\0';
				resolved_len = q - resolved;
			}
			continue;
		}

		/*
		 * Append the next path component and lstat() it. If
		 * lstat() fails we still can return successfully if
		 * there are no more path components left.
		 */
		resolved_len = _dl_strlcat(resolved, next_token, PATH_MAX);
		if (resolved_len >= PATH_MAX) {
			goto err;
		}
		if ((ret = _dl_lstat(resolved, &sb)) != 0) {
			if (ret == ENOENT && p == NULL) {
				return (resolved);
			}
			goto err;
		}
		if (S_ISLNK(sb.st_mode)) {
			if (symlinks++ > SYMLOOP_MAX) {
				goto err;
			}
			slen = _dl_readlink(resolved, symlink, sizeof(symlink) - 1);
			if (slen < 0)
				goto err;
			symlink[slen] = '\0';
			if (symlink[0] == '/') {
				resolved[1] = 0;
				resolved_len = 1;
			} else if (resolved_len > 1) {
				/* Strip the last path component. */
				resolved[resolved_len - 1] = '\0';
				q = _dl_strrchr(resolved, '/') + 1;
				*q = '\0';
				resolved_len = q - resolved;
			}

			/*
			 * If there are any path components left, then
			 * append them to symlink. The result is placed
			 * in `left'.
			 */
			if (p != NULL) {
				if (symlink[slen - 1] != '/') {
					if (slen + 1 >= sizeof(symlink)) {
						goto err;
					}
					symlink[slen] = '/';
					symlink[slen + 1] = 0;
				}
				left_len = _dl_strlcat(symlink, left, sizeof(symlink));
				if (left_len >= sizeof(left)) {
					goto err;
				}
			}
			left_len = _dl_strlcpy(left, symlink, sizeof(left));
		}
	}

	/*
	 * Remove trailing slash except when the resolved pathname
	 * is a single "/".
	 */
	if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
		resolved[resolved_len - 1] = '\0';
	return (resolved);

err:
	if (mem_allocated)
		_dl_free(resolved);
	return (NULL);
}
Ejemplo n.º 2
0
struct elf_resolve *_dl_load_shared_library(unsigned int rflags, struct dyn_elf **rpnt,
	struct elf_resolve *tpnt, char *full_libname, int attribute_unused trace_loaded_objects)
{
	char *pnt;
	struct elf_resolve *tpnt1;
	char *libname;

	_dl_internal_error_number = 0;
	libname = full_libname;

	/* quick hack to ensure mylibname buffer doesn't overflow.  don't
	   allow full_libname or any directory to be longer than 1024. */
	if (_dl_strlen(full_libname) > 1024)
		goto goof;

	/* Skip over any initial initial './' and '/' stuff to
	 * get the short form libname with no path garbage */
	pnt = _dl_strrchr(libname, '/');
	if (pnt) {
		libname = pnt + 1;
	}

	_dl_if_debug_dprint("\tfind library='%s'; searching\n", libname);
	/* If the filename has any '/', try it straight and leave it at that.
	   For IBCS2 compatibility under linux, we substitute the string
	   /usr/i486-sysv4/lib for /usr/lib in library names. */

	if (libname != full_libname) {
		_dl_if_debug_dprint("\ttrying file='%s'\n", full_libname);
		tpnt1 = _dl_load_elf_shared_library(rflags, rpnt, full_libname);
		if (tpnt1) {
			return tpnt1;
		}
	}

	/*
	 * The ABI specifies that RPATH is searched before LD_LIBRARY_PATH or
	 * the default path of /usr/lib.  Check in rpath directories.
	 */
#ifdef __LDSO_RUNPATH__
	pnt = (tpnt ? (char *) tpnt->dynamic_info[DT_RPATH] : NULL);
	if (pnt) {
		pnt += (unsigned long) tpnt->dynamic_info[DT_STRTAB];
		_dl_if_debug_dprint("\tsearching RPATH='%s'\n", pnt);
		if ((tpnt1 = search_for_named_library(libname, rflags, pnt, rpnt,
						      tpnt->libname)) != NULL)
			return tpnt1;

	}
#endif

#ifdef __LDSO_LD_LIBRARY_PATH__
	/* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */
	if (_dl_library_path) {
		_dl_if_debug_dprint("\tsearching LD_LIBRARY_PATH='%s'\n", _dl_library_path);
		if ((tpnt1 = search_for_named_library(libname, rflags, _dl_library_path, rpnt, NULL)) != NULL)
		{
			return tpnt1;
		}
	}
#endif
	/*
	 * The ABI specifies that RUNPATH is searched after LD_LIBRARY_PATH.
	 */
#ifdef __LDSO_RUNPATH__
	pnt = (tpnt ? (char *)tpnt->dynamic_info[DT_RUNPATH] : NULL);
	if (pnt) {
		pnt += (unsigned long) tpnt->dynamic_info[DT_STRTAB];
		_dl_if_debug_dprint("\tsearching RUNPATH='%s'\n", pnt);
		if ((tpnt1 = search_for_named_library(libname, rflags, pnt, rpnt, NULL)) != NULL)
			return tpnt1;
	}
#ifdef __LDSO_RUNPATH_OF_EXECUTABLE__
        /*
         * Try the DT_RPATH of the executable itself.
         */
        pnt = (char *) _dl_loaded_modules->dynamic_info[DT_RPATH];
        if (pnt) {
                pnt += (unsigned long) _dl_loaded_modules->dynamic_info[DT_STRTAB];
                _dl_if_debug_dprint("\tsearching exe's RPATH='%s'\n", pnt);
                if ((tpnt1 = search_for_named_library(libname, rflags, pnt, rpnt, NULL)) != NULL)
                        return tpnt1;
        }
#endif
#endif

	/*
	 * Where should the cache be searched?  There is no such concept in the
	 * ABI, so we have some flexibility here.  For now, search it before
	 * the hard coded paths that follow (i.e before /lib and /usr/lib).
	 */
#ifdef __LDSO_CACHE_SUPPORT__
	if (_dl_cache_addr != NULL && _dl_cache_addr != MAP_FAILED) {
		int i;
		header_t *header = (header_t *) _dl_cache_addr;
		libentry_t *libent = (libentry_t *) & header[1];
		char *strs = (char *) &libent[header->nlibs];

		_dl_if_debug_dprint("\tsearching cache='%s'\n", LDSO_CACHE);
		for (i = 0; i < header->nlibs; i++) {
			if ((libent[i].flags == LIB_ELF
			     || libent[i].flags == LIB_ELF_LIBC0
			     ||	libent[i].flags == LIB_ELF_LIBC5)
			 && _dl_strcmp(libname, strs + libent[i].sooffset) == 0
			 && (tpnt1 = _dl_load_elf_shared_library(rflags, rpnt, strs + libent[i].liboffset))
			) {
				return tpnt1;
			}
		}
	}
#endif

#ifdef LDSO_MULTILIB_DIR
	/* If multilib directory is selected, search it before falling back to
	   standard lib directories. */
	_dl_if_debug_dprint("\tsearching multilib lib path list\n");
	tpnt1 = search_for_named_library(libname, rflags,
					UCLIBC_RUNTIME_PREFIX LDSO_MULTILIB_DIR ":"
					UCLIBC_RUNTIME_PREFIX "usr/" LDSO_MULTILIB_DIR,
					rpnt, NULL);
	if (tpnt1 != NULL)
		return tpnt1;
#endif

#if defined SHARED && defined __LDSO_SEARCH_INTERP_PATH__
	/* Look for libraries wherever the shared library loader
	 * was installed */
	_dl_if_debug_dprint("\tsearching ldso dir='%s'\n", _dl_ldsopath);
	tpnt1 = search_for_named_library(libname, rflags, _dl_ldsopath, rpnt, NULL);
	if (tpnt1 != NULL)
		return tpnt1;
#endif

	/* Lastly, search the standard list of paths for the library.
	   This list must exactly match the list in uClibc/ldso/util/ldd.c */
	_dl_if_debug_dprint("\tsearching full lib path list\n");
	tpnt1 = search_for_named_library(libname, rflags,
					UCLIBC_RUNTIME_PREFIX "lib:"
					UCLIBC_RUNTIME_PREFIX "usr/lib"
#ifndef __LDSO_CACHE_SUPPORT__
					":" UCLIBC_RUNTIME_PREFIX "usr/X11R6/lib"
#endif
					, rpnt, NULL);
	if (tpnt1 != NULL)
		return tpnt1;

#ifdef __LDSO_RUNPATH_OF_EXECUTABLE__
	/* Very last resort, try the executable's DT_RUNPATH and DT_RPATH */
	/* http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#shobj_dependencies
	 * The set of directories specified by a given DT_RUNPATH entry is
	 * used to find only the immediate dependencies of the executable or
	 * shared object containing the DT_RUNPATH entry. That is, it is
	 * used only for those dependencies contained in the DT_NEEDED
	 * entries of the dynamic structure containing the DT_RUNPATH entry,
	 * itself. One object's DT_RUNPATH entry does not affect the search
	 * for any other object's dependencies.
	 *
	 * glibc (around 2.19) violates this and the usual suspects are
	 * abusing this bug^Wrelaxed, user-friendly behaviour.
	 */

	pnt = (char *) _dl_loaded_modules->dynamic_info[DT_RUNPATH];
	if (pnt) {
		pnt += (unsigned long) _dl_loaded_modules->dynamic_info[DT_STRTAB];
		_dl_if_debug_dprint("\tsearching exe's RUNPATH='%s'\n", pnt);
		if ((tpnt1 = search_for_named_library(libname, rflags, pnt, rpnt, NULL)) != NULL)
			return tpnt1;
	}
	pnt = (char *) _dl_loaded_modules->dynamic_info[DT_RPATH];
	if (pnt) {
		pnt += (unsigned long) _dl_loaded_modules->dynamic_info[DT_STRTAB];
		_dl_if_debug_dprint("\tsearching exe's RPATH='%s'\n", pnt);
		if ((tpnt1 = search_for_named_library(libname, rflags, pnt, rpnt, NULL)) != NULL)
			return tpnt1;
	}
#endif


goof:
	/* Well, we shot our wad on that one.  All we can do now is punt */
	if (_dl_internal_error_number)
		_dl_error_number = _dl_internal_error_number;
	else
		_dl_error_number = LD_ERROR_NOFILE;
	_dl_if_debug_dprint("Bummer: could not find '%s'!\n", libname);
	return NULL;
}
Ejemplo n.º 3
0
struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt,
	struct elf_resolve *tpnt, char *full_libname, int attribute_unused trace_loaded_objects)
{
	char *pnt;
	struct elf_resolve *tpnt1;
	char *libname;

	_dl_internal_error_number = 0;
	libname = full_libname;

	/* quick hack to ensure mylibname buffer doesn't overflow.  don't
	   allow full_libname or any directory to be longer than 1024. */
	if (_dl_strlen(full_libname) > 1024)
		goto goof;

	/* Skip over any initial initial './' and '/' stuff to
	 * get the short form libname with no path garbage */
	pnt = _dl_strrchr(libname, '/');
	if (pnt) {
		libname = pnt + 1;
	}

	_dl_if_debug_dprint("\tfind library='%s'; searching\n", libname);
	/* If the filename has any '/', try it straight and leave it at that.
	   For IBCS2 compatibility under linux, we substitute the string
	   /usr/i486-sysv4/lib for /usr/lib in library names. */

	if (libname != full_libname) {
		_dl_if_debug_dprint("\ttrying file='%s'\n", full_libname);
		tpnt1 = _dl_load_elf_shared_library(secure, rpnt, full_libname);
		if (tpnt1) {
			return tpnt1;
		}
	}

	/*
	 * The ABI specifies that RPATH is searched before LD_LIBRARY_PATH or
	 * the default path of /usr/lib.  Check in rpath directories.
	 */
#ifdef __LDSO_RUNPATH__
	pnt = (tpnt ? (char *) tpnt->dynamic_info[DT_RPATH] : NULL);
	if (pnt) {
		pnt += (unsigned long) tpnt->dynamic_info[DT_STRTAB];
		_dl_if_debug_dprint("\tsearching RPATH='%s'\n", pnt);
		if ((tpnt1 = search_for_named_library(libname, secure, pnt, rpnt)) != NULL)
			return tpnt1;
	}
#endif

	/* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */
	if (_dl_library_path) {
		_dl_if_debug_dprint("\tsearching LD_LIBRARY_PATH='%s'\n", _dl_library_path);
		if ((tpnt1 = search_for_named_library(libname, secure, _dl_library_path, rpnt)) != NULL)
		{
			return tpnt1;
		}
	}

	/*
	 * The ABI specifies that RUNPATH is searched after LD_LIBRARY_PATH.
	 */
#ifdef __LDSO_RUNPATH__
	pnt = (tpnt ? (char *)tpnt->dynamic_info[DT_RUNPATH] : NULL);
	if (pnt) {
		pnt += (unsigned long) tpnt->dynamic_info[DT_STRTAB];
		_dl_if_debug_dprint("\tsearching RUNPATH='%s'\n", pnt);
		if ((tpnt1 = search_for_named_library(libname, secure, pnt, rpnt)) != NULL)
			return tpnt1;
	}
#endif

	/*
	 * Where should the cache be searched?  There is no such concept in the
	 * ABI, so we have some flexibility here.  For now, search it before
	 * the hard coded paths that follow (i.e before /lib and /usr/lib).
	 */
#ifdef __LDSO_CACHE_SUPPORT__
	if (_dl_cache_addr != NULL && _dl_cache_addr != MAP_FAILED) {
		int i;
		header_t *header = (header_t *) _dl_cache_addr;
		libentry_t *libent = (libentry_t *) & header[1];
		char *strs = (char *) &libent[header->nlibs];

		_dl_if_debug_dprint("\tsearching cache='%s'\n", LDSO_CACHE);
		for (i = 0; i < header->nlibs; i++) {
			if ((libent[i].flags == LIB_ELF
			     || libent[i].flags == LIB_ELF_LIBC0
			     ||	libent[i].flags == LIB_ELF_LIBC5)
			 && _dl_strcmp(libname, strs + libent[i].sooffset) == 0
			 && (tpnt1 = _dl_load_elf_shared_library(secure, rpnt, strs + libent[i].liboffset))
			) {
				return tpnt1;
			}
		}
	}
#endif

	/* Look for libraries wherever the shared library loader
	 * was installed */
	_dl_if_debug_dprint("\tsearching ldso dir='%s'\n", _dl_ldsopath);
	tpnt1 = search_for_named_library(libname, secure, _dl_ldsopath, rpnt);
	if (tpnt1 != NULL)
		return tpnt1;

	/* Lastly, search the standard list of paths for the library.
	   This list must exactly match the list in uClibc/ldso/util/ldd.c */
	_dl_if_debug_dprint("\tsearching full lib path list\n");
	tpnt1 = search_for_named_library(libname, secure,
					UCLIBC_RUNTIME_PREFIX "lib:"
					UCLIBC_RUNTIME_PREFIX "usr/lib"
#ifndef __LDSO_CACHE_SUPPORT__
					":" UCLIBC_RUNTIME_PREFIX "usr/X11R6/lib"
#endif
					, rpnt);
	if (tpnt1 != NULL)
		return tpnt1;

goof:
	/* Well, we shot our wad on that one.  All we can do now is punt */
	if (_dl_internal_error_number)
		_dl_error_number = _dl_internal_error_number;
	else
		_dl_error_number = LD_ERROR_NOFILE;
	_dl_if_debug_dprint("Bummer: could not find '%s'!\n", libname);
	return NULL;
}