AppArmorNamespaces

From AppArmor
Jump to: navigation, search

Required Versions

  • AppArmor 2.3 with 2.6.??? kernel
    • Limitations
      • Limited experimental flat namespace support. Only partially like documented here
  • AppArmor 2.5 with 2.6.??? kernel
    • Limitations
      • Hierarchical namespaces, no stacking, basic creation/deletion via profile load and removal
      • View == current namespace
  • 2.11 with AppArmor 3.5-beta1 - (Ubuntu 16.04)
    • Limitations
      • View == current namespace
      • stacking is buggy without backported patches
      • No mkdir/rmdir namespace interface
      • apparmor/policy is not virtualized
      • /sys/module/apparmor/parameters/* are not virtualized
  • 2.11 with AppArmor 3.6-beta1 - (Ubuntu 16.10)
    • Limitations
      • View == current namespace
      • apparmor/policy is not virtualized
      • /sys/module/apparmor/parameters/* are not virtualized
  • AppArmor 4
    • Limitations
      • In development

Related Documents

Introduction

AppArmor policy namespaces and allow separating AppArmor profiles in to different logical groups that provides a scope for the profiles, names, variables and attachments inside of it. In addition they provide for contol over profile management and the view of confinement.

the policy view

The policy view is rooted at a given namespace ????.

Properties of a policy namespace

Each policy namespace provides a set of profiles that can be applied, a unique unconfined profile, a default profile, a unique set of variables, and a set of controls for who can manipulate the namespace.

name

Each policy namespace has a name consisting of alphanumeric chararacters and begins and end with a :. Technically the beginning and ending colons (:) are not part of the name but a prefix and separator but the name will always be shown with the in AppArmor so as not to confuse them with profile names.

eg. :namespace:
    :jail1:

The namespace name when combined with a profile name is known as a fully qualified path which is done by concatenating the profile name to the namespace name with the prefix and suffix : affixed with an optional separator between.

eg. :namespace:profile_name                # ssh style
    :namespace:/profile/name
    :namespace://profie_name               # url style ie :// as separator
    :namespace:///profile/name             # notice /// always parses as the separator (//) first then /

Profile names used with out specifying a namespace name are relative to the namespace that the profile is in.

The maximum length of a name is undefined but it is recommended to keep them short as they will often appear with profile names in a fully qualified path, and different parts of the system have hard limits.

 Eg.
 The proc interface used for introspecting tasks is limited to a PAGE_SIZE
 Cipso labeling for networking is limited to 40 characters
 ...


Why do namespace names need to begin with a :

AppArmor profile names can have any character or pattern that a file name may have when the profile name is used as an attachment. This greatly limits how namespace names can be expressed. None attaching profile names also put their own constraints on how the namespace name can be expressed. Because of these limitations a unique leading character is used to indicate the beginning of a namespace name. The same technique is also used to indicate and instances, stacks, delegation, and variants.

The trailing : with optional separator // allows matching common separators in ssh and several protocol urls.

Hierarchy

AppArmor policy namespaces are arranged in a tree structure with the system policy namespace at the root. The system policy namespace can have children namespaces, which in turn can have their own children. Like profiles names, namespace names can be expressed as a path using // as a component separator.

 Eg.  :parent//child:

Namespace View

AppArmor policy namespaces are strictly hierarchical, however the full hierarchy may not visible to all tasks. A virtualized view of the policy namespace hierarchy maybe set and tasks under that view can only see the portion of the hierarchy within their view.

 Eg. Given a hierarchy of :ns1//ns2:  and a view set to :ns1: then only profiles in ns1 and ns2 will be visible.

The profile introspection and management interfaces are virtualized to the current namespace view of the task doing profile management or introspection. Note: See Interfaces and current namespace for additional notes

The View acts as the root namespace for tasks assigned to that view, and the name of the View namespace will not be reported to tasks in that view.

 Eg. If profile foo is loaded into :ns1:, and Task A has its View set to :ns1: then when task one introspects
     task B confined by :ns1://foo it will see the confinement of task B as just foo. Tasks outside the
     view may be able to see the full hierarchy or none of it all depending on their own views.

While the AppArmor interfaces are virtualized, depending on how the kernel and other system namespaces (proc, user, ...) are configured it may be possible to introspect a task that is outside of the namespace View. In this situation the confinement of the task will be reported as having the name ---. AppArmor will not expose the namespace name nor the profile name of the task.

 Eg. Given the namespaces
   root policy namespace
   :ns1:
   :ns1//ns2:
   :ns3:
 And the following tasks and views
   Task A has a view set to the root system policy namespace, with it confinement set to unconfined
   Task B has a view set to ns1, with its confinement set to unconfined of namespace :ns1:
   Task C has a view set to ns1//ns2, with its confinement set to unconfined of namespace :ns1//ns2:
   Task D has a view set to ns3, with its confinement set to unconfined of namespace :ns3:
 Then
   Task A
   - can see profiles in the system namespace
   - can see the namespaces :ns1:, :ns1//ns2:, and :ns3: and the profiles in them
   - sees the confinement of
     Task A (itself) as unconfined
     Task B as :ns1://unconfined
     Task C as :ns1//ns2://unconfined
     Task D as :ns3://unconfined
   Task B
   - can NOT see profiles in the system namespace
   - can see profiles in namespaces :ns1: which appears to be the root system namespace to it
   - sees namespace :ns1//ns2: as :ns2: and can see the profiles in it
   - can NOT see namespace :ns3: nor the profiles in it
   - sees the confinement of
     Task A as --- 
     Task B (itself) as unconfined
     Task C as :ns2://unconfined
     Task D as ---
   Task C
   - can NOT see profiles in the system namespace
   - can NOT see namespace :ns1: nor :ns3: nor their profiles
   - can see profiles in namespaces :ns1//ns2: which appears to be the root system namespace to it
   - sees the confinement of
     Task A as ---
     Task B as ---
     Task C (itself) as unconfined
     Task D as ---
   Task D
   - can NOT see profiles in the system namespace
   - can NOT see namespace :ns1: nor :ns1//ns2: nor their profiles
   - can see profiles in namespaces :ns3: which appears to be the root system namespace to it
   - sees the confinement of
     Task A as ---
     Task B as ---
     Task C as ---
     Task D (itself) as unconfined

How the Namespace View affects Policy

The namespace view not only affects want policy is visible from a task but also affects how policy needs to be authored, and managed.

TODO

Namespace View and policy transitions

Namespace View and policy management

  • Note: Before AppArmor 4, the View and current namespace are the same

Current Namespace

When a task is created it is assigned to a policy namespace. The current namespace of a task governs is the namespace used for profile lookups, profile attachments, transitions, unless a namespace is specified in as part of a transition. The current namespace is always the View namespace or one of its children, it can never be a parent of the namespace View.

 Eg. given a child namespace :child1: with its view set to the root namespace. With profile R in the root namespace, and profile C in the the child namespace, and task Tr confined by R and task Tc confined by C, then
 Tr - views Tc confinement as :child1://C
    - views its own confinement as R
 Tc - views its own confinement as :child1://C
    - views Tr confinement as R

Now lets say Tc and Tr both try to transition to a profile X

 Tr will transition to X in the root namespace
 Tc will transition to a different profile X in the namespace :child1: because its current namespace is :child1: and profile lookups that don't specify a namespace are relative to the current namespace.

However if the transitions is to :child1://X

 Tr will transition to the X profile in :child1:
 Tc will still transition to the X profile in :child1:

This is because the namespace lookup is relative to the view not the current profile.

Similarly if the transitions is to :child2://Y

 Tr will transition to the Y profile in :child2:
 Tc will transition to the Y profile in :child2:

Before Version 4.0 of the AppArmor kernel module the current namespace was always set as the current View so that the current namespace always appeared to be the root namespace for tasks in that namespace.

The default profile

Each policy namespace has a default profile that is assigned to tasks when no other profile in the namespace has an attachment that matches. The standard default profile is the unconfined state. Each policy namespace has its own unique unconfined state profile which is used by tasks assigned to or created within the policy namespace.

Note: as of AppArmor 3.5 setting the default profile to something other than unconfined is experimental and can only be applied to the root system policy namespace, via a grub kernel parameter.

Cross namespace communication

Task 1 in ns1, task 2 in ns2

how permissions are resolved - if ns1 is parent and ns2 is child and visible (in view) - if ns1 is sibling to ns2 and visible (ie in view)

- if ns1 is parent and ns2 is child (ns2 can't see ns1) - if ns1 is sibling or sibling descendant to ns2 and not visible (ns1 can't see ns2, ns2 can't see ns1)


????

relative vs abs ns path

root ns is not express via a name

ns: refers to a namespace within the current root ns



When View is not the current namespace

In AppArmor 4 it is possible to have the view be a namespace that is different from the current namespace. When this occurs the view will be an ancestor of the current namespace, and the view will affect what profiles and namespaces are used when directly referenced.

For transitions and management when no namespace is specified the current namespace is used If a namespace is specified then it is from the view

:: is the namespace of the view
No equiv of file path ..
If you want the root of the view, or ns that is not a descendent the must specify abs path for view root 

how to do relative vs abs ns path

Simulating flat namespaces by setting the view

While AppArmor namespaces are hierarchical they can simulate a flat set of namespaces by setting the view to the parent namespace of the set of namespaces that should appear to be flat. Since references to namespaces are relative to the namespace view all first level children of the view namespace are referenced by a single level name and appear like a flat namespace set.

Namespaces and their interaction with Stacking

Namespaces can be used in combination with stacking to enforce confinement from different policy sets at the same time. This allows the system and a container to share a kernel and have each enforcing policy at the same time. The system can enforce restrictions on the container, and the container can have policy enforcing restrictions on the tasks in the container from the containers point of view.

For full details see Using Stacking in combination with Policy Namespaces.

Managing Policy in a Namespace

For tasks in a policy namespace profiles management is no different than regular profile management, as the namespace appears to be the root policy namespace to that task.

Eg.

 apparmor_parser profile
 apparmor_parser -r profile
 apparmor_parser -R profile

For more details see AppArmor policy management.

The management of policy for a child namespace is handled through the same means as regular policy management, however the namespace must also be specified. The namespace can be specified using the tools or in policy, depending on the needs of the policy.

To specify the namespace in the tools the -n flag is used

 apparmor_parser -r -n namespace profile

To specify the namespace in policy the namespace is specified as part of the profile name, and then the profile is loaded through using a regular load

 profile :namespace://A {
   ..
 }
 apparmor_parser -r profile

A task with the namespace set as its current namespace can just replace profiles as normal.

 apparmor_parser -r profile

Interfaces

Limitations

  • AppArmor 3.5
    • apparmor/policy is not virtualized
    • /sys/module/apparmor/parameters/* are not virtualized

Interface virtualization

The profile introspection and management interfaces are virtualized to the current namespace view of the task doing profile management or introspection.

API

Library Interface

libapparmor


Low level Interfaces

Policy Namespaces via policy interface

Policy Load

dd bs=size if=file of=/sys/kernel/security/apparmor/{.load/.replace}

If the user is capable of administering policy an AppArmor policy namespace can be created by loading a profile to it.

 apparmor_parser -n namespace profile

Or if a profile has a namespace specification as part of its definition then the profile can just be loaded

 # cat profile
 profile :ns://A {
   ..
 }
 # apparmor_parser profile

Removing a namespace

If the user is capable of administering policy an AppArmor policy namespace can be removed by echoing the namespace name into the low level .remove interface.

 echo -n "ns_name" >/sys/kernel/security/apparmor/.remove


Creating a Policy Namespace via the fs

Limitation: This first became available in AppArmor 3.6

A new child policy namespace can be created by doing mkdir in the namespaces directory in apparmorfs.

 mkdir /sys/kernel/security/apparmor/policy/namespaces/new_ns


Removing a Policy Namespace via the fs

Limitation: This first became available in AppArmor 3.6

A child policy namespace can be removed by doing rmdir in the namespaces directory in apparmorfs.

 rmdir /sys/kernel/security/apparmor/policy/namespaces/child_ns

TODO: recursive delete

Effect of removing a policy namespace if tasks are still confined by policy in it

The removal of a policy namespace removes all of its profiles. If there are tasks still confined by profiles in the namespace when it is removed then those tasks confinement will be modified dependent on the tasks confinement of the parent namespace. If the task is confined by the parent namespace then the profiles from the deleted namespace will be dropped. If however the task is not confined by the parent namespace, the profiles from the deleted namesapce will be replaced by the default profile of the parent namespace.

Egs. Given a root namespace with profiles A, B, and a default profile of D. And an namespace ns1 with profile X. When :ns1: is removed, X will be removed or replaced based on :ns1:'s parent the root namespace

 Task1 is confined by
    A//&:ns1://X
  since Task1 is confined by the profile A in the root namespace X is dropped from the confinement resulting in a new confinement of
    A
 Task2 is confined by
    :ns1://X
 since Task2 is not confined by a profile in the root namespace the profile X is replaced by the default profile D for the root namespace.

Setting Namespace properties

View

owner

Using Namespaces in policy

Policy Transitions within a namespace

Transitioning to a new namespace

Policy Namespace Example

Limitations

As of AppArmor kernel module 3.5 namespaces only support a local view, they do not support sharing a root. That is


Creating Namespaces

Specifying Namespaces in Policy

=