[apparmor] [patch] is_known_rule(): check includes recursively

Christian Boltz apparmor at cboltz.de
Mon Jun 22 20:14:01 UTC 2015


is_known_rule() in aa.py checked only direct includes, but not includes
in the included files. As a result, aa-logprof asked about things that
are already covered by an indirect include.

For example, the dovecot/auth profile includes abstractions/nameservice,
and abstractions/nameservice includes abstractions/nis, which contains
"capability net_bind_service,".
Nevertheless, aa-logprof asked to add capability net_bind_service.

Reproducer: (asks for net_bind_service without this patch, should not
ask for anything after applying the patch):
python3 aa-logprof -d ../profiles/apparmor.d/ -f <(echo 'type=AVC msg=audit(1415403814.628:662): apparmor="ALLOWED" operation="capable" profile="/usr/lib/dovecot/auth" pid=15454 comm="auth" capability=13  capname="net_bind_service"')

The patch adds code to check include files included by other include
files. Note that python doesn't allow to change a list while looping
over it, therefore we have to use "while incname" as workaround. 

This fixes a regression for network rules (this patch is based on the
old match_net_include() code). Funnily it "only" fixes capability rule
handling (without the "regression" part) because the old
match_cap_include() didn't do the recursive include handling.

[ 55-is_known_rule-check-includes-recursively.diff ]

=== modified file utils/apparmor/aa.py
--- utils/apparmor/aa.py        2015-06-21 19:02:13.797642711 +0200
+++ utils/apparmor/aa.py        2015-06-22 21:56:15.601218138 +0200
@@ -4087,11 +4087,28 @@
         if profile[rule_type].is_covered(rule_obj, False):
             return True
-    for incname in profile['include'].keys():
+    includelist = list(profile['include'].keys())
+    checked = []
+    if includelist:
+        incname = includelist.pop(0)
+    while incname:
+        checked.append(incname)
         if include[incname][incname].get(rule_type, False):
             if include[incname][incname][rule_type].is_covered(rule_obj, False):
                 return True
+        for childinc in include[incname][incname]['include'].keys():
+            if childinc not in checked:
+                includelist += [childinc]
+        if len(includelist):
+            incname = includelist.pop(0)
+        else:
+            incname = False
     return False
 def reload_base(bin_path):


Christian Boltz
> if anybody who broke a nightly build should pay on beer, the
> whole development department would be drunk I guess ;-)
[...] over the last 2 weeks we would have been *very* drunk.
[> Ulrich Windl and Marcus Meissner]

More information about the AppArmor mailing list