0 Unconfined, the unconfined flag and default allow
John Johansen edited this page 2024-07-25 22:59:19 +00:00

Introduction

The relationship between the unconfined profile, the unconfined flag, and the default-allow flag is can be confusing, and requires some knowledge of how AppArmor mediation works and why to fully understand.

short explanation

unconfined flag

The unconfined flag puts a profile into the unconfined mode. In the unconfined mode the profile acts almost like the application is running unconfined on system without AppArmor. The unconfined flag is used with a profile to give an application a security label that can be referenced for ipc.

In newer kernels it is possible that some rules might be enforced while unconfined and will require the unconfined profile to have rules if it is to allow the unconfined restricted item. An example of this would be the unprivileged user namespace restriction.

The effect of adding rules to a profile with the unconfined flag is kernel and parser dependent, but generally speaking rules will have no effect unless there is a special requirement like with the unprivileged user namespace restriction. The rules however will likely be compiled and carried into the kernel in case such restriction are enabled.

Profiles in the unconfined mode will reflect this with (unconfined) as part of their context.

default_allow flag

The default_allow flag puts a profile into deny listing mode. All operations are allowed by default. Allow rules within the profile are allowed but redundant. In default allow profiles deny rules are the only way to cause mediation.

The default_allow flag can be implemented in userspace by adding a low priority allow all, rule to the profile. However the policy compiler (apparmor parser) is allowed to optimize the policy so that rule classes that have no denials are optimized away and treated as not enforced for a small performance improvement.

The profiles with the default_allow flag set will have (enforce) as part of their context.

unconfined profile

The unconfined profile is a special profile with the reserved name unconfined, no attachment specification, and the unconfined flag set. There is a unique unconfined profile created for each policy namespace. The unconfined profile is the default profile assigned to tasks on kernel init, if init is to change its profile it will use the change_profile api.

The unconfined profile has domain transition of ix /**,, so that if an application is started from the unconfined profile it will check for other attaching to other profiles before falling back to using the unconfined profile.

The unconfined profile is special in that its mode will not be reported as part of introspection.

In depth explanation

Under the hood optimizations can blur the boundaries between the unconfined flag, the default_allow or even an allow all, rule embedded in the profile. To understand this a little bit of knowledge about how AppArmor is implemented is needed.

short circuiting mediation

AppArmor does short circuiting of mediation when ever it can to reduce the performance impact mediation can have. Ideally when AppArmor is not enforcing policy it would have no overhead, allowing it to be enabled on systems and made available for the cases where mediation is desired.

Unfortunately it is not possible to have zero overhead but AppArmor strives to reduce overhead where ever possible. Where possible, it does this by doing quick low overhead checks about mediation before entering into code that can have a performance impact. If mediation is not required the only overhead is the early check.

mediation pattern

There is a common mediation pattern within apparmor.

get the task confinement label
do some shared work
for each Profile in the label
   do work

with short circuiting the pattern becomes

get the task confinement label
if label is mediated
   do some shared work
   for each Profile in the label
       if Profile is mediated
           do work

This allows short circuiting to be partially used even in a stacking situation.

mediation classes and compatibility

For backwards compatibility reasons, some mediation classes may not be mediated. This check is added to the mediation pattern after the Profile check but before doing the profile's work.

get the task confinement label
if label is mediated
   do some shared work
   for each Profile in the label
       if Profile is mediated
           if Class is mediated
               do work

improving the mediation check and short circuiting.

In older kernels the mediation check can be expressed more specifically as

get the task confinement label
if label is NOT unconfined
   do some shared work
   for each Profile in the label
       if Profile is NOT unconfined
           if Class is mediated
               do work

The nested nature of the mediation checks can result in more work being done than actually needs to be. Eg if none of the profiles in the label are going to mediate a Class, all profiles will still have to be checked to do this.

The unconfined check only allowed for a boolean test. To improve this a bit set of mediated classes was added to the label. When the label is created the bit set is computed from the profiles that make up the label. If any profile mediates the the class within the label the label will have the mediated bit set, and a secondary check is done. Profiles in the unconfined mode just don't set the class as mediated unless they are designed to mediate a given class.

This allowed removing the unconfined check for a more generic class mediated check.

get the task confinement label
if label class is mediated
   do some shared work
   for each Profile in the label
       if Class is mediated
           do work

The improvement is actually better than the above mediation pattern would indicate. As while only 1 check was removed, it allows for many mediation classes to be bypassed entirely on the first check, and then second Class is mediated check in the profile is now a fast bit set check instead of having to do the class walk on the state machine.

It is important to note that the above pattern relies on the policy compiler setting the mediated classes correctly for all profiles including those with the unconfined or default_allow flags.