Bug 272706 - procstat(1): procstat vm in jails shows host paths of binaries and shared libraries from outside prison
Summary: procstat(1): procstat vm in jails shows host paths of binaries and shared lib...
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 13.2-STABLE
Hardware: Any Any
: --- Affects Many People
Assignee: freebsd-jail (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-07-25 01:47 UTC by Elizabeth Myers
Modified: 2023-09-06 18:58 UTC (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Elizabeth Myers 2023-07-25 01:47:30 UTC
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
Comment 1 crest 2023-07-25 08:27:03 UTC
What is the jail's enforce_statfs setting?
Comment 2 Elizabeth Myers 2023-07-25 09:27:52 UTC
(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.
Comment 3 Andrew "RhodiumToad" Gierth 2023-07-25 11:19:41 UTC
(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?
Comment 4 Andrew "RhodiumToad" Gierth 2023-07-25 15:08:02 UTC
(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).
Comment 5 Andrew "RhodiumToad" Gierth 2023-07-25 17:36:25 UTC
(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.
Comment 6 Elizabeth Myers 2023-07-25 21:31:19 UTC
(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! :)