realpath() leakage and unix socket collision in -o union mounts + jails
Date: Tue, 07 Oct 2025 18:49:27 UTC
Hi all,
I'm working on a network testing system that uses jails to emulate
virtual routers. The test target is == the host here, so I'm using
union mounts to create a "clone" of the host. That looks like this:
[root@freebsd15test]: /home/equinox/topotato # uname -a
FreeBSD r1 15.0-ALPHA4 FreeBSD 15.0-ALPHA4 stable/15-n280334-d2b670b27f37 GENERIC amd64
[root@freebsd15test]: /home/equinox/topotato # mount | grep ujbfygu3
/ on /tmp/topo_ujbfygu3/root (nullfs, local)
/tmp/topo_ujbfygu3/___ on /tmp/topo_ujbfygu3/root (nullfs, local, union)
/home on /tmp/topo_ujbfygu3/root/home (nullfs, local)
/tmp/topo_ujbfygu3/___home on /tmp/topo_ujbfygu3/root/home (nullfs, local, union)
/tmp on /tmp/topo_ujbfygu3/root/tmp (nullfs, local)
/dev on /tmp/topo_ujbfygu3/root/dev (nullfs, local)
(The last 2 mounts are intentionally not union. ALPHA5 VM images are
currently broken for unrelated reasons, hence me being on ALPHA4.)
With a jail then created in /tmp/topo_ujbfygu3/root, there are 2 issues.
First, realpath() leaks the full path outside the Jail:
access("/usr/local/share/yang",X_OK|R_OK) = 0 (0x0)
open("/usr/local/lib/libyang/types",O_RDONLY|O_DIRECTORY|O_CLOEXEC,011) ERR#2 'No such file or directory'
open("/usr/local/lib/libyang/extensions",O_RDONLY|O_DIRECTORY|O_CLOEXEC,05343024270) ERR#2 'No such file or directory'
__realpathat(AT_FDCWD,"/usr/local/share/yang","/tmp/topo_3vmk0s5z/root/usr/local/share/yang",1024,0) = 0 (0x0)
access("/tmp/topo_3vmk0s5z/root/usr/local/share/yang",X_OK|R_OK) ERR#2 'No such file or directory'
clock_gettime(0,{ 1759858363.616407491 }) = 0 (0x0)
writev(2,[{"2025/10/07 17:32:43 ",20},{"MGMTD: ",7},{"libyang: Unable to fully access search directory "/tmp/topo_3vmk0s5z/root/usr/local/share/yang" (No such file or directory).\n",125}],3) = 152 (0x98)
This can be reproduced invoking the realpath binary directly:
[root@freebsd15test]: /home/equinox/topotato # jexec 18 /bin/sh
# mount
/tmp/topo_ujbfygu3/___ on / (nullfs, local, union)
# realpath /etc
/tmp/topo_ujbfygu3/root/etc
# realpath /
/
(Interestingly, it does not happen for /.)
The second issue is quite a bit worse: AF_UNIX sockets "break through"
between jails. This can be reproduced with socat:
[root@freebsd15test]: /home/equinox/topotato # jls
JID IP Address Hostname Path
16 switch-ns /tmp/topo_u3crsgjg/root
17 r1 /tmp/topo_5x1s_smf/root
18 r2 /tmp/topo_ujbfygu3/root
[root@freebsd15test]: /home/equinox/topotato # jexec 18 /bin/sh
# mount
/tmp/topo_ujbfygu3/___ on / (nullfs, local, union)
# hostname
r2
# socat UNIX-LISTEN:/var/socktest STDIO
asdf
# #(above asdf is output from below)
[root@freebsd15test]: /home/equinox/frr # jexec 17 /bin/sh
# mount
/tmp/topo_5x1s_smf/___ on / (nullfs, local, union)
# hostname
r1
# echo asdf | socat UNIX-CONNECT:/var/socktest STDIO
Neither of these two issues happens with unionfs (which I've now fallen
back to using, but AIUI that's entirely unmaintained and unsupported...)
Could someone investigate these?
Cheers,
equi
P.S.: please stick me on Cc:, I used the "nomail" subscribe option.