[PATCH 0/3] elf: load the main program from AT_EXECFD
Andreas K. Huettel
dilfridge@gentoo.org
Wed Jul 15 12:05:38 GMT 2026
Am Mittwoch, 15. Juli 2026, 19:13:02 Japanische Normalzeit schrieb Christian Brauner:
> A Linux binfmt_misc handler can dispatch a program to a chosen dynamic
> linker. This is how you run a program under a different or newer ld.so.
> When the handler is registered with the 'O' (open binary) or 'C'
> (credentials) flag, the kernel keeps the executed file open across the
> dispatch. It hands the descriptor to the interpreter in the AT_EXECFD
> auxiliary vector entry. This is the SVR4 contract. AT_EXECFD is "the
> file descriptor of the program to load", the alternative to AT_PHDR.
> FreeBSD's rtld consumes it, and qemu-user has consumed it since 2013.
>
> The GNU dynamic linker never has. When such a handler dispatches to
> ld.so, the descriptor is ignored. It leaks into the new program. ld.so
> opens the executable again, this time by the path spliced into the
> argument vector.
No matter where this discussion goes, it's post-release material.
>
> Opening the file again by path is racy, and often it is not possible at
> all. The file ld.so opens need not be the file the kernel checked and
> executed. A binary with execute permission but no read permission can be
> run by execve(). It cannot be opened for reading by path, so ld.so
> rejects it with EACCES, even though the descriptor it was handed is
> readable. Sometimes there is no path to open. The program may be a
> sealed memfd.
>
> As Carlos said in [1] "I like where this is going because you can run
> ld.so to execute an isolated AT_EXECFD application." which is a good way
> to think about this.
>
> Also, nixos wants to use binfmt_misc to execute elf binaries and will be
> invoking the loader this way. I also have a use-case for this in
> systemd-homed in the future and I'm extending the abilities of
> binfmt_misc a bit. So I would really appreciate if we could support
> this in the glibc loader.
>
> This series makes ld.so load the main program from AT_EXECFD when ld.so
> is the program the kernel loaded. The object comes from the descriptor,
> not from a path opened a second time. The loaded file is exactly the one
> execve() checked, so there is no race. A binary with no read permission
> runs. A program with no accessible path runs. Applications see no
> difference. The argument vector they observe is the same as for a direct
> execution. No kernel changes are needed. The binfmt_misc 'O' and 'C'
> flags have been around for a long time. This works against current
> kernels.
>
> The series also adds the option "ld.so --program-fd N NAME". This is the
> explicit counterpart to AT_EXECFD, and FreeBSD's ld-elf.so.1 spells it
> -f. It lets a program run from an inherited descriptor, such as a sealed
> memfd, with no kernel dispatch at all.
>
> Tested on x86_64. tst-rtld-program-fd exercises the descriptor loading
> path on its own, with no kernel support needed. tst-rtld-execfd drives
> the whole path through a real binfmt_misc handler in a private user and
> mount namespace. That test needs Linux 6.7 or newer and reports
> UNSUPPORTED otherwise. It covers the case of a binary with no read
> permission.
>
> I've discussed this on mastodon in [2] with Carlos a little bit a couple
> of days ago.
>
> An LLM was used to get familiar with this particular part of the glibc
> codebase and for review of the implementation. It's been a while so I
> hope I still got the gist of contributions right.
>
> Link: https://mastodon.social/deck/@codonell@fosstodon.org/116918469134997346 [1]
> Link: https://mastodon.social/deck/@brauner/116913310306668229 [2]
> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
> ---
> Christian Brauner (3):
> elf: load the main program from AT_EXECFD when run as a binfmt interpreter
> elf: test AT_EXECFD consumption through a binfmt_misc 'O' handler
> elf: add ld.so --program-fd
>
> NEWS | 15 ++
> elf/Makefile | 4 +
> elf/dl-load.c | 50 +++++
> elf/dl-usage.c | 2 +
> elf/rtld.c | 166 ++++++++++++++-
> elf/tst-rtld-program-fd-prog.c | 28 +++
> elf/tst-rtld-program-fd.c | 126 +++++++++++
> sysdeps/generic/ldsodefs.h | 7 +
> sysdeps/unix/sysv/linux/Makefile | 5 +
> sysdeps/unix/sysv/linux/tst-rtld-execfd-prog.c | 43 ++++
> sysdeps/unix/sysv/linux/tst-rtld-execfd.c | 282 +++++++++++++++++++++++++
> 11 files changed, 719 insertions(+), 9 deletions(-)
> ---
> base-commit: 5396eb704531d9ede0388bffcc21b93bb661d404
> change-id: 20260715-work-glibc-binfmt_misc-939266ac4824
>
>
--
PD Dr. Andreas K. Hüttel
dilfridge@gentoo.org
Gentoo Linux developer
(council, comrel, toolchain, base-system, perl, libreoffice)
https://wiki.gentoo.org/wiki/User:Dilfridge
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 870 bytes
Desc: This is a digitally signed message part.
URL: <https://sourceware.org/pipermail/libc-alpha/attachments/20260715/65ee27f3/attachment.sig>
More information about the Libc-alpha
mailing list