On 6/18/18 2:28 AM, John Johansen wrote:
On 06/17/2018 05:56 AM, Vincas Dargis wrote:
With policy versioning we could have single profile for all future AppArmor releases? Basically, no 
more need to have these directories (nor "ubuntu", neither "apparmor/x.y")?

A possibility, that I would certainly like to get to, but I don't think we will 
be able to get to it with the 3.0 release

Oh, we need some more "conditioning" features I guess?
Basically the big issue is installing policy with rules that supports new 
features on older systems that don't have support for the feature. You could 
update the userspace but most stable releases are unwilling to do this. To help 
deal with this in the past we have been front running the features in the 
parser before they land upstream, but we really need to get away from doing 
that. We could wrap rules in conditional statements but with the current 
implementation the parser will break as conditionals are not a preprocess and 
the rules in their blocks must be parsable.

The long term goal is to allow defining parsing patterns within the parser 
language itself. So we could add a pattern that would be used to skip/downgrade 
a rule if the parser doesn't support the feature. So something along the lines 
of

   if !parser_supports(Xapparmor) {
      ignore pattern 'X' .... # some expression that will let the parser get 
past the unsupported rule
   }

and eventually if the rules follow supported patterns and don't need anything 
specially allow declaring the rule patterns in policy entirely.

This "x_supports" is planned for > 3.0?

Will we have new policy version numbers on every minor AppArmor release (with 
new/updated abstractions)?

Using policy versioning as a name is really as misnomer, at least at the policy 
level, the idea certainly started out as such but it has evolved from there.

The idea is that we declare the supported feature abi that the policy was 
developed under right in the policy it self. This will give a similar effect as 
using feature pinning but on a per profile basis instead of applying to all 
policy on the system. If the feature abi is not declared in policy then, policy 
will fall back to feature pinning and then if there is no declaration the 
compile will fallback to the 4.14 feature abi as the default.

Policy wise the base of policy versioning is the new feature rule.

   features=<features/file>,

Also instead of sticking the features into a feature file they can be included 
inline
    features={ blah, blah blah }

the features file will be the same as what is currently used for caching and 
feature pinning. And in support of this, there will be a couple of additions to 
the parser language to help identify what is currently supported.

   kernel_supports
   parser_supports
   policy_supports
   supports - asking about what is supported for this compile which is an 
intersection of what the kernel and the policy supports

hopefully if we do it right we can hide most conditionals within the 
abstractions.

to abstract some of the details away we are going to wrap the features= rule in 
an include which will allow us to abstract away anything new we come up with

the include could contain multiple features= rules, defining some variables 
that can be used conditionally etc.

It is the include file naming and how packaging of policy is handled that would 
be the closest to what policy versioning implies, and I have been struggling 
with how best to do this

OK so it's "versioning" against features. That's useful, as two distributions might look like having the "same" AppArmor v3.0, though one distro might not have DBus mediation in Kernel yet, for example.

Could you give us an example of how versioned profile snippet will look like? Meaning, "if 
apparmor/policy version is >= X, then include <abstraction/foo>, else copy-pasted 
rule...".


So I'd like to address the version number first. I would like, if possible, to avoid having 
to do "if version >= X", I am not saying there won't be cases where something 
of the sort is needed but I would rather the conditionals be along the lines of

   if (supports(X)) {
      include <abstraction/foo>
   }

So for every new abstraction there should be defined as "a feature" in a version/3.0 include, basically? This "supports" will look at included feature set and/or distro feature file, right?

In recent Thunderbird profile backport [0] I've copied abstractions/dri-enumerate content inline, as Debian Sid does not yet have 2.13. What if abstractions/dri-enumerate would have been available, but not up-to-date, with some rules missing?

We aren't going to add a feature definition for every abstraction change..? (you do mention abstraction versions later, but see below)

and that we keep the conditionals in the abstractions as much as possible

The version abstraction at its most basic would look like
$ cat version/3.0

# feature set supported by the 3.0 release
features=<features/4.17>
# allow policy to also support kernels with the older out of tree patches
features=<features/out_of_tree_net_and_af_unix>
@{version}=3.0    # or perhaps define the var as @{abi} instead doesn't matter 
as long as we are consistent

$

The idea behind the @{version} variable is then that could be used in policy to 
do things like

include <abstractions/@{version}/...>

for version specific bits if needed.


a profile file would then do

   include <version/3.0>

to set what its policy version

No sure about this this <abstractions/@{version}/... , I imagine one would like to use latest abstraction by default, only adding (backporting) some missing rules. I guess it could look like this (still using v2.13 as for example with mentioned Thunderbird issue, with imaginary 2.14):

```
if (@{version} >= 2.14) {

  # AA >= 2.14 abstraction has all the features we need (so far)!
  #include <abstractions/dri-enumarate>

} else if (@{version} == 2.13) {

   #include <abstractions/dri-enumarate>

  # Backported from the dri-enumerate abstraction from AppArmor 2.14
   /some/additional/rule.. r,

} else {

  # We don't have dri-enumerate at all in AA 2.12!

  # Backported from the dri-enumerate abstraction from AppArmor 2.13

/sys/devices/pci[0-9]*/**/{device,subsystem_device,subsystem_vendor,uevent,vendor} r,

  # Backported from the dri-enumerate abstraction from AppArmor 2.14
   /some/additional/rule.. r,
}

That's a lot of "ifdefing", but maybe it could reach that "single profile for all AA versions" style though.

Or is there a cleaner approach? You said you would like to avoid "if version >= X", I am not yet sure about avoiding in this example, when AppArmor version is fixed in distribution release, but some application (like Thunderbird in this example) gets updates and needs more recent abstractions.
```

packaging and dealing with missing bits of policy is where I am failing atm, 
and 3.0 won't have debhelpers or rpm macros to help with packaging needs around 
policy versioning.

I am not sure if we want to split the version and feature files into their own 
packages that packaging can setup dependencies on or whether it should just be 
dealt with in policy.

policy authors could do things like

   include if exists <version/3.0>

if they want the ability to fallback to a different version, but use a regular 
include if they want the missing dependency to fail.

OK so let's imagine Debian Buster has AppArmor 3.0, and Buster+1 has AppArmor 3.2. How could we make _same single profile_ that could use 3.2 features on Buster+1, and 3.0 on Buster?

Multiple includes that would override each over? Like this:

```
#include <version/3.0> # policy needs at least 3.0!
#include if exists <version/3.2> # add more features than 3.0 had

...

if supports(dbus_mediation) { # since ABI version 3.2
        #include <abstractions/dbus-session-strict>
        dbus ...,
}
```

I suspect we are going to end up with a mix of packaging and policy magic 
depending on the policy author needs. Policy that the apparmor project ships 
could be easily setup to have packaging dependencies but LXD might choose to do 
something more flexible as they are dynamically generating policy


Maybe we could still use "apparmor/3.0" directory for new-style versioned profiles, leaving 
ubuntu/x.y for backpacking as it is now (We will have Ubuntu 18.04 for quite some time). If any day policy 
changes too much, "apparmor/4.0" could be added, or maybe we are sure enough that that's never 
going to happen, and we don't need that "3.0" at all?


That is a possibility, and whether or not we are sure that policy will never 
change enough to require a new version number we are going to keep the option 
to provide one because if we don't, we will need it later.

So is this "a deal"? Could we have "apparmor/3.0" (or similar) in apparmor-profile repo to make this big distinction against "old-style" policies, to add new 3.x-based profiles and upgrade older ones? What others think?

[0] https://gitlab.com/apparmor/apparmor-profiles/commit/748fe86fd81a9e48b5a26c771c3551c444c1d89a

--
AppArmor mailing list
AppArmor@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/apparmor

Reply via email to