Table of Contents
- Warning this document and feature are a WIP
- Required Versions
- Related Documentation
- Introduction
- Policy directed delegation (inheritance)
- Policy directed delegation done through extending the target profile
- The task can not delegate permissions it does not have
- Delegation can be restricted to open files
- Overlapping rules can be used to control delegation
- Rule sets can be named to avoid having to retype rules.
- Multiple rule sets can be delegated
- Sharing rules sets
- Application directed delegation
- Application directed delegation has to be allowed by the profile
- Delegation can have additional restrictions
- A task can not delegate permissions it doesn't have
- The set of rules that can be delegated can be further limited
- The task can not delegate permissions it doesn't have
- Delegation can be restricted to open objects
- Task labels under delegation
- Inheritance
- Inheritance of Delegation by Children
- Delegation across profile transition boundaries
- Advanced topics
- Notes on object & rule delegation
- Run time implications of delegation
- Delegating permissions to a stack
- Profile transitions
- Delegation to Profiles that contain the delegated [authority](AppArmorDelegation#authority-privilege)
- Delegation and profile replacement
- Delegation vs. Revalidation
- Delegation and Change_hat/Change_profile
- Delegation and no_new_privs (nnp)
- Delegation and Domain transitions
- delegtion and stacking
- Privilege Separation
- Portals
- Trusted helpers and Delegation
- Object Delegation and Stacking
Warning this document and feature are a WIP
Required Versions
- AppArmor kernel module 4 or later
- AppArmor userspace 4 later
Related Documentation
- Delegation of Authority
- Object Delegation (this document)
- Rule Delegation
- Run time composition of Policy
- Stacking or Bounding
- Object labeling
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
=======================