Re: how to restrict file access below some top directory

From: David Chisnall <theraven_at_FreeBSD.org>
Date: Thu, 10 Feb 2022 09:13:07 UTC
Hi,

> On 10 Feb 2022, at 08:25, Matthias Apitz <guru@unixarea.de> wrote:
> 
> I want restrict in a C- or Perl-written application the file access to
> only files below some top directory, say
> 
> 	/var/spool/dir/
> 
> and not allowing, for example, access to /var/spool/dir/../../../etc/passwd
> Ofc, this could be done easy with chroot(2), but this would require root
> permision. Any other ideas?

There are (at least?) four ways of doing this with FreeBSD:

You can use chroot.  This provides a simple redefinition of the root of the filesystem.  All dependencies (shared libraries and so on) must be below the new root.  You can use nullfs mounts to set up this hierarchy to include read-only views of existing things (such as /lib, /usr/lib).  Note that chroot doesn’t restrict anything other than the filesystem namespace.  SysV IPC, sockets, and so on are unrestricted.  Note that you must be root to enter a chroot, but root can fairly easily escape from the chroot, so you need to setuid after entering it.



You can use a jail:

https://docs.freebsd.org/en/books/handbook/jails/

This has the same set of requirements as a chroot (the process can’t access anything outside of the new root, so the new root must have all support files needed) but gives you a much more complete environment.  You can restrict access to the network and other IPC namespaces to the jail and you can also have multiple user accounts inside.  Root in a jail is not the same as root outside and (modulo kernel bugs), root in the jail can’t escape, so it’s safe to run things as root in the jail.



You can write a MAC policy that restricts access to the hierarchy: 

https://docs.freebsd.org/en/books/handbook/mac/

This has the advantage that it’s non-invasive and makes it possible to poke holes in the restriction for things like shared libraries but writing the policy can be complex.  The BSD Extended MAC policy provides firewall-like rules that let you constrain a user to a subset of the filesystem, which is probably the simplest way of writing this kind of policy.

https://www.freebsd.org/cgi/man.cgi?query=mac_bsdextended



You can use Capsicum:

https://www.freebsd.org/cgi/man.cgi?query=capsicum

This requires source-code modification.  Once you call `cap_enter`, you have no access to any global namespace (filesystem, IPC, network, and so on) but if you’ve opened /var/spool/dir then you can use `openat` to open files below that location in the filesystem namespace.  You can also apply fine-grained restrictions to file descriptors (for example, granting read-only access to certain directories or append-only access to certain files).  We’re using this in Verona with a lightweight RPC mechanism to invoke untrusted shared libraries and proxy any calls to access things in the global that they need (open, connect, bind) to the parent process, which can enforce policy.

David