[apparmor] [RFC PATCH 1/1] libapparmor: Create man page for aa_stack_profile()/aa_stack_onexec()

John Johansen john.johansen at canonical.com
Tue Jan 12 23:10:28 UTC 2016


On 01/11/2016 06:27 PM, Seth Arnold wrote:
> On Mon, Jan 11, 2016 at 05:41:43PM -0800, John Johansen wrote:
>>>> +Stacking another profile via aa_stack_profile() is permanent and the process is not
>>>> +permitted to revert to the previous confinement context. Unlike
>>>> +aa_change_profile(2), confined programs wanting to use aa_stack_profile() need
>>>> +no special rules in their profile to stack a new profile since the operation
>>>> +does not broaden the allowed permissions.
> 
>>> I'm also afraid that this kind of rule might also allow these APIs to be
>>> used by exploit code to unreasonably manipulate profile transitions in
>>> ways that aren't expected by policy authors.
>>>
>> how so?
>>
>> the policy will have to allow stacking, and stacking is purely restrictive.
>> If the profile allows the stack, then and only then can it take priority
>> over the profiles exec transitions, just like with change_profile.
> 
> Earlier in the manpage it was suggested that policy does _not_ have to
> have syntax to allow stacking.
> 
> If the stacking is entirely under the control of the program and not
> influenced by policy (as suggested in this manpage) then the following
> attack is feasible:
> 
> Presume we're running in a confined sshd-alike application. The profile
> for the sshd-alike includes the following rule:
> 
> /bin/bash Px -> user_shell,
> 
> The intention is that users are confined to a specific profile once they
> are authenticated, one that doesn't allow system administration tasks.
> 
> If an exploit during user authentication is allowed to call
> aa_stack_onexec("administrator_shell");
> and this API call overrides the Px in the profile, then an exploit could
> bypass the restricted profile and get a profile that allows administration
> tasks.
> 
not necessarily so. There are in fact 3 different semantics stack_onexec
could take on, and we will have to be precise about what it is doing and
why.

The desire to delay the stack to exec is similar to change_onexec so that
you don't have to implement a stub profile in policy for the brief period
between change_profile and the exec.

Eg.

basic change_profile: replaces the current profile immediately
  A  -- change_profile --> B

change_onexec: replaces the current profile, but delays it until exec
  A  -- change_onexec ... exec --> B

this avoids having to make policy where what you do is
  A  -- change_profile --> STUB
  STUB --> exec --> B

where STUB has to have permissions for intermediate operation and then
the exec transition.

With change_profile you could skip the STUB profile portion and include
any permissions granted in STUB into the B profile. However since
change_profile is usually being used to reduce permissions, that is not
desirable, where change_onexec includes the STUB profile permissions
into A.

Now lets move on to stacking.

basic stack: reduce the current permissions immediately
  A -- stack B -->  A//&B

notice how A wasn't replaced or removed. Once we come to the exec
the exec rules for both A and B are applied. Lets say A transitions
to C and B to D then we get
  A -- stack B --> A//&B -- exec --> C//&D

if however A and B both transition to C then we get
  A -- stack B --> A//&B -- exec --> C//&C -- collapses to --> C

now lets look at the stack on exec case. The stack addition is delayed
until exec.  The current profile will have the stack added on top, the
question is when and how.

1. stack_onexec as stack + change_onexec: stack is computed immediately
    but the transition is delayed until exec (this overrides any
    transitions and is how Tyler described it)
  A -- stack_onexec B -- exec --> A//&B

2. stack_onexec, stack delayed until exec applied pre-exec transitions
  A -- stack_onexec B -- exec apply stack -- A//&B -- exec trans --> C//&D

3. stack_onexec, stack delayed until exec applied post-exec transitions
  A -- stack_onexec B -- exec trans -- C -- apply stack --> C//&B

each is a viable definition and each could have their uses.

Example 1: is like change_onexec in that it completely replaces the
domain transition, with a profile set computed at the time it is called.
Neither A nor B require a domain transition, A requires a change_profile
or stack_profile rule, and all intermediary permissions between
stack_onexec and exec need to be included in B

This is the most like change_onexec in behavior. However a better
description of it is stack and apply at exec.

Example 2: follows what happens with aa_stack, contrary to change_onexec
  mimics what happens with straight stacking, and like change_onexec
  puts all intermediary permissions between stack_onexec and exec into A.
  However A//&B must have exec permissions and this is contrary to how
  change_onexec works. That is change_onexec has a rule in A that defines
  the exec permission and has priority over regular domain transition
  rules and the target B does NOT need an exec rule.

  We could and should have a stack_onexec or use the change_onexec rule to
  mitigate the first difference but that B requires and exec rule is odd,
  and I don't think it is a viable definition.

Example 3: is similar to example 2 except B does not require a domain
  transition. It can be thought of stack on top of what ever current is
  after exec.

  Rules wouldn't be required in this model but still might be desirable.

Whether to go with 1, 3 or both depends on use cases, and how these are
implemented. So lets look at the exec side some more. Because exec rules
are also going to pickup the ability to specify stacking. Note the syntax
here is not final but sufficient for the discussion.

exec rules allow naming a profile to transition to
  px /foo/bar -> A,
  px /** -> A,

this will be extended to support specifying an explicit stack
  px /foo/bar -> A//&B,
  px /** -> A//&B,

however we may want to be able to specify the stack based off the target
profile, this works for
  px /foo/bar -> /foo/bar//&B,

but does not work for the rule with globbing because there can be
multiple targets matched.
  px /** -> ??//&B,

we can get around this by either introducing a special variable
  px /** -> @{TARGET}//&B,

or extending the stacking syntax a little to mean use the target and
what is specified.
  px /** -> &B,   # leading & specifies use target and stack B

however neither of these syntaxes are sufficient (for globbing rules) to
specify the final confinement when we want the execed process to have
current confinement and B. We can extend each syntax to support this.

  px /** -> @{SELF}//&B,
  #Note: @{PROFILE} is not correct as the task may already have
  #      a stack of profiles, so it is current confinement

and
  ix /** -> &B,			# notice ix instead of px


notice how the choices 1 and 3 for stack_onexc parallel the above exec
rules.
  1. is the same as
      px /** -> @{SELF}//&B,
    or
      ix /** -> &B,

  3. is the same as
     px /** -> @{TARGET}//&B,
   or
     px /** -> &B,

both cases have their uses, and I believe we need to support both. So
the stack api should probably support both as well.

Now to the matter of whether stacking rule in the profile is required.

1. requires a rules otherwise it can be exploited, as Seth has
   already pointed out.

3. doesn't require a rule but it probably should use them, mostly
   so for consistency with 1.

The question still remains whether we use change_profile rules or
introduce a separate stacking rule.

If we go with change_profile rules then
  change_profile -> A,
  change_profile -> B,

grants enough permissions for stacking to A//&B, however it grants wider
permissions than necessary as it also allows a transition to just B,
which may not be desired. Which means at the least we need to augment
change_profile to support the more restrictive case.
  change_profile -> A//&B,

we could do the same with a special stack rule
  stack -> A//&B,
  stack -> @{SELF}//&B,

but I see no reason to limit the change_profile api to not allow
specifying compound targets. ie. I can see using change_profile to
  change_profile  C//&D,

this is an immediate change to this confinement and there is no exec
target involved. Further once delegation lands we will want to be able
to specify targets with delegation.
  change_profile  A//+E,

at which point I think change_profile, stacking and delegation rules are
more complex than combining into a single rule as each of them are going
to have to support bits of the other.

yes this does mean the stacking api is really just a convenience layer
on top of change_profile, but that isn't a bad thing.



More information about the AppArmor mailing list