Rationale
glibc's _dl_get_origin() calls readlink("/proc/self/exe") during startup to discover library search paths relative to the executable. kbox_is_proc_escape_path() correctly identifies /proc/self/exe as an escape path, but forward_readlinkat() still routes the syscall to LKL instead of CONTINUE to the host kernel. LKL's /proc/self/exe has no knowledge of the injected guest binary, so the readlink fails.
musl-static works because musl does not call readlink("/proc/self/exe") during startup. Dynamically-linked Alpine binaries work because their libraries are already on the LKL filesystem.
Proposed Changes
- In
forward_readlinkat(), check for magic /proc/*/ symlinks (exe, cwd, root) and CONTINUE to the host kernel instead of routing to LKL.
- The host kernel returns a memfd path (
/proc/self/fd/N), which is already part of the exec injection strategy (src/image.c). Verify glibc accepts this.
- Alternative: synthesize a readlink result pointing to the guest binary's original rootfs path (requires the supervisor to track the original exec path).
Considerations
- Narrow the CONTINUE scope to specific magic symlinks, not all escape paths generically, to avoid re-opening directory traversal
- Audit other
/proc/self/ symlinks for similar routing issues
/proc/self/fd/N is not foreign to the design -- already used in exec injection
- Needs a regression test -- no current coverage for this path
- Unblocks glibc-static compatibility, expanding the range of supported binaries
References
src/path.c : kbox_is_proc_escape_path() identifies /proc/self/exe; kbox_is_lkl_virtual_path() returns false for escape paths
src/seccomp-dispatch.c : forward_readlinkat() routes to LKL regardless
src/image.c : exec injection already uses /proc/self/fd/N
Rationale
glibc's
_dl_get_origin()callsreadlink("/proc/self/exe")during startup to discover library search paths relative to the executable.kbox_is_proc_escape_path()correctly identifies/proc/self/exeas an escape path, butforward_readlinkat()still routes the syscall to LKL instead of CONTINUE to the host kernel. LKL's/proc/self/exehas no knowledge of the injected guest binary, so the readlink fails.musl-static works because musl does not call
readlink("/proc/self/exe")during startup. Dynamically-linked Alpine binaries work because their libraries are already on the LKL filesystem.Proposed Changes
forward_readlinkat(), check for magic/proc/*/symlinks (exe,cwd,root) and CONTINUE to the host kernel instead of routing to LKL./proc/self/fd/N), which is already part of the exec injection strategy (src/image.c). Verify glibc accepts this.Considerations
/proc/self/symlinks for similar routing issues/proc/self/fd/Nis not foreign to the design -- already used in exec injectionReferences
src/path.c:kbox_is_proc_escape_path()identifies/proc/self/exe;kbox_is_lkl_virtual_path()returns false for escape pathssrc/seccomp-dispatch.c:forward_readlinkat()routes to LKL regardlesssrc/image.c: exec injection already uses/proc/self/fd/N