From nobody Thu Apr 2 02:42:15 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4fmR2v4SvNz6WMWL for ; Thu, 02 Apr 2026 02:42:15 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fmR2v3dXcz3K30 for ; Thu, 02 Apr 2026 02:42:15 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1775097735; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=BXkF6PghBDPtK3Yb2sW8ygICaL6TaE+zCjZQ0WCYsK4=; b=VhakjLpSvDhFIyJfC6UHg9s5pRWbRSBKby7EHO+NsgHeICMWwS6gvg0D/jTzdL+it2ELw+ Vkc2tVyDZg2xzcDgs6HJWNKFoAWutcp2T7WwgE4PnVqnmk22n46hT+nVgbD/f3jtIC/l+6 4hDUn9DiedcYfaYfbVMB8y3nqTCc9aIBRf/ctjZPyMRvnifqsQAfkauWJude+pkOlMCm2C CFRIVV8NIr1WgjtZRdL2bTmqO8bYXP88wJZ7pBrv6XX4RwzdPFPzwZR0lCqKilofG4CxyL Rb7DiGtUfDRkazf17udThiMVDLrFSezXHQZx6FiHHhN42J4wFas7kuDJ/qJRGw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1775097735; a=rsa-sha256; cv=none; b=uc/pmv3fnExKwW2AoGK4K3JDt4NareLSeg1g7mnVd5/qAbZrmHnLuG1JI4LQQUta8UiVdO zj3zrz7xYCZoNTIrpg4AH88L4P1IfDxdryqXCS5YCncTI3x/djQy7oxnI1NmUu7i2tvVoK Z+kzKedy7srZ61eFzLH48/Z3kjATdr7817cJJUJis6lVO+f74fqQ7W8Q+/n5UrpsmW608P LOBTW6zEha3bj2d3Z7nSPVpHMekzfxqAdO8/q6i4tZ77FAcCqoIGCbKiwk0oiZrwzXQjGk KIkKFmP1Gq2M3ox+LD/PmwSbs0O6ULzCgxh7aWdnHHGUu3qgo4t+D2tZf0mMKw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1775097735; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=BXkF6PghBDPtK3Yb2sW8ygICaL6TaE+zCjZQ0WCYsK4=; b=qF8bGGlC+gvyD83/HK/gouczfBFLZ2kBV0gFEy9v8UVLYWVD4mjLPadcWNEYtFoP5Mg6YI q+N3D6KkOCXy7R5MQX47CR4OzuIqqYS+OTqvTboHsOf9Dk1xuMdMsTnsSSIKXOXVbRKTSK vVetxxdsS8jWmCMQTz4Isx2T76jK+B1RLNPEsOaZGOgJvb7p6rjdM8OxxUpo06J8sVGB0d kC5sOkzdxf3Eg/CGaspyKBHL0Sf6W2WRl8idsH/jW4mutKW0E4IVZ62EXs6PYm7EhDdhOr N2vyN7dp9nqikN086FjlNxS7WHvepj1SUeyepYkOMCTNJlU/ir5GInA87GNTRA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fmR2v3D2Xzk5Y for ; Thu, 02 Apr 2026 02:42:15 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 360cc by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Thu, 02 Apr 2026 02:42:15 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Konstantin Belousov Subject: git: ffbf3fecdeff - main - rtld: allow dlopen("#/") List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kib X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: ffbf3fecdeffa17c0745e7ed342989acb620d68e Auto-Submitted: auto-generated Date: Thu, 02 Apr 2026 02:42:15 +0000 Message-Id: <69cdd787.360cc.29cd7c78@gitrepo.freebsd.org> The branch main has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=ffbf3fecdeffa17c0745e7ed342989acb620d68e commit ffbf3fecdeffa17c0745e7ed342989acb620d68e Author: Konstantin Belousov AuthorDate: 2026-03-29 22:45:49 +0000 Commit: Konstantin Belousov CommitDate: 2026-04-02 02:41:55 +0000 rtld: allow dlopen("#/") 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.