[apparmor] Handling chroot, pivotroot, and file system namespaces

John Johansen john.johansen at canonical.com
Sat Dec 3 01:31:17 UTC 2011


Currently AppArmor policy doesn't handled chroot or pivotroot well. These
two operations cause two separate problems: disconnected paths, and current
policy doesn't provide a means of dealing with the changed meaning of root.

Lets look at an example of the problem.

You have an fs setup with the standard layout /etc/, /usr, etc. and setup
a chroot image in /var/chroot/

Now say you are in task that is confined by a profile, its file accesses
are relative to the original root, ie. /etc/ , /var/chroot/, ..., and
so are the file access rules (/etc/* r, /var/chroot/** rw, ).

Now the task does a chroot, so its root has switched and what was
/var/chroot/etc is now /etc

The question is how should the current profiles rules be applied?
should /etc/** r, be applied to what was /etc or should it apply to the
new /etc/, what was /var/chroot/etc before.

There are a few potential solutions
1. Just live with the aliasing problems this cause, and write really
   broad policy that covers both what is desired pre and post chroot.

   Basically its not an acceptable solution

2. Always resolve path lookups to the real fs root.  That is, even
   post chroot AppArmor sees paths relative to the original root.
   This fixes the aliasing of rules problem but still requires the
   profile to contain rules to cover both pre and post chroot
   accesses.

   This is what the namespace_relative flag does

   The mixing of pre and post chroot policy mostly works but can
   require broader access be granted than what may be desired.
   Eg. Prechroot may have mount permissions that you don't want to
   allow post chroot.

3. change the profile so that different profiles are in use both
   pre and post chroot.  This solution can fix both the aliasing
   and the broad policy authoring problems from 1 and 2.
   Further it can work whether paths are relative to the chroot
   or as in 2 relative to the fs root.

   There are 2 possible implementations of 3.
   3.1 Have the task change its profile using change profile.  This
       could work now but requires every task doing chroot, etc.  To
       manually make the appropriate change, which means modifying these
       tasks.

   3.2 Add a rule to apparmor policy that allows defining this change
       either something like

          chroot /foo -> /bar,

        or possibly a chroot block

        profile foo {
          # prechroot rules

          chroot {
            # post chroot rules

          }
        }

Now that we have thrown out a few possible solutions, lets consider some use
cases.

A. User wants to use a chroot as an application jail, and wants to secure
   the jail with a profile.  In this situation the environment outside of
   the chroot is placing restrictions on the chroot environment.  Neither
   1 nor 2 is sufficient as the pre and post chroot evironments share rules.
   While #2 takes care of filesystem path aliasing it does not solve
   issues with shared capabilities, etc.

B. The user is using a chroot to do some system testing, ie. its being used
   like a VM, and the user wants the VM to have its own profiles.  To do
   this a new profile namespace is setup, and that will be used by the
   chroot to load its own profiles.

   In this case #2 does not work for the profiles loaded in the chroot
   environment, as to them the chroot is the real root.  It is conceivable
   that #2 could be made to work if we tied the "root" to the apparmor
   profile namespace, so that we could detect when to resolve to the
   fs root.

C. The user wants to do both A and B
   Hey one can dream :)  So this is actually one of the cases for profile
   stacking and is actually one of the things we have been working towards.

   In this case you need to be able to deal with the restrictions imposed
   in both A and B

Are there other use cases of chroots that can't be fit into these broad
use cases?

So with chroots out of the way, what of pivot root, and filesystem namespaces.
Well they are basically the same.  They are just newer and more flexible ways
of changing what the filesystem and other parts of the system appear.

However there are a couple of key differences, the kernel tracks the chroot
base and the fs root, allowing us to do something like solution #2 easily.
This is not the case with fs namespaces, and pivot root.  We would have to
come up with a way to track this information, and that may not be acceptable.

Looking at it, I think #3 is the preferred solution.  It keeps the simplicity
of profile paths being what is expected within a chroot, fs namespace, etc.
and also allows for the flexibility needed for both pre and post chroot/pivot
root/namespace change mediation.  However #3 can't directly deal with the
disconnected paths problem.


The second problem of disconnected paths is many ways harder and is something
we have always had problems with, and its not just at chroot.  Basically in
the context of chroot/fs namespaces some files opened before a change to the
namespace layout (chroot, ...) may still need to be accessed after the changed,
but there is no valid path to open them anymore, so the path lookup results in
a disconnected path, that is it can't be resolved to the current root (no
leading /).

If a revalidation is required, which changing the profile as proposed in
#3 will cause, then mediation of the file by path is no longer possible.
Solution #2 deals with this for a chroot environment, by changing the
mediation root, this is bad for use case B but at least avoids having
files that can not be mediated.  Moving beyond chroots to generic filesystem
namespaces we loose this ability, not to mention the case of lazily unmounted
filesytems etc, so it is better to devise a solution that works everywhere

To fix this I think we have two solutions.  File label mediation, and fd
delegation.  We already do both of these to a limited degree. File's get
implicitly labeled when first opened and then we don't need to revalidate if
the task's profile is the same as the implicit file label.  Delegation is
currently used for fd's opened by the unconfined process.

The file label mediation would basically be the current proposed ipc mediation

  profile=A rw,

allows read and write access to tasks labeled with profile A, we could use
this to access the implicitly labeled files as well.  This could be limited
to just files using

  file profile=A rw,



Delegation is I think a little farther out and would work by defining what
files the parent could delegate to the child. I don't think this one will
be required but it is interesting and something we have wanted to explore for
a long time. This begins taking AppArmor in the direction of a capability
system




More information about the AppArmor mailing list