From 16de4ee43d6ab5fc0e54d679b9c007b3d2e821a7 Mon Sep 17 00:00:00 2001 From: Christian Boltz Date: Wed, 8 Jul 2015 22:43:48 +0200 Subject: [PATCH] is_known_rule(): check includes recursively 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 includelist" 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. Acked-by: Steve Beattie --- utils/apparmor/aa.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/utils/apparmor/aa.py b/utils/apparmor/aa.py index 92a717424..a7f8a675e 100644 --- a/utils/apparmor/aa.py +++ b/utils/apparmor/aa.py @@ -4071,11 +4071,21 @@ def is_known_rule(profile, rule_type, rule_obj): if profile[rule_type].is_covered(rule_obj, False): return True - for incname in profile['include'].keys(): + includelist = list(profile['include'].keys()) + checked = [] + + while includelist: + incname = includelist.pop(0) + 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] + return False def reload_base(bin_path):