[PATCH 0/3] elf: load the main program from AT_EXECFD

Christian Brauner brauner@kernel.org
Thu Jul 16 23:00:28 GMT 2026


On 2026-07-16 17:37:21+02:00, Florian Weimer wrote:
> * Christian Brauner:
> 
> >> What does /proc/self/exe look like for such processes?  Does GDB work?
> >
> > Right, I checked that.
> >
> > /proc/self/exe is ld.so. The kernel exec'd ld.so, so it names ld.so
> > whether the program arrived via AT_EXECFD, via --program-fd, or via a
> > plain "ld.so PROG" command line.
> 
> Yeah, and that causes problems with binaries that try to be relocatable.
> We don't have a very convenient way to get the correct path in those
> scenarios, so a lot of code uses /proc/self/exe instead.
> 
> I'm wondering if we can use the checkpoint-restore facilities (the
> restore parts) to fix this: load ld.so another time, transfer control to
> it, and instruct it to unmap the first copy and then invoke the
> necessary prctls to make the process look exactly like a directly
> invoked process.

At first I was very confused about this proposal but I think I
understand what you are after now. Your point is that we shouldn't just
fix argv like in my proposal but actually even fix the exe file and
remap.

So I think doing this purely in userspace isn't doable. The restore
parts can fix everything except the exe link. PR_SET_MM_MAP requires
capabilities in the relevant user namespace for the exe file. That makes
it pretty useless for us. And dropping that capability requirement isn't
feasible, I think. LSMs and audit trust the exe link, so an uncapped
exe file would let any process masquerade as an arbitrary executable.

Everything else (the entire saved auxv, the start/end_code/data, brk and
stack markers) is validated but requires no capability at all. So an
unprivileged ld.so can already repair /proc/<pid>/auxv and the
stat/statm code accounting, but never /proc/self/exe.

Unmapping the first copy is also not really feasible. Even with
privilege making this work would be very ugly: The kernel's
replace_mm_exe_file() refuses with -EBUSY while any vma still maps the
old exe file. From my research, CRIU works around exactly this by
copying its restorer blob into an anonymous mapping before it unmaps the
old address space.

So I think the exe link should be fixed up at exec time.
begin_new_exec() sets mm->exe_file to bprm->file which after the
binfmt_misc handoff is the interpreter. But bprm->executable is the file
the kernel access-checked and kept open for AT_EXECFD. We have it right
there. This is the file that would_dump() uses for it's decision and
binfmt_misc's 'C' flag derive credentials from.

We simply need an extension to binfmt_misc that sets mm->exe_file to
bprm->executable. Then it is correct from the start and there's no
window and no privilege question and existing 'O'/'C' users (qemu-user
registrations) are unaffected. It then raises AT_FLAGS_PRESERVE_ARGV.

On the userspace side, ld.so now sees this AT_* flag and in response
issues one uncapped PR_SET_MM_MAP (that's available completely
unprivileged) to retarget AT_PHDR/AT_ENTRY/AT_BASE and drop the stale
AT_EXECFD from saved_auxv.

With both in place, attaching gdb to a dispatched process is fully
correct and /proc/self/exe-based self-location works. As a bonus the
program file gets the same exe_file write-denial a directly executed
binary has. Today it is ld.so that gets pinned and the running program's
file stays writable while its text is mapped.

After this, only uninteresting differences should be left. This would be
a follow-up series I'm happy to do. Does that sound reasonable?



More information about the Libc-alpha mailing list