[Bug 297426] linuxulator: linprocfs /proc/self/exe host path breaks execve under Linux ABI

From: <bugzilla-noreply_at_freebsd.org>
Date: Tue, 11 Aug 2026 02:42:30 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=297426

--- Comment #4 from Devin Teske <dteske@FreeBSD.org> ---
(In reply to Alex S from comment #3)

Thanks for taking the time to test.  The difference between our systems
will be what is mounted at the native /proc -- could you post your
`mount | grep proc`?

On a default Linuxulator setup -- linux_enable=YES, where rc.d/linux
mounts linprocfs at /compat/linux/proc and nothing is mounted at the
native /proc -- the same sequence fails:

$ mount | grep proc
linprocfs on /compat/linux/proc (linprocfs, local)

$ /compat/linux/usr/bin/python3.9 -c "
import os
print('readlink:', os.readlink('/proc/self/exe'))
try:
    print('stat:', os.stat('/proc/self/exe'))
except OSError as e:
    print('stat: FAIL --', e)
try:
    os.execv('/proc/self/exe', ['python3', '-c', 'print(\"execv OK\")'])
except OSError as e:
    print('execv: FAIL --', e)
"
readlink: /compat/linux/usr/bin/python3.9
stat: FAIL -- [Errno 2] No such file or directory: '/proc/self/exe'
execv: FAIL -- [Errno 2] No such file or directory

Mechanism: linprocfs fills the exe symlink with the host path
(/compat/linux/usr/bin/python3.9).  The Linux ABI resolves absolute
paths from compat.linux.emul_path, so following that target looks up
/compat/linux/compat/linux/usr/bin/python3.9 and gets ENOENT.  If
procfs(5) is mounted at the native /proc (it provides both "self" and
"exe" nodes), namei's restart into the native namespace resolves
/proc/self/exe there and stat/execve succeed -- which would explain
the results on your system.

Note that even in your successful run, readlink returned
'/compat/linux/usr/bin/python3.9'.  On Linux this returns the path in
the process's own namespace ('/usr/bin/python3.9'); the emulator
prefix is host configuration (a FreeBSD sysctl) that consumers
comparing or deriving paths from the result should never see.  The
proposed patch strips that prefix.

I'll attach a small litmus program that exercises
readlink/stat/access/execve for both cases: a binary under the
emulator root, and one outside it (e.g. Linux binaries that ports
install under ${PREFIX}, such as www/linux-brave, which is how this
was found).

-- 
You are receiving this mail because:
You are the assignee for the bug.