[apparmor] "default"/"system" profile

John Johansen john.johansen at canonical.com
Thu May 16 00:13:15 UTC 2013


So this is a new attempt to frame the default/init/system profile discussion


The goal of the default/system profile is to replace the unconfined profile
and make it easier to have a default system policy and also to confine
applications from boot. The unconfined profile has few different properties
  1. It is the profile that is attached to init as the first process
  2. It is the target profile for ux/Ux profile transitions
  3. It is the fallback target for Pux profile transitions
  4. It is the fallback target for Pix from the unconfined profile. That is
     to say unconfined does the equivalent of
       /** pix,
     for all execs from profiles confined by pix.
  5. unconfined is assumed by most policy to be the common system default,
     though there is nothing in apparmor that requires this as profile
     transition are determined by profile rules not globally.
  6. unconfined is the default profile transitioned to when the profile a
     task is confined by is removed.
  7. the unconfined profile is exposed on interfaces (historical artifact) as
       unconfined
     instead of
       unconfined (<mode>)
  8. the unconfined profile can't be replaced or removed as it is special
     and not in the profile lists
  9. the unconfined profile can't be directly transitioned to by
       /foo/bar px -> unconfined
 10. the unconfined profile is treated special to bail out of mediation
     early
 11. each namespace has its own unconfined profile used to make sure profile
     attachment occurs from the correct namespace


To replace unconfined we must be able to address each of these points.

Fixing 2 & 3:
  If there is to be a default profile then having a separate unconfined
  profile that can be used to escape the default profiles confinement is
  not acceptable. U/ux based transitions need to become transitions to the
  default profile what ever that is (whether it is unconfined or some other
  profile).


Fixing 4.
  Nothing to do. Pix is behaving correctly if you are in a different
  profile than unconfined it is the one that gets inherited if that rule
  is used


Fixing 5.
  Nothing to do. Policy should just work. If an author sets up a system
  confinement then things that are breaking due to not being unconfined
  need to be address in the modified policy.


Fixing 6:
  The solution to this is the same as 2, removal of a profile should result
  in transitioning to the default profile what ever it is (unconfined or
  otherwise)


Fixing 7.
  We can just convert to using
    <profile> (<mode>)
  and stop using a bare unconfined, the unconfined profile shows up as
    unconfined (unconfined)

  this will require some tooling updates to deal with any conditions based
  on things being "unconfined" but won't out right break tools either


Fixing 8 & 9
  We just make it available and maybe special case its removal, replacement.
  As there must always be a profile on a task


Fixing 10.
  We add an unconfined mode, it can be placed on any profile. (DONE)


Fixing 11.
  Nothing to fix, profiles will still need to be per namespace, and tracked
  per namespace. That means the default/system/init profile that replaces
  unconfined needs to be per namespace as well. However having a global
  kernel config that sets the name of the "default" profile for all
  namespaces may not be correct for cases where a container is being used
  as a VM. In that case any "default" profile name could be configured as
  part of the container setup, but defaulting to the system one or the
  parent namespaces default profile name is an acceptable first pass
  solution.

  That is there will need to be work to define this per namespace but that
  can be done later


Now to the harder point

Fixing 1. Confining init
  First up the unconfined profile conflates two issues, confinement of init
  and the default profile. This is largely because these two issues are not
  so easily separated. But for the discussion lets tackle each separately
  and then decide whether they should be combined.

  When the system starts up the kernel attaches a profile to the initial
  process (init). What exactly init is will vary depending on the system,
  but it is responsible for bringing the system up. At this point we do
  not have real context about what init is, just that it is the first
  process. This first process runs and forks/execs children to do
  different jobs and they inherit its profile (unconfined). At some point
  policy is loaded and profile attachments can begin.

  In a system with an initrd, we can think of init as the early init
  process that is responsible for doing the tasks required by the initrd
  (loading modules, etc) before the real init takes over. It is possible to
  load policy from the initrd, though if doing so it should be only what
  is required and precompiled. This way policy is in place when the system
  init is started and policy is correctly applied to the whole system.

  Loading policy from the initrd is a pita, and it doesn't work systems
  that don't have an initrd, so it is desirable to be able to trust early
  boot, and do an early policy load which provides system confinement. This
  is not currently possible as the unconfined profile can not be replaced,
  nor can individual tasks have their profile set by an external task.  To
  be able to confine the processes that are present before policy load
  occurs (init, and several children) the profile on them must be
  replaceable. However all these processes share a single profile, because
  the initial profile has no policy transition rules, and no other profiles
  are available.

  There are several potential solutions to the problem of confining init
  and its early children
    1. Policy load in the initrd (assuming you have an initrd), and having
       the early initrd init exec into the system init process
       This is clean and allows policy to be specified separate from the
       kernel.

    2. special case init and children in the kernel code
       - No, just no.

    3. provide a basic policy compiled into the kernel. This is like the
       initrd solution but is built into the kernel. The initrd solution is
       more flexible but may not be available on some systems

    4. set the profile on individual tasks, after policy load
       - this is racy as you are chasing different tasks trying to properly
         confine tasks with the initial profile
       - this ability does not currently exist and likely won't for a long
         while

    5. provide the ability to replace the initial profile, and accept all
       tasks under the initial profile will have the same confinement
       - changing the confinement of the tasks is not really an option as
         attachments and parent child hierarchy chains aren't reliable
       - what name to use

    6. Put the initial profile into a "complain" like mode where each child
       process gets its own child profile and the hierarchy is maintained.
       - this is somewhat racy as you still need to chase down and replace
         the dynamic profiles before they fork a child and exec to yet
         another new profile
       - do not want complain messages to the log, so new mode?


  The name of the initial profile is not terribly important as long as it
  is consistent and conveys the correct meaning. This could be "init",
  "system", "default", ... (remember at this point we are not yet
  discussing the default confinement profile). When renaming replacement
  becomes available this profile can also be renamed as it is replaced,
  and several profiles (if the hierarchy option is chosen) can be
  collapsed into a single profile. Also as suggested this initial
  profile name could easily be defined as a grub boot option, or as part
  of the Kconfig when a kernel is built



Now on to the default profile

  The default/system profile is used when ux/Ux is used or a profile is
  removed and application confinement falls back to the default.
  Traditionally this and the init role have been played by the unconfined
  profile, but it is possible to separate them. The question is how and is
  it worth it. If the default/system profile is not attached on boot then
  it is the init profile will be attached to processes on boot and the
  default profile won't see use until a profile is removed or ux/Ux/pux is
  encountered. This means the system is confined by the init profile by
  default.

  For a finer grained confinement on boot, multiple profiles need to be
  defined along with their transition rules as discussed above, without
  that the "init" profile is the default in use by the system after boot,
  and having a separate default profile that is transitioned to on profile
  removals is confusing.

  So without having a more detailed policy defined at boot what can be
  done?

  Two profiles could be define at boot (well actually for each namespace),
  an init and default profile. The init process would start in the "init"
  profile and at some point the default profile begins to be used. The
  question is when?

  a. on every exec until policy is loaded
     this is equivalent to having the init profile doing pux

     this is problematic unless the init profile has a defined attachment
     so that it can keep the init processes in the init profile if it
     re-execs itself. Also note we can not arbitrarily change what this
     attachment is at boot. It is possible to have the attachment based on
     a name and change it at boot time, but the kernel will not have the
     dfa compiler in it so it is not possible to user regexs as part of
     the attachment.

  b. define an attachment for init
     the attachment needs to be fixed so it is not flexible to different
     systems. While the attachment could be defined as a grub boot option
     it could not use regexes/globbing (so exactly one name).

  c. once default is loaded
     in this case init is aliased to the default profile until a new
     default profile is loaded, at which point the new default takes over.

     This is different from a in that all the early processes are confined
     by the init profile, and default is only different once a new one is
     loaded. This is also racy as to what processes receive a give
     confinement unless the policy load is ordered and other boot
     processes wait on it

  d. A variation of c
     Except default doesn't have to be loaded, it will go into effect as
     soon as the first profile is loaded. I would assume it would start
     out as just the default (unconfined) {} profile.

  e. build init, and default as actual profiles and compile into the
     kernel (I am not found of this)

     The problem with confining early boot and having init have a different
     profile is that you need a way to identify which processes should be
     confined by which profiles. The best way to do this is an early policy
     load, any other solution is somewhat hackish. Splitting the init and
     default profiles has some merit but the question is it enough for the
     extra effort. As without a defined early policy we are very limited
     in how processes are divided between separate init and default
     profiles.


Aside: the problem with a default profile with broad attachment specification
  It is possible to define a fixed broad attachment specification for the
  original default profile, but there is no point as having init use
  a specific attachment or pux will have the same results. And the broad
  attachment breaks pix

  If the default profile is define like
    profile default /** {

    }

  then it will break the fallback in pix rules, where a profile may want
  to transition to itself if an application profile is not defined,
  because there is always a profile defined (ie the p portion of the
  specification always finds a profile and the ix fallback never happens).


Choosing a name

  IFF we choose to split the init and default profile then I think the
  names should be
   init and default (or maybe system)

  otherwise
    system seems to make sense




More information about the AppArmor mailing list