Date: Thu, 02 Apr 2026 02:42:15 +0000
From: Konstantin Belousov <kib@FreeBSD.org>
To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject: git: ffbf3fecdeff - main - rtld: allow dlopen("#<number>/<path>")
Message-ID: <69cdd787.360cc.29cd7c78@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=ffbf3fecdeffa17c0745e7ed342989acb620d68e commit ffbf3fecdeffa17c0745e7ed342989acb620d68e Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2026-03-29 22:45:49 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2026-04-02 02:41:55 +0000 rtld: allow dlopen("#<number>/<path>") When a specially formatted path is passed to dlopen(), of the form #number/path and the number is the valid dirfd file descriptor listed in the LD_LIBRARY_FDS, interpret it as a relative path name against dirfd number. This complements the result returned from dladdr() for such objects in dli_fname. Reviewed by: markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D56152 --- lib/libc/gen/dlopen.3 | 14 ++++++++++++ libexec/rtld-elf/rtld.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/lib/libc/gen/dlopen.3 b/lib/libc/gen/dlopen.3 index 340545114114..2f10c17a4f53 100644 --- a/lib/libc/gen/dlopen.3 +++ b/lib/libc/gen/dlopen.3 @@ -164,6 +164,20 @@ Symbols from the loaded library are put before global symbols when resolving symbolic references originated from the library. .El .Pp +A special syntax for the +.Fa path +is supported, in the form of +.Dl #number/name . +The +.Ql number +should be a decimal number, which references an open file descriptor, +and which must be also listed in the environment variable +.Ev LD_LIBRARY_PATH_FDS . +In this case, the linker tries to load an object that can be opened by +.Ql openat(number, path, O_RDONLY) . +This feature is only available to trusted processes, i.e., +the activated image must be not set-uid or set-gid. +.Pp If .Fn dlopen fails, it returns a null pointer, and sets an error condition which may 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); @@ -3586,6 +3590,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.home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69cdd787.360cc.29cd7c78>
