9 AppArmorObjectDelegation
John Johansen edited this page 2024-01-03 02:15:12 +00:00

Warning this document and feature are a WIP

Required Versions

  • AppArmor kernel module 4 or later
  • AppArmor userspace 4 later

Related Documentation

Introduction

This documentation covers delegation of authority via objects, for a general overview of delegation of authority and rule delegation please see Delegation of Authority.

Delegation of Authority via objects is a way to limit delegation to objects (files, network sockets, ...) that the application has opened and actively has a reference on. Object delegation shares some properties with rule delegation, including most of the same policy syntax but has several functional differences.

Object delegation can often be more selective and aligns with existing apis. ???Object delegation has similarities

In AppArmor object delegation can be further divided into Policy directed delegation and Application directed delegation. Both policy and application directed require policy rules but policy directed delegation allows policy to declare that certain objects should can be delegated on behalf of the application, while application directed delegation policy specifies what an application can delegate through the api.

Policy directed delegation (inheritance)

Policy directed delegation is done on behalf of the task generally at exec time (domain transition) without any additional task initiated action. It provides a means of specifying which open file objects can be inherited without revalidation, and without having to modify the application.

Policy directed object delegation is achieved by specifying what can be delegated in policy.

Policy directed delegation done through extending the target profile

To delegate some files to a child task the exec rule can be extended with a set of rules that extend the target profile.

profile example {
  rw @{HOME}/**,

  px /usr/bin/child + object {
      # extend the profile for /usr/bin/child with the following objects if already open at exec
      rw @{HOME}/**,
  }

}

When executed the child task will be confined by the profile for /usr/bin/child but it will be allowed to inherit objects opened under the example profile that match the rule rw @{HOME}/**,.

MOVE THIS It is important to note that the object will use the authority (and label) of the delegating profile, it will not be relabeled to use the inheriting profile label.

The task can not delegate permissions it does not have

In the above example the rw @{HOME}/**, rule appears twice, once in the profile and once in the block of rules governing what objects can be delegated. This is because the task (and hence the profile) can not delegate permissions that it does not have.

profile example {
  rw @{HOME}/**,

  px /usr/bin/child + {
      rw @{HOME}/**,
      rw /etc/passwd,
  }
}

Because the example profile does not have access to /etc/passwd it can not open the /etc/password file and thus can not delegate it. The compile may catch this case and fail with an error message.

Delegation can be restricted to open files

The profile can limit the delegation to already open files using the object qualifier. This prevents the child task from being able to open new files that match the delegated rule.

profile example {
  rw @{HOME}/**,

  px /usr/bin/child + {
      object rw @{HOME}/**,
  }
}

Overlapping rules can be used to control delegation

Overlapping rules can be used to determine delegation permissions. The open qualifier is not accumulated like regular permissions but instead applied on a most specific match basis similar to exec rule qualifiers.

profile example {
  rw @{HOME}/**,

  px /usr/bin/child + {
      object rw @{HOME}/**,
      rw @{HOME}/Downloads/*,
  }
}

In this example @{HOME}/Downloads/* is more specific so the rule is delegated instead of only open files.

Rule sets can be named to avoid having to retype rules.

Like with application directed delegation the rule sets can be named by making them non-attaching profiles.

profile example {

   authority foo {
      rw @{HOME}/**,
      r  /tmp/**,
  }

  px /usr/bin/child + foo,

}

Multiple rule sets can be delegated

profile example {

   authority foo {
      rw @{HOME}/**,
      r  /tmp/**,
  }

  authority bar {
      r /etc/passwd,
      rw @{HOME/.config/**,
  }

  px /usr/bin/child + foo + bar + {
      mr /usr/lib/**,
  }
}

Sharing rules sets

Rule sets can be shared between multiple profiles

authority shared {
      rw @{HOME}/**,
      r  /tmp/**,
  }

profile one {
  px /usr/bin/child + shared,

}

profile two {
  px /usr/bin/bash + shared,

}

Application directed delegation

???? In the case of run time application directed ?link? delegation the delegated rule set will be dynamically bounded by the profile ensuring that this restriction is enforced ???.

Applications can take action to delegate some or all of their authority to another application, if allowed by the confining profile. This is done by the application taking an explicit action to either delegate an open file descriptor or to delegate profile rules. This mean the application must have code that will direct apparmor on what should be delegated.

To delegate objects an application uses

  • unix domain socket fd passing, to pass fd objects to an existing task +
  • apparmor api for object delegation, to control inheritance of open fds *

To delegate rule the application uses

  • apparmor api for rule delegation

In addition to the application having to take explicit action to delegate authority (rule or object) the applications confinement must also allow the delegation.

+ the use of standard unix fd passing over sockets means many applications support object delegation without needing to be moified explicitly to support apparmor.

* It is important to note that the default of task's inheriting open files is not an explicit action and does NOT cause delegation of authority. If this behavior is desired it can be achieved through policy directed delegation.

Application directed delegation has to be allowed by the profile

For an application to perform delegation the profile must contain a rule allowing delegation.

profile example {
  # allow delegating to any profile
  allow delegation,
}

Delegation can be restricted to specific profiles by specifying the profile name as a target.

profile example {
  allow delegation -> foo,
  allow delegation -> bar,
}

Like capability names profile names can be collapsed into a list.

profile example {
  allow delegation -> (foo bar),

Pattern matching can be used in the target profile name to allow multiple profiles with a single name.

profile example {
  allow delegation -> foo*,

This can be particularly useful when combined with namespaces to allow all profiles in a given namespace.

profile example {
  allow delegation -> :ns:**,

Delegation can have additional restrictions

Delegation can have additional restrictions and qualifiers. In particular delegation can be restricted to children tasks.

profile example {
  # allow delegating to any child, no matter its profile
  allow delegation options=child,
}

and these restriction can be combined with the profile restriction

profile example {
  allow delegation options=child -> foo,
}

A task can not delegate permissions it doesn't have

In addition to delegation being limited by the delegation rule, the application can only delegate permissions granted in the profile.

The profile

profile example {
  allow delegation -> foo,
  allow delegation -> bar,
}

does not actually allow delegating anything as it does not have any rules that grant permission.

The profile

profile example {
  allow delegation -> foo,
  allow delegation -> bar,

  rw @{HOME}/**,
}

would be limited to delegating read write access to files in @{HOME}.

The set of rules that can be delegated can be further limited

By default the task can delegate any permission granted by its profile, but the set of what can be delegated to a profile can be further controlled to a limited subset of the profiles permissions.

profile example {
  allow delegation -> foo {
      rw /**,
  }
  allow delegation -> bar,

  rwk /**,
}

The task can not delegate permissions it doesn't have

It is important to note that if the set of rules limiting the delegation contains permissions not granted by the profile those permissions will be dropped. The rule block is only for reducing the possible set of permissions delegated it is not possible for the task to delegate permissions the profile does not have.

For example

profile example {
  allow delegation -> foo {
      rw /**,
  }
  allow delegation -> bar,

  r /**,
}

even though the delegation rules allow delegating of write permissions the profile does not contain any write permissions so it will not be possible for the task to delegate write permissions.

AppArmor allows for this type of situation without issuing an error or warning during compile for a few reasons.

  • It allows for easier sharing and reuse of rule through includes.
  • It is not always possible to detect at policy compile time that the policy is allowing delegation of permissions that exceed what is allowed by the profile. As will be seen below the rule set controling delegation can be something that is changed dynamically at run time. AppArmor will ensure even in this situation that delegation can not be used to circumvent the profiles restrictions.

Rule sets can be named

Rule sets can be given a name, by making them a profile, which can then be used in place of the block of rules.

authority bar {
  rw /**,
}

profile example {
  allow delegation (bar) -> foo,
}

Delegation can be restricted to open objects

The profile can limit the delegation to already open files/objects using the object qualifier. This prevents the child task from being able to open new files that match the delegated rule.

profile example {
  rw @{HOME}/**,

  allow delegation -> /usr/bin/child + {
      object rw @{HOME}/**,
  }
}

Rules that do not have the object only restriction restriction will also allow for object delegation, but the object restriction does not allow rules to be delegated.

Task labels under delegation

Delegation affects what the task label is and how it is displayed. How the label is affected different based on whether rules or objects are being delegated.

Task labels under Rule delegation

Because delegation is task based a tasks label will be composed of the different identities. This is done by appending the delegated information to the profile name with the character sequence //+. separating the components.

For the introductory real world example, the task label in apparmor might be expressed as

Bob//+deputy

and if the authority of father is split into its own identity separate from Bob we would have

Bob//+deputy//+father

The order of the Delegation is unimportant, the identity of the task is all of the profiles in the label.

Unamed rule blocks and labels

When an unamed rule block is used to specify delegation. Eg.

profile example {

  px /usr/bin/child + {
      rw @{HOME}/**,
  }
}

The rule block will be a created as child profile assigned a unique name based on the exec rule, and that will be name that appears as part of the task label during delegation.

Eg.

/usr/bin/child//+example//delegate_usr/bin/child

Task delegated Rules and labels

When a task explicitly delegates rules as special child profile with a unique name is created for the delegation. Eg.

  • task T1 is confined by profile example
  • task T2 is confined by profile target
profile example {
  allow delegation -> target,
  ...
}

task T1 delegates some rules to T2 via the apparmor rule delgation api. Then task T2 is confined by the label

target//+example//#<T1 pid>_<unique>

where <T1 pid> is task T1s pid and <unique> is an additional unique identifier if needed.

Extended task labels showing the hidden stack

/proc/<pid>/attr/apparmor/extended????

A&B+(C&delegator)

Task labels under Object delegation

When delegation to a task is limited to objects it does not explicitly extend the task (subjects) authority with a new set of rules, so it does not manifest in the tasks labell ing the same way as rule. Instead the tasks label remains the same as a task that has no delegation except it carries a trailing //* mark indicating that objects have been delegated extending its authority.

bob//*

the actual set of objects that have been delegated to the task can be found by looking in the tasks /proc/<pid>/fd/ directory.

conjunctive normal form

When apparmor labels contain both stacking and delegation, the label can be complicated to understand. In the label stacking always has higher priority than delegation. The exception is when () to indicate a higher priority grouping. Eg.

(bob//&jane)//+police

the above label may be decomposed into conjunctive normal form to remove the () grouping.

bob//+police//&jane//+police

Both forms are valid and what form is used during display is implementation specific.

Regardles of the form used to display the label, the object delegation mark will always be the last element of a label.


WIP

Inheritance

Delegation is inheritable

Delegation is inheritable by tasks but whether it will be inherited is controlled by policy.

If a task inherits its parent confinement it will also inherit any delegation it parent has. However if the tasks confinement changes the delegation will be re-evaluated to determine if the delegation was allowed to the new profile. If the originally delegating profile allows the delegation to the new profile then the delegation will be inherited.

eg. ....

Also need way to allow to delegate to any child.

Does the whole delegation get dropped or do we do intersections.

Inheritance of Delegation by Children

Delegation is inherited by children as long as their AppArmor confinement remains unchanged. When a tasks confinement is changed via exec rules, application directed transitions or other means the delegation is re-evaluated and my be entirely dropped, partially dropped, or full inherited depending as specified by policy.

To determine how the delegation will be handled the original delegotor policy is checked to determine if it allows delegating to the new confinement.

At this time it is not possible for the original delegator to delegate this ability to a child, but it may be added in the future if the need arises.

Delegation across profile transition boundaries

Delegation on objects??? may be dropped, and access still retained, if the the target confinement contains permissions.

Advanced topics

Notes on object & rule delegation

???? Move to advanced ????

There are aspects of object and rule delegation that are common regardless if the delegation was done via an application directing the delegation or by policy rules.

The delegator of objects or rules is tracked along with the object or set of rules that is delegated. The tracked delegator is used during revalidation and inheritance. In addition to the delegator being tracked additional information can be tracked like the set of restrictions placed on delegated rules or the set of profiles an object could be delegated to.

This tracked information is used as part of mediation, however profile replacement may causes changes that causes revalidation, and a change in information and delegation can be lost due to revalidation.

Eg. 1: If /usr/bin/child is executed from the confinement of

profile child /usr/bin/child {
  ...
}

profile one {
  px /usr/bin/child + foo,
  ...
}

then /usr/bin/child has a confinement of child//+foo. If the profile foo is replaced with a new profile revision tht has fewer permissions then, the authority of child//+foo is also reduced, as this delegation is computed dynamically.

Eg. 2: Loss of delegation at revalidation

Given

profile one {
  allow delegation -> child,
  allow delegation -> two,
  ...
}

and that profile one delegated some objects to child. The resulting confinement is child//+????. If profile one is replaced so that the delegation rules are removed.

profile one {
  ...
}

Then at any point there is a redelgation or revalidation check the previously delegated objects will loose their delegated authority and access to them will be lost unless the remaining confinement allows access to those objects.

Object Delegation

object delegation against non-open rules.

When object delegation is used, permission to delegate the object is not limited to rules with the object qualifier. Eg.

profile example {
  rw @{HOME}/**,

  allow delegation ->/usr/bin/child + {
      rw @{HOME}/**,
  }
}

Allows delegation of any object that matched the rw @{HOME}/**, rule when it was opened.

What happens when object delegation fails

If the application tries to delegate an object and the delegation is not allowed the object may still be allowed to be passed, it just won''t be done under delegated authority. Instead when delegation fails the object is revalidated against the target tasks confinement, and if allowed by the target tasks confinement the object may still be passed. This fall back is how apparmor handle object passing and inheritance before delegation was supported.

Profile example can be used to delegate any object allowed by the rule rw @{HOME}/**. Basically for object delegation all rules are treated as if the object qualifier was applied. That is to say object delegation can only be used to pass already open object and not rules.

Run time implications of delegation

object delegation and unconfined

The unconfined state delegates its open object access. This behavior has always existed in apparmor, but the ability was not available in profiles. It is equivalent to

profile unconfined {
  allow delegation -> ** + object {
     allow all,
  }
  pix /** + object { allow all, }

}

Delegating permissions to a stack

Permission evaluation

Profile transitions

Delegation to Profiles that contain the delegated authority

It is possible that a task could delegate authority to another task that is confined by a profile that contains all the delegated authority. In this situation the delegation is not dropped or thrown away, it is kept and carried as part of the task label. This ensures that inheritance of the delegation will not be lost in a profile transition occurs.

Delegation and profile replacement

the reference profile is updated, potentially resulting in new restrictions or new privileges.

Delegation vs. Revalidation

Delegation and Change_hat/Change_profile

Delegation and no_new_privs (nnp)

Delegation can not be used to circumvent the no_new_privs restrictions. While delegation may be allowed task confinement will be enforced such that neither object nor rule delegation can be used to expand a tasks authority.

Profile composition

labels can be given attachments

While not delegation (Move else where) profile attachment can be used with labels.

label example//+foo /usr/bin/, label example//&bar//+foo /usr/bin/, label example//&(bar//+foo) /usr/bin/**

compound labels can be given a short name alias label example=free//&bar

???? ordering with stacking

how is composition different from delegation

  • same as delegation when evaluating permission
  • doesn''t dynamically track where the permission came from (delegation label is null)
  • segments just drop based on exec, no check to see if it can be inherited?

file inheritance

  • check if original delegator allows passing to target
  • if not revalidate

What happens delegation of a block comes from 2 areas (say inheritance + explicit delegation), asingle reference to the block is kept and the delegation label contains both sources. If inheriting/passing both sources are consulted if one doesn't allow it is dropped. Delegation block is only dropped when all its sources are dropped.

This means a label now needs to consist of 2 vecs. 1st vec is label, 2nd is delegators/source with NULL used for authority that wasn't delegated. Hrmmm how does this work with nesting? source could have same nesting. How does it work with stacking? Just does, its nesting that is the issue. Other potential format, vec is array of struct (profile, source)

Delegation and Domain transitions

When an exec transition or change_profile happens causing a profile transition. The tasks confinement and delegation is re-evaluated.

First each component of the task confinement is evaluated for transitions, this is done for the profile as well as the delegated rules. ??? do the delegated rule objects replace themselves if they have exec rules or the profile ???

After the transition evaluation the delegated rules are checked for inheritance.

delegtion and stacking

confinement is always expressed in conjunctive normal form

delegating to a stack (A//&B)//+C is transformed into (A//+C)//&(B//+C)

delegation through inheritance onexec

  • load object
  • set onexec to target + object

delegation through rule passing

  • load object
  • write object delegation to api, identifying task
  • mark task->security object
  • task notices, task invalidation, does label update
In effect it is defining a new custom extended profile except that ipc rules to the profile label will continue to work and there is the possibility of partial dynamic replacement.

Privilege Separation

Portals

Trusted helpers and Delegation

==============================

Object Delegation and Stacking

=======================