procstat(1)'s vm subcommand in jails shows host paths of shared libraries and binaries from outside the prison (example below). I am selecting the kernel component, because I suspect this is an issue in the kernel, rather than the procstat vm command. I could be wrong, though. It is extremely unlikely that this can be used for a meaningful exploit, but is more of an aesthetic issue. It is worth noting only root in the jail can execute this subcommand. Things that do not help (tested on 13.2): – Disallowing kmem and /dev/io in the jail – Disallowing procfs in the jail – sysctl security.bsd.unprivileged_proc_debug=0 in the host Here is an example: root@z6a.info:/ # procstat vm 989 PID START END PRT RES PRES REF SHD FLAG TP PATH 989 0x20210af3000 0x20210af7000 r-- 4 10 22 2 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/usr/sbin/rtsold 989 0x20210af7000 0x20210afe000 r-x 7 10 22 2 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/usr/sbin/rtsold 989 0x20210afe000 0x20210aff000 rw- 1 0 5 0 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/usr/sbin/rtsold 989 0x20210aff000 0x20210b01000 rw- 2 0 1 0 C---- sw 989 0x20a11ab8000 0x20a31a98000 --- 0 0 0 0 ----- gd 989 0x20a31a98000 0x20a31ab8000 rw- 3 0 1 0 C--D- sw 989 0x20a32148000 0x20a32169000 rw- 7 0 1 0 C---- sw 989 0x20a3290c000 0x20a3290f000 r-- 3 6 32 12 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libcasper.so.1 989 0x20a3290f000 0x20a32912000 r-x 3 6 32 12 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libcasper.so.1 989 0x20a32912000 0x20a32913000 r-- 1 0 5 0 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libcasper.so.1 989 0x20a32913000 0x20a32914000 rw- 1 0 5 0 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libcasper.so.1 989 0x20a32914000 0x20a32915000 rw- 1 0 1 0 C---- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libcasper.so.1 989 0x20a3335c000 0x20a33364000 r-- 7 19 52 18 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libutil.so.9 989 0x20a33364000 0x20a3336f000 r-x 11 19 52 18 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libutil.so.9 989 0x20a3336f000 0x20a33370000 rw- 1 0 5 0 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libutil.so.9 989 0x20a33370000 0x20a33371000 rw- 1 0 1 0 C---- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libutil.so.9 989 0x20a33371000 0x20a33373000 rw- 0 0 0 0 ----- -- 989 0x20a33855000 0x20a33856000 r-- 1 2 24 4 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/casper/libcap_syslog.so.1 989 0x20a33856000 0x20a33858000 r-x 2 2 24 4 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/casper/libcap_syslog.so.1 989 0x20a33858000 0x20a33859000 rw- 1 0 5 0 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/casper/libcap_syslog.so.1 989 0x20a33859000 0x20a3385a000 rw- 1 0 1 0 C---- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/casper/libcap_syslog.so.1 989 0x20a34523000 0x20a345a8000 r-- 78 321 89 41 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libc.so.7 989 0x20a345a8000 0x20a346f3000 r-x 219 321 89 41 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libc.so.7 989 0x20a346f3000 0x20a346fc000 r-- 9 0 5 0 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libc.so.7 989 0x20a346fc000 0x20a346fd000 rw- 1 0 5 0 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libc.so.7 989 0x20a346fd000 0x20a34704000 rw- 7 0 1 0 C---- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libc.so.7 989 0x20a34704000 0x20a34926000 rw- 7 0 1 0 C---- sw 989 0x20a355cd000 0x20a355d7000 r-- 8 20 30 10 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libnv.so.0 989 0x20a355d7000 0x20a355e4000 r-x 12 20 30 10 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libnv.so.0 989 0x20a355e4000 0x20a355e5000 rw- 1 0 5 0 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libnv.so.0 989 0x20a355e5000 0x20a355e7000 rw- 2 0 1 0 C---- vn /usr/jails/basejail/base_amd64_amd64_13.2/lib/libnv.so.0 989 0x20a36200000 0x20a36400000 rw- 2 0 1 0 C---- sw 989 0x20a366f9000 0x20a368f9000 rw- 18 0 1 0 C---- sw 989 0x20a37800000 0x20a37c00000 rw- 1 1 1 0 C---- sw 989 0x20a38947000 0x20a38948000 rw- 0 0 1 0 ----- sw 989 0x31ae14de4000 0x31ae14deb000 r-- 7 29 76 28 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/libexec/ld-elf.so.1 989 0x31ae14deb000 0x31ae14e01000 r-x 22 29 76 28 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/libexec/ld-elf.so.1 989 0x31ae14e01000 0x31ae14e02000 r-- 1 0 5 0 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/libexec/ld-elf.so.1 989 0x31ae14e02000 0x31ae14e03000 rw- 1 0 5 0 CN--- vn /usr/jails/basejail/base_amd64_amd64_13.2/libexec/ld-elf.so.1 989 0x31ae14e03000 0x31ae14e04000 rw- 0 0 1 0 C---- sw 989 0x7fffffffe000 0x7ffffffff000 r-x 1 1 59 0 ----- ph
What is the jail's enforce_statfs setting?
(In reply to crest from comment #1) It was originally 1. I tested with multiple values. 0, 1, or 2 has no effect. The jail doesn't start above 2, which makes sense as I believe it can't mount devfs at that point.
(In reply to Elizabeth Myers from comment #2) Wait, are you saying that procstat executed from *outside* the jail shows the full paths (which is expected), or that procstat executed *inside* the jail shows the full paths (which I can't reproduce)? The code path at issue uses vn_fullpath which is sensitive to the root directory of the invoking process, i.e. procstat, not to that of the process being examined. If you're finding that procstat from *inside* the jail is showing the full path, can you show a complete session transcript including the jail creation and execution of the procstat command?
(In reply to Andrew "RhodiumToad" Gierth from comment #3) I think I figured this one out, it happens when nullmounts are involved, even if the jail's root directory is not itself the mountpoint of a nullmount. e.g. mkdir /some/dir mount -t nullfs /path/to/real/jail/tree /some/dir jail -c path=/some/dir/somejail at this point, executing procstat (or possibly other vn_fullpath clients) inside the jail returns paths based on /path/to/real/jail/tree/somejail (and not /some/dir/somejail).
(In reply to Andrew "RhodiumToad" Gierth from comment #4) I've confirmed my analysis this far: vn_fullpath is being called with vp pointing to a physical filesystem vnode (i.e. not the nullfs node on the upper layer, but the lower layer vnode backing it). Accordingly, since in general the lower vnode is somewhere outside the jail root, the traverse of parent dirs never hits the process root directory, so the full path is shown. Most other uses of vn_fullpath will be starting from the upper-level vnode (for example, because they just looked up a filename, or they have an open file, etc.), and in this case, the code seems to correctly traverse the upper layer and end at the process root dir. What I don't know is why the vm_object is apparently referencing the lower vnode rather than the upper one.
(In reply to Andrew "RhodiumToad" Gierth from comment #5) To reply to previous comments: Yes, this is *within* the jail, not *outside* the jail. As far as I know, no other procstat subcommand does this from within the jail. I am indeed using null mounts here. Thank you for your fast analysis! :)