diff options
| author | Konstantin Belousov <kib@FreeBSD.org> | 2026-03-29 22:45:49 +0000 |
|---|---|---|
| committer | Konstantin Belousov <kib@FreeBSD.org> | 2026-04-02 02:41:55 +0000 |
| commit | ffbf3fecdeffa17c0745e7ed342989acb620d68e (patch) | |
| tree | 8ddd860ba8f220a0a6b1849202f5842268547480 /libexec | |
| parent | 51db69c14fb1a1c2dc807695e6f564d498d33d5a (diff) | |
Diffstat (limited to 'libexec')
| -rw-r--r-- | libexec/rtld-elf/rtld.c | 57 |
1 files changed, 54 insertions, 3 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 1cf0d3e9ba28..e3f5aa5be9b4 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -178,6 +178,7 @@ static int symlook_obj1_sysv(SymLook *, const Obj_Entry *); static int symlook_obj1_gnu(SymLook *, const Obj_Entry *); static void *tls_get_addr_slow(struct tcb *, int, size_t, bool) __noinline; static void trace_loaded_objects(Obj_Entry *, bool); +static int try_fds_open(const char *name, const char *path); static void unlink_object(Obj_Entry *); static void unload_object(Obj_Entry *, RtldLockState *lockstate); static void unref_dag(Obj_Entry *); @@ -2875,9 +2876,12 @@ load_object(const char *name, int fd_u, const Obj_Entry *refobj, int flags) * using stat(). */ if ((fd = open(path, O_RDONLY | O_CLOEXEC | O_VERIFY)) == -1) { - _rtld_error("Cannot open \"%s\"", path); - free(path); - return (NULL); + fd = try_fds_open(path, ld_library_dirs); + if (fd == -1) { + _rtld_error("Cannot open \"%s\"", path); + free(path); + return (NULL); + } } } else { fd = fcntl(fd_u, F_DUPFD_CLOEXEC, 0); @@ -3587,6 +3591,53 @@ rtld_nop_exit(void) } /* + * Parse string of the format '#number/name", where number must be a + * decimal number of the opened file descriptor listed in + * LD_LIBRARY_PATH_FDS. If successful, tries to open dso name under + * dirfd number and returns resulting fd. + * On any error, returns -1. + */ +static int +try_fds_open(const char *name, const char *path) +{ + const char *n; + char *envcopy, *fdstr, *last_token, *ncopy; + size_t len; + int fd, dirfd, dirfd_path; + + if (!trust || name[0] != '#' || path == NULL) + return (-1); + + name++; + n = strchr(name, '/'); + if (n == NULL) + return (-1); + len = n - name; + ncopy = xmalloc(len + 1); + memcpy(ncopy, name, len); + ncopy[len] = '\0'; + dirfd = parse_integer(ncopy); + free(ncopy); + if (dirfd == -1) + return (-1); + + envcopy = xstrdup(path); + dirfd_path = -1; + for (fdstr = strtok_r(envcopy, ":", &last_token); fdstr != NULL; + fdstr = strtok_r(NULL, ":", &last_token)) { + dirfd_path = parse_integer(fdstr); + if (dirfd_path == dirfd) + break; + } + free(envcopy); + if (dirfd_path != dirfd) + return (-1); + + fd = __sys_openat(dirfd, n + 1, O_RDONLY | O_CLOEXEC | O_VERIFY); + return (fd); +} + +/* * Iterate over a search path, translate each element, and invoke the * callback on the result. */ |
