[apparmor] apparmor policy versioning

John Johansen john.johansen at canonical.com
Wed Jul 17 22:57:34 UTC 2013


On 07/11/2013 12:55 PM, Christian Boltz wrote:
> Hello,
> 
> Am Mittwoch, 10. Juli 2013 schrieb Jamie Strandboge:
>> On 07/10/2013 04:18 PM, John Johansen wrote:
>>> So it turns out we are going to need to support policy versioning
>>> (Christian can gloat now). 
> 
> I already wanted it when we enforced the trailing / on directory names 
> some years ago ;-)
> 
yes I am well aware of that, as well as for other changes that rolled out.
Its a good thing you weren't around for the x to px Px transition, that
was brutal :)

>>> We are looking at 2 different options
>>>
>>> 1. we support a version tag in files, with the tag required to be on
>>> each> 
>>>    file including any include.
>>>    When the parser detects mixed versioning does it
>>>    - gracefully convert between v2 and v3 policy
>>>    - just fail
>>>
>>> 2. we move to a new versioned directory /etc/apparmor3.d/ or
>>> something of> 
>>>    the sort with everything in /etc/apparmor.d/ remaining in v2
>>>    policy
>>>    (format and semantics)
>>>    
>>>    In this case what if a profile exists in both directories
>>>    - fail
>>>    - default to v3 on new kernels
>>>    - default to v2 on older kernels?
>>
>> I was initially thinking that for '1' if any profile or include had a
>> v3 annotation, then it would be v3. But I don't think that works well
>> and '1' doesn't cleanly separate. Ie, what happens if I update the
>> base abstraction with a v3 rule? We decided today that the parser
>> should probably support converting v2 policy to v3 by adding
>> equivalent open rules on kernels that supported them (ie, v3 policy
>> that acts like v2. Eg v2 policy doesn't have a dbus rule, so if the
>> parser detected v2 policy it would add an implicit 'dbus,' rule). In
> 
> We'll probably also need support to upgrade to a newer profile version 
> in logprof or a separate 2to3 [1] tool (with a "just do it" option, and 
> a more selective one that asks about any difference).
> 
yes that would be nice to have but isn't a hard requirement

> 
> Thinking about it, we could handle the versioning with something like
>     include <abstractions/compat_aa2>  # v2 profile
> or
>     include <abstractions/compat_aa3>  # v3 profile
> 
> compat_aa2 would contain
>     dbus,
>     #include <abstractions/compat_aa3>
> 
> compat_aa3 would be empty for now, but can be filled when we switch to 
> aa4 one day.
> 
an interesting idea. Its certainly a nice way to abstract out the set
of rules that needs to be added.

> The parser should check if the profile contains a compat_* abstraction. 
> If not, it should assume it's a v2 profile and include compat_aa2 
> silently (well, a warning would be nice).
> 
I'm not sure I like making part of the include name special, and would
prefer something more specific.

> The advantage of this solution would be that we don't need big changes 
> or feature list in the tools - it would just be another abstraction.
> 
yes, though there would need to be some smarts around the special name
which I'd rather avoid.  I think perhaps setting a single conditional
would be better

if version = 3 {
  #include <abstractions/compat_aa2>
}

or something of the sort

> The only disadvantage of this method is that it will fail if we change 
> syntax or remove a rule. However, I don't expect this to happen ;-)

Well yes, and adding versioning does open up that very interesting
possibility ;-)

> (for completeness: history tells us about the trailing / for directories 
> and removal of "set capability" - but that were very rare cases.)
> 
oh more than that, the x to qualifier + x transition, and the addition
of any new rule type really so, capabilities, mount rules, removal of
netdomain, several kernel semantic changes around x, ...

The only ones that the exception are rules that cleanly extended,
resource rules and link pair rules come to mind

>> this manner, we could maybe only make the profiles themselves require
>> the v3 tag since the parser would convert everything to v3 before
>> policy load anyway (on kernels that supported it). 
> 
> Having the version tag only in the main profile sounds like a good way, 
> and then assume the abstraction uses the same version. (To answer the 

Sadly no, this really breaks the main use case for Ubuntu (inconsistent
version state during upgrades).  If we can assume policy and abstractions
are at the same version there is much less need for versioning.  Eg. all
we need to do to upgrade unknown v2 policy is automatically drop in the
v2 compat include.

The fail case of a v2 parser on v3 policy doesn't change with versioning,
the parser just bails at the version tag vs a new rule it doesn't
understand.  The one odd case is a semantic change on an existing rule,
but we are trying hard to avoid that.

> obvious question: if a v2 profile includes a v3 abstraction with a dbus 
> rule, just "don't care" while parsing - it's superfluous because v2 
> implies 'dbus' anyway.)
> 
yes

> Besides that, at least the abstractions we ship will have the "correct" 
> version - and I'd guess not many people have their own abstractions.
> 
sadly this is a case we are worried about. Especially when policy is
being shipped piece meal and we don't control the dependency resolution
of an upgrade.

>> But again, what
>> happens if I update the base abstraction to have a v3 rule and then I
>> run a v2 kernel? 
> 
> The parser would for example skip the dbus rules (which doesn't change 
> anything because dbus was not restricted in v2).
> 
right

>> I think there are a lot of corner cases that makes
>> versioning in files difficult.
> 
> Indeed ;-)
> 
yes but these are the interesting cases.  If we can assume all one or
all the other then we get back to the earlier matrix I presented and
we discussed ages ago where versioning didn't have a compelling benefit
to anyone except Christian

Specifically the compelling case to the Ubuntu distribution are policy
stored in external (non-apparmor) packaging, and updates/upgrades.

Updates don't add to much of a wrinkle except when an external package
ships policy, which just breaks down into the external packages shipping
policy case.

In the upgrade case we get in a situation where we may have old parser,
new policy, old kernel.  New parser, old policy, old kernel etc, and
even worse because policy is broken across different packages some
of those packages may have been updated and some may not so we have
a mix of v2 and v3 policy.

Tagging just the profile files does take 90% of it but there are
some packages that ship abstractions.

>> I prefer '2' because it allows us to cleanly separate. abstractions
>> probably need to be copied wholesale into the v3 directory and
>> maintained as v2 and v3 thereafter (though it does allow us the
>> opportunity to clean out ancient v2 rules, but ugh, I don't think I
>> want to have to be the one to test all those).
> 
> Exactly - cleaning out ancient rules is both boring and dangerous 
> because we _will_ get regression bugreports from at least one user ;-)
> 
> My general rule of thumb is: do not remove any permissions once they are 
> in a shipped profile or abstraction, unless it is a security problem or 
> a very obvious bug (and I don't expect bad side effects of the fix).
> If an ancient rule doesn't hurt, well, then it doesn't hurt ;-)
> 
Generally I agree but I am also tempted by the dark side to clean up the
language. I will agree if we do this it should go through a deprecation
process that takes several revision.

No one is talking about hard breaking policy, at least not yet ;)

>> v2 policies can stay
>> as v2 until we test them under v3 and then have them in both. I think
>> we need to do it this way since people might reboot into different
>> kernels and while policy should load and I don't think we guarantee
>> that v3 policy compiled with a v3 parser loaded into a v2 kernel will
>> work as expected (ie, just like v2 policy, v2 policy and a v2
>> kernel). As such, when both exist, use the one that is appropriate
>> for the kernel.
> 
> Exactly this is the reason why I don't like to have a separate directory 
> with a duplicated set of the profiles. I have more than enough 
> experience with code duplication[2], and learned to avoid the "cp" 
> command at any price.
> 
yes this can be a problem

> With an additional copy of the profiles, we'll end up in a maintenance 
> hell - and users will kill us because they have to update two profiles 
> instead of one if they want to switch kernels.
> 
we end up with maintenance hell either way, its just deciding between
which one is the 8th or 9th plane there of





More information about the AppArmor mailing list